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

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

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

Link to this section 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.

Get the names of all properties defined for a schema.

Validate a value against a Schema.

Link to this section 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

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"
  }
}

Link to this section Callbacks

@callback schema() :: t()

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

Link to this section 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

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

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.

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

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

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.