How to share config across handlers
View Sourceconfig is one value, set once at startup, that every request can
read. You need it when your handlers all want the same things: a
database pool, a cache, settings you read at boot. It saves you
from capturing them in a closure for every handler, reaching for a
global, or smuggling them through the per-request meta map (which
is really for per-request scratch).
Pass config at startup
Pass config when you start the service. It is whatever you like,
most often a map of handles, and the same value reaches every
request:
{ok, Pid} = livery:start_service(#{
http => #{port => 8080},
config => #{db => DbPool, cache => CachePid},
router => Router
}).Read it in a handler
Use livery_req:config/1 for the whole value:
list_users(Req) ->
#{db := Db} = livery_req:config(Req),
livery_resp:json(200, json:encode(users:all(Db))).or livery_req:config/2,3 to pull one key out of a map config:
list_users(Req) ->
Db = livery_req:config(db, Req),
livery_resp:json(200, json:encode(users:all(Db))).Middleware sees the same request, so it can read config too:
call(Req, Next, _Opts) ->
Limiter = livery_req:config(limiter, Req),
enforce(Limiter, Req, Next).Use a record, if you prefer
Config is any term, so a record gives you a little more discipline than a map:
%% -record(app, {db, cache}).
show(Req) ->
App = livery_req:config(Req),
livery_resp:json(200, fetch(App#app.db)).Set config on a single listener
livery:start_listener/2 takes config the same way:
{ok, _} = livery:start_listener(livery_h1, #{
port => 8080, config => App, stack => Stack, handler => Handler
}).A config inside one protocol's map on start_service/1 overrides
the service-wide one for that listener, handy when, say, your TLS
endpoint should point at a different pool.
Test with config in the spec
Handlers stay testable with no socket: put config in the request
spec.
Cap = livery_test_adapter:run([], fun my_app:list_users/1,
#{method => <<"GET">>, config => #{db => FakeDb}}).Notes
configis service-wide and set at startup: the same value for every request, read-only. Use it for shared handles and settings.metais per-request scratch a middleware writes for this one request, like the authenticated user or a trace id. See Write a custom middleware.
See also
- Concept: Request and response model
- Guide: Write a custom middleware
- Reference:
livery_req,livery_service