livery_middleware behaviour (livery v0.1.0)

View Source

Tower-style middleware pipeline.

A stack is an ordered list of middleware entries, each of which is either:

  • a {Module, State} tuple where Module implements the livery_middleware behaviour (call/3); or
  • a fun fun((Req, Next) -> Resp).

The pipeline terminates in a handler, which is either {Module, Function} or a fun fun((Req) -> Resp). run/3 walks the stack, threading a Next continuation that invokes the rest of the stack plus the handler. Middleware can short-circuit (never call Next), transform the request before calling Next, transform the response after, or both.

Callback

  • call(Req, Next, State) -> Resp — invoke the middleware with the request, the next continuation, and the per-instance state.

Summary

Functions

Lift a response transformer into a middleware entry.

Lift a request transformer into a middleware entry.

Execute the middleware stack followed by the handler.

Wrap the downstream call in a try/catch.

Types

entry()

-type entry() :: {module(), term()} | fun((req(), next()) -> resp()).

handler()

-type handler() :: {module(), atom()} | fun((req()) -> resp()).

next()

-type next() :: fun((req()) -> resp()).

req()

-type req() ::
          #livery_req{protocol :: h1 | h2 | h3,
                      method :: binary(),
                      scheme :: binary(),
                      authority :: binary(),
                      path :: binary(),
                      raw_query :: binary(),
                      bindings :: #{binary() => binary()},
                      headers :: [{binary(), binary()}],
                      peer :: {inet:ip_address(), inet:port_number()} | undefined,
                      tls :: undefined | map(),
                      body :: empty | {buffered, iodata()} | {stream, term()},
                      adapter :: module() | undefined,
                      stream :: term(),
                      engine_pid :: pid() | undefined,
                      notifier_pid :: pid() | undefined,
                      disc_ref :: reference() | undefined,
                      req_id :: binary(),
                      started_at :: integer() | undefined,
                      meta :: map()}.

resp()

-type resp() ::
          #livery_resp{status :: 100..599,
                       headers :: [{binary(), binary()}],
                       body ::
                           {full, iodata()} |
                           {chunked, fun((term()) -> ok | {error, term()})} |
                           {sse, fun((term()) -> ok | {error, term()})} |
                           {file,
                            file:name_all(),
                            undefined | {non_neg_integer(), non_neg_integer() | eof}} |
                           {upgrade, ws | wt, term()} |
                           empty | taken_over,
                       trailers ::
                           undefined | [{binary(), binary()}] | fun(() -> [{binary(), binary()}])}.

stack()

-type stack() :: [entry()].

Callbacks

call/3

-callback call(req(), next(), term()) -> resp().

Functions

after_response(Fun)

-spec after_response(fun((resp()) -> resp())) -> entry().

Lift a response transformer into a middleware entry.

before(Fun)

-spec before(fun((req()) -> req())) -> entry().

Lift a request transformer into a middleware entry.

The returned entry calls Fun(Req) to derive a new request, then invokes the rest of the pipeline.

run/3

-spec run(stack(), handler(), req()) -> resp().

Execute the middleware stack followed by the handler.

wrap(Fun)

-spec wrap(fun((throw | error | exit, term(), list()) -> resp())) -> entry().

Wrap the downstream call in a try/catch.

Fun is called as Fun(Class, Reason, Stacktrace) and must return a #livery_resp{}. Intended for top-of-stack error recovery. Class is throw | error | exit.