View Source Apical (apical v0.1.0)
Generates a web router from an OpenAPI document.
Building an OpenAPI-compliant Phoenix router can be as simple as:
defmodule MyRouter do
require Apical
Apical.router_from_file(
"path/to/openapi.yaml",
controller: MyProjectWeb.ApiController
)
end
See https://spec.openapis.org/oas/v3.1.0 for details on how to compose an OpenAPI schema.
Using the macros router_from_string/2
or router_from_file/2
you may generate a
Phoenix.Router
that corresponds to OpenAPI document.
tip
TipIn general, using
router_from_file/2
is should be preferred, especially if you must maintain multiple versions of the schema, though you may find it easier to iterate usingrouter_from_string/2
during early development. In that case, it is possible to switch torouter_from_file/2
when you are ready to finalize your API design or start versioning
plug-routers
Plug routers
Plug
-only routers, which do not requirePhoenix
, are planned for a future release.
The following activities are performed by the router generated by the macros:
- Tagging inbound requests with API version
- Constructing route and http verb matches in the router
- Parameter operations
- Supports:
- Cookie parameters
- Header parameters
- Path parameters
- Query parameters
- Features:
- Style decoding based on parameter styles (see https://spec.openapis.org/oas/v3.1.0#style-values)
- Custom style decoding
- Parameter marshalling (converting strings to types)
- Parameter validation
- Supports:
- Request body validation
- content-length and content-type validation
- matching content-type with request body plugs
- Automatic json and
form-encoded
request body parsing - Parameter marshalling for
form-encoded
requests
options
Options
The following options are common to router_from_string/2
and router_from_file/2
.
Global options
encoding
: mimetype which describes how the schema is encoded.required in
router_from_string/2
, deduced from filename inrouter_from_file/2
.decoders
: A proplist of mimetype to decoders.If you use an encoding that isn't
application/json
orapplication/yaml
you should provide this proplist, which, at a minimum, contains[{encoding_mimetype, {module, function}}]
. The callmodule.function(string)
should return a map representing the OpenAPI schema, and should raise in the case that the content is not decodable.root
: the root path for the router.Defaults to
/v{major}
wheremajor
is the major version of the API, as declared underinfo.version
in the schema.dump
: (For debugging), sends formatted code of the router to stdout.Defaults to
false
. If set to:all
, will also passdump: true
to Exonerate.
Scopable options
The following options are scopable. They may be placed as top-level options or under the scopes (see below)
controller
: Plug module which contains code implementing the API.It is recommended to
use Phoenix.Controller
in this plug module, or the functions may or may not be targetted as expected.Controller modules should implement public functions corresponding to the
operationId
of each operation in the schema. These functions must be cased in the same fashion as theoperationId
, and like all Phoenix Controller functions, take two arguments:conn
: thePlug.Conn
for the requestparams
: a map containing the parameters for the operation. This is identical toconn.params
.
important
ImportantUnlike standard Phoenix controller functions, parameters declared in the
parameters
list of the operation are made avaliable in theparams
argument as well as inconn.params
. These parameters will overwrite any fields present in body parameters that happen to have the same name.A single router may have its routes target more than one controller.
extra_plugs
: a list of plugs to execute after the route has matched but before the parameter and body pipeline has been executed.These plugs are defined using
{atom, [args...]}
whereargs
is a list of plug options to be applied to the plug, oratom
which is equivalent to{atom, []}
. These may be either a function plug or a module plug.route-level-security-plugs
Route-level Security PlugsRoute-level security checks should be performed in plugs declared in
extra_plugs
, untilApical
provides direct support for security schemes.global-plugs
Global plugsif you need plugs to be executed for all routes, declare those plugs in the router module before the macro
Exonerate.router_from_*
.post-pipeline-plugs
Post-pipeline plugsif you need plugs to be executed after the parameter and body pipeline, for example, for row-level security checks, declare those plugs in the controller module. Note that these plugs should be able to match on the
operationId
atom usingconn.private.operation_id
.styles
: a proplist of custom styles and their corresponding parsers.Each parser is represented as
{module, function, [args...]}
or{module, function}
which is equivalent too{module, function []}
.The parsers are functions that are called as
module.function(string, args...)
, and return{:ok, value}
or{:error, message}
. The message should be a string describing the error.The following styles are supported by default and do not need to be included in the styles proplist:
"matrix"
"label"
"simple"
"form"
"space_delimited"
"pipe_delimited"
"deep_object"
see https://spec.openapis.org/oas/v3.1.0#style-values for description of these styles.
custom-styles
Custom stylesIf you need to support a custom style, you must add it to the
styles
proplist.form-exploded-objects
Form-exploded objectsForm-exploded style parameters with type
object
in their schema are not supported due to ambiguity in their definition per the OpenAPI specification.content_sources
: A proplist of media-types (as string keys) and functions to act as the source for request body. These should be defined as{media_type, {module, [opts...]}}
. These opts will be passed into theApical.Plugs.RequestBody.Source.fetch/3
.nest_all_json
: Analogous to the option inPlug.Parsers.JSON
, this option will nest all json request body payloads under the"_json"
key. if this is not true, objects payloads will be merged intoconn.params
.
Available scopes
The scopes have the following precedence:
operation_ids > tags > parameters > global
operation_ids
: A keywordlist ofoperationId
s (as atom keys) and options to target to these operations.The keys must be cased in the same fashion as the
operationId
in the schema.tags
: A keywordlist of tags (as atom keys) and options to target to those tags.The tag keys must be cased in the same fashion as their tags in the schema.
parameters
: A keywordlist of parameters (as atom keys) and options to target to those parameters.The parameter keys must be cased in the same fashion (including kebab-case) Note that this scope may be further nested inside of
tag
andoperation_ids
scopes.
Link to this section Summary
Functions
Generates a web router from a String containing an OpenAPI document.
Generates a web router from a String containing an OpenAPI document.
Link to this section Functions
Generates a web router from a String containing an OpenAPI document.
example
Example:
defmodule MyRouter do
require Apical
Apical.router_from_file(
"path/to/openapi.yaml",
controller: MyProjectWeb.ApiController
)
end
For options see Apical
module docs.
Generates a web router from a String containing an OpenAPI document.
example
Example:
defmodule MyRouter do
require Apical
Apical.router_from_string(
"""
openapi: 3.1.0
info:
title: My API
version: 1.0.0
paths:
"/":
get:
operationId: getOperation
responses:
"200":
description: OK
""",
controller: MyProjectWeb.ApiController,
encoding: "application/yaml"
)
end
For options see Apical
module docs.