Loads an OpenAPI document through a pluggable adapter, and sanity-checks it.
API reference pages belong in a documentation site, but where the OpenAPI document comes from varies wildly: derived from Ash domains, declared with OpenApiSpex, generated by a service in another language, or checked in by hand. Binding the build pipeline to any one of those would make DocShell useful to a fraction of the projects that want it.
So the pipeline talks to DocShell.Generate.OpenApi.Adapter and never to a
spec library. Three adapters ship with the package — see
DocShell.Generate.OpenApi.Adapters.AshOaskit,
DocShell.Generate.OpenApi.Adapters.OpenApiSpex, and
DocShell.Generate.OpenApi.Adapters.RawJson — and hosts add their own by
implementing one callback. Writing one is covered in the
OpenAPI adapters notebook.
What this module guarantees
extract/2 is the trust boundary between the build and code it does not
own. It asks Elixir to load the adapter module, checks that loaded modules
export load/1, calls the callback inside a rescue so an adapter raising
cannot take down a build with a
stacktrace instead of a reason, and validates that whatever came back
actually claims to be OpenAPI 3.0 or 3.1.
That validation is deliberately shallow. Full schema validation is the job of
the spec library that produced the document, and duplicating it here would
mean DocShell rejecting documents its own adapters consider fine. What
validate/1 catches is the common integration mistake: an adapter returning
a config map, an envelope, or a spec struct that was never rendered.
Errors
{:error, :nofile}— the adapter module could not be loaded{:error, :invalid_adapter}— the loaded module does not exportload/1{:error, :invalid_openapi_source}— the adapter returned something other than{:ok, map}or{:error, reason}{:error, :invalid_openapi_document}— no usableopenapiversion key{:error, {:openapi_adapter_failed, message}}— the adapter raised- anything the adapter itself returned as
{:error, reason}
Summary
Functions
Loads the OpenAPI document from adapter, passing opts through to it.
Checks that a map identifies itself as an OpenAPI 3.0 or 3.1 document.
Functions
Loads the OpenAPI document from adapter, passing opts through to it.
Guards against a missing, non-conforming, or raising adapter, and rejects documents that do not identify as OpenAPI 3.0 or 3.1.
@spec validate(map()) :: :ok | {:error, :invalid_openapi_document}
Checks that a map identifies itself as an OpenAPI 3.0 or 3.1 document.
Accepts either a string or atom openapi key, since adapters build documents
with whichever their underlying library prefers. This is a shape check, not
schema validation — see the module documentation for where that line sits.
Examples
iex> DocShell.Generate.OpenApi.validate(%{"openapi" => "3.1.0"})
:ok
iex> DocShell.Generate.OpenApi.validate(%{openapi: "3.0.3"})
:ok
iex> DocShell.Generate.OpenApi.validate(%{"swagger" => "2.0"})
{:error, :invalid_openapi_document}