Callbacks
Table of Contents
Callbacks
There are three callbacks which are required for every request handler:
init/3, HttpMethod/3 and terminate/4.
Types
Route = cowboy_router:route_match()
Req = pid()
State = any()
json_term() = [json_term()]
| {binary() | atom(), json_term()}
| true
| false
| null
| integer()
| float()
| binary()
status_binding() = continue
| switching_protocols
| ok
| created
| accepted
| non_authoritative_information
| no_content
| reset_content
| partial_content
| multiple_choices
| moved_permanently
| found
| see_other
| not_modified
| use_proxy
| switch_proxy
| temporary_redirect
| bad_request
| unauthorized
| payment_required
| forbidden
| not_found
| not_allowed
| not_acceptable
| proxy_authentication_required
| request_timeout
| conflict
| gone
| length_required
| precondition_failed
| request_entity_too_large
| request_uri_too_long
| unsupported_media_type
| requested_range_not_satisfiable
| expectation_failed
| internal_server_error
| not_implemented
| bad_gateway
| service_unavailable
| gateway_timeout
| http_version_not_supported
Status = non_neg_integer() | binary() | status_binding()
Headers = [{binary(), iodata()}]
Body = string() | binary() | {json | msgpack, json_term()} | {html, binary()}
Behaviour
prefix/0
This is an optional callback which you can use for prefixing routes.
Module:prefix() -> string()
Example:
prefix() -> "/v1".
NOTE: this won't affect ~Route~s in the handler, but instead, this will be used when gathering routes and starting the Cowboy listener.
init/3
Module:init(Route, Req, State) ->
{ok, State}.
cross_domains/3
This is an optional callback that lets you enable cross-domain requests (CORS).
Module:cross_domains(Route, Req, State) -> {[HostMatch], State}
HostMatch is equal to Cowboy HostMatch syntax.
This will be used when preparing headers right before replying.
If one of the HostMatches and the Origin match, access-control-allow-origin
will be set to the Origin.
is_authenticated/3
Exporting this callback in a module means that every request that should come to the handler needs authorization.
Module:is_authenticated(Route, Req, State) ->
{true, State} | {false, Body, State} | {false, Headers, Body, State}
has_permission/3
This is an optional callback which lets you handle if a request has permission to proceed or not.
This callback will be called after Module:is_authenticated/3 if
authentication succeeds.
Module:has_permission(Route, Req, State) ->
{true, State} | {false, Body, State} | {false, Headers, Body, State}
HttpMethod/3
This means get/3, put/3, post/3, delete/3.
Module:HttpMethod(Route, Req, State) ->
{Body, State} | {Status, Body, State} | {Status, Headers, Body, State}
In this case, Route must be a pattern that would match only a single string.
Examples:
get("/", Req, State) ->
...
{<<"index">>, State}.
put("/:id/edit", Req, State) ->
...
{200, <<"edited">>, State}.
post("/new", Req, State) ->
...
{201, [{<<"Location">>, <<"/data/386">>}], <<"created">>, State}.
delete("/:id", Req, State) ->
...
%% Body as a json
{204, {json, [{<<"message">>, <<"deleted">>}]}, State}.
terminate/4
Module:terminate(Reason, Route, Req, State) -> ok
Type:
Reason = normal | not_allowed | unauthenticated | no_permission | {error, any()}
Example
Please pay attention to comment.
-module(example).
-compile({parse_transform, leptus_pt}).
-export([prefix/0]).
-export([init/3]).
-export([cross_domains/3]).
-export([is_authenticated/3]).
-export([get/3]).
-export([terminate/4]).
prefix() -> "/example".
init(_Route, _Req, State) ->
{ok, State}.
cross_domains(_Route, _Req, State) ->
{['_'], State}.
is_authenticated(_Route, _Req, State) ->
{true, State}.
%% Route is "/1" in every callback in this example,
%% but we used prefix/0 to prepend "/example",
%% so this will be used by issuing the url '/example/1'
get("/1", _Req, State) ->
{<<"Example 1!">>, State}.
terminate(_Reason, _Route, _Req, _State) ->
ok.