Oaskit behaviour (oaskit v0.9.0)
View SourceThe main API to work with OpenAPI specifications.
This module can be used to define a specification module that will then be used in your Phoenix router and controllers.
Example
defmodule MyAppWeb.OpenAPISpec do
alias Oaskit.Spec.Paths
alias Oaskit.Spec.Server
use Oaskit
@impl true
def spec do
%{
openapi: "3.1.1",
info: %{title: "My App API", version: "1.0.0"},
servers: [Server.from_config(:my_app, MyAppWeb.Endpoint)],
paths: Paths.from_router(MyAppWeb.Router, filter: &String.starts_with?(&1.path, "/api/"))
}
end
end
Summary
Types
A cache action given to cache/1. Oaskit will use keys of
type cache_key/0 when calling the cache.
The cache keys used by this module when calling cache/1.
Callbacks
This callback is used to cache the built version of the OpenAPI specification, with JSV schemas turned into validators.
This function is intended to change cache keys at runtime. The variant is any
term used as the last element of a cache_key/0.
Normalizes an extention key and value to a JSON encodable form.
Returns the options that will be passed to JSV.build/2 when building the
spec for the implementation module.
Loads an extension from its raw form and make it available in then
conn.private.oaskit.extensions data given to controllers.
This function should return the OpenAPI specification for your application.
Functions
Retrieves a cached from the implementation module.
Validates the given OpenAPI specification module returns a representation of
the specification using structs such as Oaskit.Spec.OpenAPI,
Oaskit.Spec.Response, etc.
Default options used for the JSV.build/2 function when building schemas
Normalizes OpenAPI specification data.
Returns a JSON representation of the given OpenAPI specification module.
Types
@type cache_action() :: {:get, key :: cache_key() | term()} | {:put, key :: cache_key() | term(), value :: term()}
A cache action given to cache/1. Oaskit will use keys of
type cache_key/0 when calling the cache.
The cache keys used by this module when calling cache/1.
@opaque extension_point()
@type json_decoded() :: %{optional(binary()) => json_decoded()} | [json_decoded()] | String.t() | number() | boolean() | nil
Callbacks
@callback cache(cache_action()) :: :ok | {:ok, term()} | :error
This callback is used to cache the built version of the OpenAPI specification, with JSV schemas turned into validators.
- The callback will be called with
:getto retrieve a cached build, in which case the callback should return{:ok, cached}or:error. - It will be called with
{:put, value}to set the cache, in which case it must return:ok.
Caching is very important, otherwise the spec will be built for each request
calling a controller that uses ValidateRequest. An efficient
default implementation using :persistent_term is automatically generated.
Override this callback if you need more control over the cache.
@callback cache_variant() :: term()
This function is intended to change cache keys at runtime. The variant is any
term used as the last element of a cache_key/0.
This is useful if you need to rebuild the OpenAPI specification and its validators at runtime, when the used schemas or even routes depend on current application state. For instance, if a schema for a given entity is fetched regularly from a remote source and changes over time.
The default implementation returns nil.
Stale cache entries are not purged automatically
If you return a new variant from this callback, cache entries stored with
previous variants in the key are not automatically cleaned. You will need to
take care of that. See cache/1 to implement a cache mechanism that you
can control.
@callback dump_extension(pair :: {String.t() | atom(), term()}) :: {String.t(), json_decoded() | extension_point()} | nil
Normalizes an extention key and value to a JSON encodable form.
Extensions are keys that are not known by Oaskit. They can be given to the
Oaskit.Controller.operation/2 macro or found in a raw JSON specification.
This callback must return a pair with a string key and a JSON-encodable value.
It is also possible to return nil to ignore the pair. In that case, it will
not be included in the JSON specification generated by mix openapi.dump and
will not be available in the conn.private.oaskit.extensions data given to
controllers.
Extension points given to operations declared in controllers are always
normalized, see load_extension/1 for more information.
With use Oaskit, a default implementation is added and will attempt to
preserve the original value to provide it to controllers without having to
write a specific normalizer function.
Custom Serialization
If you override this callback, you should also override load_extension/1.
The default implementation uses an internal struct to wrap the original value
and preserve it through normalization. If you override only one of the two,
you might lose this behavior or get unexpected results.
@callback jsv_opts() :: [JSV.build_opt()]
Returns the options that will be passed to JSV.build/2 when building the
spec for the implementation module.
The default implementation delegates to Oaskit.default_jsv_opts/0.
Loads an extension from its raw form and make it available in then
conn.private.oaskit.extensions data given to controllers.
Extensions are keys that are not known by Oaskit. They can be given to the
Oaskit.Controller.operation/2 macro or found in a raw JSON specification.
Note that due to the support for JSON based specifications, extensions are always normalized and then denormalized. It is necessary to declare this callback even for extension points that are only defined in controllers.
For instance:
operation :create_user,
operation_id: "CreateUser",
# ...
custom_data: %MyApp.SomeStruct{}In this case the dump_extension/1 callback will be called, and then the
load_extension/1 callback will be called with the normalized pair.
With use Oaskit, a default implementation is added and will attempt to
return the original declared in controller operations. This works well with
the default implementation defined for dump_extension/1.
Custom Deserialization
If you override this callback, you should also override dump_extension/1.
The default implementation uses an internal struct to wrap the original value
and preserve it through normalization. If you override only one of the two,
you might lose this behavior or get unexpected results.
@callback spec() :: map()
This function should return the OpenAPI specification for your application.
It can be returned as an %Elixir.OpenAPI{} struct, or a bare map with atoms or
binary keys (for instance by reading from a JSON file at compile time).
The returned value will be normalized, any extra data not defined in the
Oaskit.Spec... namespace will be lost.
Functions
Retrieves a cached from the implementation module.
If the value is not in catche, the generator is called and the generated
value is put in cache before being returned.
Validates the given OpenAPI specification module returns a representation of
the specification using structs such as Oaskit.Spec.OpenAPI,
Oaskit.Spec.Response, etc.
Default options used for the JSV.build/2 function when building schemas:
[
default_meta: JSV.default_meta(),
formats: [Oaskit.JsonSchema.Formats | JSV.default_format_validator_modules()]
]
Normalizes OpenAPI specification data.
Takes specification data (raw maps or structs) and normalizes it to a JSON-compatible version (with binary keys).
Returns a JSON representation of the given OpenAPI specification module.
See Oaskit.SpecDumper.to_json!/2 for options.