AutoStruct logo

AutoStruct

Generated structs for Elixir from JSON Schema.

AutoStruct is a thin code generation layer over Exonerate. Exonerate validates JSON-shaped Elixir terms generated from JSON Schema; AutoStruct generates structs, conversion helpers, and encoder implementations around that validator.

Installation

The package can be installed by adding auto_struct to your list of dependencies in mix.exs:

def deps do
  [
    {:auto_struct, "~> 0.3.0"}
  ]
end

Documentation is available on HexDocs.

Usage

defmodule Person do
  use AutoStruct.JsonSchema,
    schema: """
    {
      "$id": "https://example.com/person.schema.json",
      "$schema": "https://json-schema.org/draft/2020-12/schema",
      "title": "Person",
      "type": "object",
      "properties": {
        "first_name": {
          "type": "string",
          "description": "The person's first name."
        },
        "age": {
          "description": "Age in years which must be equal to or greater than zero.",
          "type": "integer",
          "minimum": 0
        },
        "happy": {
          "type": "boolean",
          "default": true,
          "description": "Whether the person is happy."
        },
        "attrs": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Optional array of attributes.",
          "nullable": true
        }
      },
      "required": ["first_name"]
    }
    """
end

# `new/1` returns {:ok, value} | {:error, reason}
iex> Person.new(first_name: "George", age: 31)
{:ok, %Person{first_name: "George", age: 31, happy: true, attrs: nil}}

# `new!/1` raises on error
iex> Person.new!(first_name: "George", age: 31, attrs: %{phone: 123})
** Some Error Message from the underlying validation library

# `from_json/1` returns {:ok, value} | {:error, reason}
iex> Person.from_json(%{"first_name" => "George", "age" => 31})
{:ok, %Person{first_name: "George", age: 31, happy: true, attrs: nil}}

iex> Person.from_json(%{"first_name" => "George", "age" => 31, "attrs" => %{"phone" => 123}})
** Some Error Message from the underlying validation library

# Generated structs implement Elixir's built-in JSON.Encoder.
iex> JSON.encode!(Person.new!(first_name: "George"))
"{\"age\":null,\"attrs\":null,\"first_name\":\"George\",\"happy\":true}"

# If you would like to build the struct directly, and avoid the internal cast to json map
# and back again, you can skip validation but still enforce the keys:
iex> %Person{first_name: "Hello"}

Examples

Runnable examples are available in the examples/ directory:

mix run examples/inline_schema.exs
mix run examples/file_schema.exs

Mix Tasks

mix auto_struct.gen.modules

Generate the Module stubs from a folder of schema files.

mix auto_struct.gen.modules <path_to_schemas> <output_path_modules>

How it works

Under the hood the use AutoStruct.JsonSchema macro uses Exonerate to generate the validation function needed by new/1, from_json/1, and validate/1.

AutoStruct creates a defstruct with an atom key for every top-level property in the JSON Schema. Property names are preserved as-is. For properties marked as required, AutoStruct also includes them in @enforce_keys.

new/1 and validate/1 recursively normalize structs, maps, and lists into JSON-shaped terms before calling Exonerate. Nested maps and arrays are validated by Exonerate, but from_json/1 only casts the top-level object into a struct; nested objects remain JSON-shaped maps unless you transform them yourself.

Generated modules expose schema metadata:

Person.__schema__(:json)
Person.__schema__(:fields)
Person.__schema__(:required)

Elixir's built-in JSON.Encoder is the primary encoder. When Jason is available, AutoStruct also emits a compatible Jason.Encoder implementation.

Limitations

Nested JSON Schema objects and arrays are validated by Exonerate, but AutoStruct only casts the top-level schema object into a struct. Nested objects returned from from_json/1 remain string-keyed maps unless you transform them yourself.

AutoStruct currently generates fields from top-level schema properties. Advanced JSON Schema composition features are delegated to Exonerate for validation and are not expanded into additional struct fields.