openapi_handler
is a library translating OpenAPI requests
into native Erlang function calls. It takes schema (compiled single file JSON or YAML), extracts, validates
and converts request parameters to Erlang types.
First, you need to compile cowboy routes for your schema.
PetstoreRoutes = openapi_handler:routes(#{
schema => PetstorePath, % path/to/your/schema.{json,yaml}
prefix => <<"/api/prefix">>, % HTTP path prefix for your API
name => petstore_server_api, % API identifier, must be unique
module => petstore_impl % A module with functions to call
}),
cowboy:start_clear(petstore_api_server, [{port, 8000}],
#{env => #{dispatch => cowboy_router:compile([{'_', PetstoreRoutes}])}}),
Your callback module needs authorize function:
authorize(#{authorization := AuthorizationHeader, operationId := OperationId, args := OperationParams,
ip := _, name := ApiName, accept := _}) ->
% Any map for success (will appear as auth_context),
% {error, _} on bad auth
#{user_id => 42}.
Then, for each operationId
you want to handle, create a function with that name in the callback module.
For example, assume part of your schema is:
paths:
'/user/{username}':
get:
operationId: getUserByName
parameters:
- name: username
in: path
required: true
schema:
type: string
When a client performs GET /api/prefix/user/Jack
, the corresponding function is called
with a map of parameters as a single argument:
petstore_impl:getUserByName(#{username => <<"Jack">>} = _OperationArgs) ->
#{id => 3418, email => <<"[email protected]">>}.
OperationArgs
is OperationParams with some added fields:
auth_context
-- a term returned byauthorize/1
callback
Valid callback return values are:
{json, StatusCode, #{} = RespObject}
-- the server will respond with given status and RespObject encoded as JSON in body{json, StatusCode, undefined}
-- the server will respond with given status and no body{error, badrequest | enoent | unavailable}
-- shortcuts for statuses 400, 404, 503 accordingly with minimal status description in bodyok
-- status 204 with no body#{} = RespObject
-- shortcut to{json, 200, RespObject}
<<_/binary>>
-- status 200 and exactly this body{raw, Code, #{} = Headers, <<_/binary>> = Body}
-- the server will respond with given status Code, Headers and Body, Headers MUST include 'Content-Type' header
If your schema describes responses
, the callback return value is validated against response schema.
E.g., if you return an atom or a binary where schema requires integer, it will be an error, and response code will be 500.
Also see validation quirks below.
Schema | Erlang |
---|---|
string | binary |
integer | integer |
number | number |
enum | atom |
oneOf(const) | atom |
boolean | boolean |
openapi_handler
allows undefined
value for non-nullable
fields and drops these fields.
This behaviour allows writing simple code like Response = #{key1 => key1_getter(State)}
without
further complex fillering of each key/value pair.