View Source OpenApiSpex.Schema behaviour (open_api_spex v3.21.1)

Defines the OpenApiSpex.Schema.t type and operations for casting and validating against a schema.

The OpenApiSpex.schema macro can be used to declare schemas with an associated struct and JSON Encoder.

Examples

defmodule MyApp.Schemas do
  defmodule EmailString do
    @behaviour OpenApiSpex.Schema
    def schema do
      %OpenApiSpex.Schema {
        title: "EmailString",
        type: :string,
        format: :email
      }
    end
  end

  defmodule Person do
    require OpenApiSpex
    alias OpenApiSpex.{Reference, Schema}

    OpenApiSpex.schema(%{
      type: :object,
      required: [:name],
      properties: %{
        name: %Schema{type: :string},
        address: %Reference{"$ref": "#/components/schemas/Address"},
        age: %Schema{type: :integer, format: :int32, minimum: 0}
      }
    })
  end

  defmodule StringDictionary do
    @behaviour OpenApiSpex.Schema

    def schema() do
      %OpenApiSpex.Schema{
        type: :object,
        additionalProperties: %OpenApiSpex.Schema{
          type: :string
        }
      }
    end
  end

  defmodule PetCommon do
    require OpenApiSpex
    alias OpenApiSpex.{Schema, Discriminator}
    OpenApiSpex.schema(%{
      title: "PetCommon",
      description: "Properties common to all Pets",
      type: :object,
      properties: %{
        name: %Schema{type: :string},
        petType: %Schema{type: :string}
      },
      required: [:name, :petType]
    })
  end

  defmodule Cat do
    require OpenApiSpex
    alias OpenApiSpex.Schema
    OpenApiSpex.schema(%{
      title: "Cat",
      type: :object,
      description: "A representation of a cat. Note that `Cat` will be used as the discriminator value.",
      allOf: [
        PetCommon,
        %Schema{
          type: :object,
          properties: %{
            huntingSkill: %Schema{
              type: :string,
              description: "The measured skill for hunting",
              default: "lazy",
              enum: ["clueless", "lazy", "adventurous", "aggressive"]
            }
          },
          required: [:huntingSkill]
        }
      ]
    })
  end

  defmodule Dog do
    require OpenApiSpex
    alias OpenApiSpex.Schema
    OpenApiSpex.schema(%{
      type: :object,
      title: "Dog",
      description: "A representation of a dog. Note that `Dog` will be used as the discriminator value.",
      allOf: [
        PetCommon,
        %Schema {
          type: :object,
          properties: %{
            packSize: %Schema{
              type: :integer,
              format: :int32,
              description: "the size of the pack the dog is from",
              default: 0,
              minimum: 0
            }
          },
          required: [
            :packSize
          ]
        }
      ]
    })
  end

  defmodule Pet do
    require OpenApiSpex
    alias OpenApiSpex.Discriminator
    OpenApiSpex.schema(%{
      title: "Pet",
      type: :object,
      discriminator: %Discriminator{
        propertyName: "petType"
      },
      oneOf: [
        Cat,
        Dog
      ]
    })
  end
end

Summary

Types

The basic data types supported by openapi.

Global schemas lookup by name.

Callbacks

A module implementing the OpenApiSpex.Schema behaviour should export a schema/0 function that produces an OpenApiSpex.Schema struct.

Functions

Cast a simple value to the elixir type defined by a schema.

Generate example value from a %Schema{} struct.

Generate example value from a OpenApiSpex.Schema or a OpenApiSpex.Reference struct.

Get the names of all properties defined for a schema.

Validate a value against a Schema.

Types

@type data_type() :: :string | :number | :integer | :boolean | :array | :object

The basic data types supported by openapi.

Reference

@type schemas() :: %{required(String.t()) => t()}

Global schemas lookup by name.

@type t() :: %OpenApiSpex.Schema{
  additionalProperties:
    boolean() | t() | OpenApiSpex.Reference.t() | module() | nil,
  allOf: [t() | OpenApiSpex.Reference.t() | module()] | nil,
  anyOf: [t() | OpenApiSpex.Reference.t() | module()] | nil,
  default: any(),
  deprecated: boolean() | nil,
  description: String.t() | nil,
  discriminator: OpenApiSpex.Discriminator.t() | nil,
  enum: [any()] | nil,
  example: any(),
  exclusiveMaximum: boolean() | nil,
  exclusiveMinimum: boolean() | nil,
  extensions: %{required(String.t()) => any()} | nil,
  externalDocs: OpenApiSpex.ExternalDocumentation.t() | nil,
  format: String.t() | atom() | nil,
  items: t() | OpenApiSpex.Reference.t() | module() | nil,
  maxItems: integer() | nil,
  maxLength: integer() | nil,
  maxProperties: integer() | nil,
  maximum: number() | nil,
  minItems: integer() | nil,
  minLength: integer() | nil,
  minProperties: integer() | nil,
  minimum: number() | nil,
  multipleOf: number() | nil,
  not: t() | OpenApiSpex.Reference.t() | module() | nil,
  nullable: boolean() | nil,
  oneOf: [t() | OpenApiSpex.Reference.t() | module()] | nil,
  pattern: String.t() | Regex.t() | nil,
  properties:
    %{required(atom()) => t() | OpenApiSpex.Reference.t() | module()} | nil,
  readOnly: boolean() | nil,
  required: [atom()] | nil,
  title: String.t() | nil,
  type: data_type() | nil,
  uniqueItems: boolean() | nil,
  writeOnly: boolean() | nil,
  "x-struct": module() | nil,
  "x-validate": module() | nil,
  xml: OpenApiSpex.Xml.t() | nil
}

Schema Object

The Schema Object allows the definition of input and output data types. These types can be objects, but also primitives and arrays. This object is an extended subset of the JSON Schema Specification Wright Draft 00.

Example

alias OpenApiSpex.Schema

%Schema{
  title: "User",
  type: :object,
  properties: %{
    id: %Schema{type: :integer, minimum: 1},
    name: %Schema{type: :string, pattern: "[a-zA-Z][a-zA-Z0-9_]+"},
    email: %Schema{type: :string, format: :email},
    last_login: %Schema{type: :string, format: :"date-time"}
  },
  required: [:name, :email],
  example: %{
    "name" => "joe",
    "email" => "joe@gmail.com"
  }
}

Callbacks

@callback schema() :: t()

A module implementing the OpenApiSpex.Schema behaviour should export a schema/0 function that produces an OpenApiSpex.Schema struct.

Functions

Link to this function

cast(schema, value, schemas)

View Source

Cast a simple value to the elixir type defined by a schema.

By default, object types are cast to maps, however if the "x-struct" attribute is set in the schema, the result will be constructed as an instance of the given struct type.

Examples

iex> OpenApiSpex.Schema.cast(%Schema{type: :integer}, "123", %{})
{:ok, 123}

iex> {:ok, dt = %DateTime{}} = OpenApiSpex.Schema.cast(%Schema{type: :string, format: :"date-time"}, "2018-04-02T13:44:55Z", %{})
...> dt |> DateTime.to_iso8601()
"2018-04-02T13:44:55Z"

Casting Polymorphic Schemas

Schemas using discriminator, allOf, oneOf, anyOf are cast using the following rules:

  • If a discriminator is present, cast the properties defined in the base schema, then cast the result using the schema identified by the discriminator. To avoid infinite recursion, the discriminator is only dereferenced if the discriminator property has not already been cast.

  • Cast the properties using each schema listing in allOf. When a property is defined in multiple allOf schemas, it will be cast using the first schema listed containing the property.

  • Cast the value using each schema listed in oneOf, stopping as soon as a successful cast is made.

  • Cast the value using each schema listed in anyOf, stopping as soon as a successful cast is made.

@spec example(schema :: t() | module() | OpenApiSpex.Reference.t()) ::
  map() | String.t() | number() | boolean()

Generate example value from a %Schema{} struct.

This is useful as a simple way to generate values for tests.

Example:

test "create user", %{conn: conn} do
  user_request_schema = MyAppWeb.Schemas.UserRequest.schema()
  req_body = OpenApiSpex.Schema.example(user_request_schema)

  resp_body =
    conn
    |> post("/users", req_body)
    |> json_response(201)

  assert ...
end
@spec example(schema :: t() | module(), schemas :: OpenApiSpex.OpenApi.t() | map()) ::
  map() | String.t() | number() | boolean()

Generate example value from a OpenApiSpex.Schema or a OpenApiSpex.Reference struct.

The second parameter must either be an OpenApiSpex.OpenApi struct or a map of schemas.

See also: example/1.

Get the names of all properties defined for a schema.

Includes all properties directly defined in the schema, and all schemas included in the allOf list.

Link to this function

validate(schema, value, schemas)

View Source
@spec validate(t() | OpenApiSpex.Reference.t(), any(), %{
  required(String.t()) => t() | OpenApiSpex.Reference.t()
}) :: :ok | {:error, String.t()}

Validate a value against a Schema.

This expects that the value has already been cast to the appropriate data type.

Examples

iex> OpenApiSpex.Schema.validate(%OpenApiSpex.Schema{type: :integer, minimum: 5}, 3, %{})
{:error, "#: 3 is smaller than minimum 5"}

iex> OpenApiSpex.Schema.validate(%OpenApiSpex.Schema{type: :string, pattern: "(.*)@(.*)"}, "joe@gmail.com", %{})
:ok

iex> OpenApiSpex.Schema.validate(%OpenApiSpex.Schema{type: :string, pattern: "(.*)@(.*)"}, "joegmail.com", %{})
{:error, "#: Value \"joegmail.com\" does not match pattern: (.*)@(.*)"}
Link to this function

validate(schema, value, path, schemas)

View Source

See OpenApiSpex.DeprecatedCast.validate/4.