Current section
Files
Jump to
Current section
Files
lib/doc/schema.ex
defmodule APIDoc.Doc.Schema do
@moduledoc ~S"""
A schema definition for use as in and output type.
"""
require Logger
@typedoc ~S"""
The schema type.
"""
@type type ::
:integer
| :string
| :object
| :array
@typedoc ~S"""
The format for types that have different formats.
Example: `:int32` for `:integer`s.
"""
@type format ::
:int32
| :int64
@typedoc @moduledoc
@type t :: %__MODULE__{
name: atom,
type: type,
format: format | nil,
required: list(atom) | nil,
properties: map | nil,
example: any,
minimum: integer | nil,
maximum: integer | nil,
items: map
}
@enforce_keys [:name, :type]
defstruct [
:name,
:type,
format: nil,
required: nil,
properties: nil,
example: nil,
minimum: nil,
maximum: nil,
items: nil
]
@doc false
@spec validate!(t) :: :ok
def validate!(schema) do
with %{errors: errors, warnings: warnings} <- validate(schema) do
name = Macro.to_string(schema.name)
if errors != [], do: Enum.each(errors, &Logger.error("APIDoc: Schema '#{name}': #{&1}"))
if warnings != [], do: Enum.each(warnings, &Logger.warn("APIDoc: Schema '#{name}': #{&1}"))
end
:ok
end
@doc false
@spec validate(t) :: :ok | %{errors: [String.t()], warnings: [String.t()]}
def validate(schema = %__MODULE__{type: type}) do
validated =
schema
|> Map.from_struct()
|> Enum.map(fn {k, v} -> validate_property(type, k, v) end)
|> Enum.reject(&is_nil/1)
|> Enum.group_by(&elem(&1, 0))
if validated[:error] || validated[:warn] do
%{
errors: Enum.map(validated[:error] || [], &elem(&1, 1)),
warnings: Enum.map(validated[:warn] || [], &elem(&1, 1))
}
else
:ok
end
end
@spec validate_property(type, atom, any) :: nil | {:error, String.t()} | {:warn, String.t()}
# Integer
defp validate_property(:integer, :format, nil),
do: {:warn, "No format set for integer. Recommend setting `:int32` or `:int64`."}
# Object
defp validate_property(:object, :properties, nil), do: {:error, "No properties set for object."}
defp validate_property(:object, :required, nil),
do: {:error, "No required properties set for object. Recommend setting required fields."}
# All
defp validate_property(_type, :example, nil),
do: {:warn, "No example supplied. Strongly recommend setting an example."}
defp validate_property(_type, _property, _value), do: nil
end