arizona_roadrunner_router (arizona_roadrunner v0.1.0)

View Source

Compiles a list of Arizona route specs into a roadrunner route table.

The resulting compiled routes are stored in persistent_term under the listener-scoped key {arizona_roadrunner_dispatch, Name} -- one entry per listener, so arizona_roadrunner_req:resolve_route/3 resolves a WS upgrade/navigate against the routes of the listener that accepted it, and two listeners do not clobber each other. Calling compile_routes/3 again replaces the previous compiled set, which is how arizona_roadrunner_server:recompile_routes/0 picks up new routes after a hot reload without restarting the listener.

Route shapes

TagDescriptionRoadrunner handler
{live, Path, Handler, Opts}Arizona stateful pagearizona_roadrunner_http
{ws, Path, Opts}WebSocket endpointarizona_roadrunner_ws
{asset, Path, {dir, Dir}[, Opts]}Static files from directoryroadrunner_static
{asset, Path, {priv_dir, App, Sub}[, Opts]}Static files from app privroadrunner_static
{Verb, Path, Handler, Opts}Single-verb controllerarizona_roadrunner_controller
{match, Spec, Path, Handler, Opts}Multi/custom methodsarizona_roadrunner_controller
{mcp, Path, Handler, Opts}MCP serverarizona_roadrunner_controller
{reload, Path, Opts}Dev SSE reload endpointarizona_roadrunner_controller

Verb is get/post/put/patch/delete/head/options; match's Spec is a single verb, a list of verbs, a custom uppercase method binary, or '*' (any method).

An {asset, ...} route answers GET and HEAD only (plus OPTIONS when it carries a CORS transform, for the preflight); any other method gets 405 + Allow.

An {asset, ...} route's optional Opts is #{cache_control => binary()} -- a Cache-Control header set verbatim on cacheable responses (off by default); use it only for content-hashed assets, never arizona's own stable bundle filenames.

An {asset, Path, ...} route compiles to Path/*path, so the catch-all is generated rather than written and is invisible in the route list. Matching is first-match-wins in list order, which makes an asset path listed ahead of a longer one it prefixes swallow that one -- ~"/static" before ~"/static/arizona" serves, and 404s, every request meant for the latter. Order the longer prefix first.

The dev-mode signals a {reload, ...} or arizona_dev_mcp route carries are not written here: the server reports its running listeners to arizona_server_registry, which keeps them in step. routes/1,2 only expand, so a listener start can build and validate its table before writing anything.

Summary

Functions

Compiles Routes into a roadrunner route table and stores it under the listener-scoped persistent term key {arizona_roadrunner_dispatch, Name}, so each listener's WS upgrade/navigate (arizona_roadrunner_req:resolve_route/3) resolves against its own routes. Replaces any previous compiled set atomically. This is the form the server boot/recompile path uses.

Erases the listener-scoped dispatch key written by compile_routes/3. Called by arizona_roadrunner_server:stop/1 so a stopped listener leaves no stale compiled routes behind.

Formats route-compilation errors into a human-readable message. Picked up by erl_error:format_exception/3 via the error_info annotation at the raise site.

The innermost roadrunner middleware of a route whose OPTIONS was opened only so its CORS transform can answer a preflight (see open_cors_options/1). The transform short-circuits a preflight, so an OPTIONS reaching here is a plain one, answered 204 with the Allow set a 405 on that URL would carry rather than handed to a controller action or live page that never declared the method.

Translates a list of Arizona routes into roadrunner's route entries (map shape) without compiling. Used by the listener boot path so the live and recompile flows share the same expansion logic.

Like routes/1 with build-time opts (see compile_routes/2).

Types

asset_opts()

-nominal asset_opts() :: #{cache_control => binary(), middlewares => [arizona_middleware:http_transform()]}.

asset_source()

-nominal asset_source() :: {dir, file:filename_all()} | {priv_dir, atom(), file:filename_all()}.

controller_opts()

-nominal controller_opts() ::
             #{state => term(),
               action => atom(),
               middlewares => [arizona_middleware:middleware()],
               check_origin => boolean(),
               _ => term()}.

method()

-nominal method() :: get | post | put | patch | delete | head | options.

method_spec()

-nominal method_spec() :: atom() | binary() | [atom() | binary()].

path()

-nominal path() :: binary().

route()

-nominal route() ::
             {live, path(), module(), arizona_live:route_opts()} |
             {ws, path(), map()} |
             {asset, path(), asset_source()} |
             {asset, path(), asset_source(), asset_opts()} |
             {method(), path(), module(), controller_opts()} |
             {match, method_spec(), path(), module(), controller_opts()} |
             {mcp, path(), module(), arizona_mcp_handler:route_opts()} |
             {reload, path(), map()}.

Functions

compile_routes(Routes, BuildOpts, Name)

-spec compile_routes(Routes, BuildOpts, Name) -> ok
                        when Routes :: [route()], BuildOpts :: map(), Name :: atom().

Compiles Routes into a roadrunner route table and stores it under the listener-scoped persistent term key {arizona_roadrunner_dispatch, Name}, so each listener's WS upgrade/navigate (arizona_roadrunner_req:resolve_route/3) resolves against its own routes. Replaces any previous compiled set atomically. This is the form the server boot/recompile path uses.

BuildOpts threads build-time options through to per-route expansion:

  • compress — when true (default), roadrunner_compress is attached as a per-route middleware on live and asset routes. WS, dev SSE reload, and controller (verb/match) routes are not compressed.

forget_routes(Name)

-spec forget_routes(Name) -> ok when Name :: atom().

Erases the listener-scoped dispatch key written by compile_routes/3. Called by arizona_roadrunner_server:stop/1 so a stopped listener leaves no stale compiled routes behind.

format_error(Reason, Stacktrace)

-spec format_error(Reason, Stacktrace) -> ErrorInfo
                      when
                          Reason :: term(), Stacktrace :: [tuple()], ErrorInfo :: #{general := iolist()}.

Formats route-compilation errors into a human-readable message. Picked up by erl_error:format_exception/3 via the error_info annotation at the raise site.

options_reply(Req, Next, State)

-spec options_reply(Req, Next, State) -> roadrunner_handler:result()
                       when
                           Req :: roadrunner_req:request(),
                           Next :: roadrunner_middleware:next(),
                           State :: term().

The innermost roadrunner middleware of a route whose OPTIONS was opened only so its CORS transform can answer a preflight (see open_cors_options/1). The transform short-circuits a preflight, so an OPTIONS reaching here is a plain one, answered 204 with the Allow set a 405 on that URL would carry rather than handed to a controller action or live page that never declared the method.

routes(Routes)

-spec routes(Routes) -> [roadrunner_router:route()] when Routes :: [route()].

Translates a list of Arizona routes into roadrunner's route entries (map shape) without compiling. Used by the listener boot path so the live and recompile flows share the same expansion logic.

routes(Routes, BuildOpts)

-spec routes(Routes, BuildOpts) -> [roadrunner_router:route()]
                when Routes :: [route()], BuildOpts :: map().

Like routes/1 with build-time opts (see compile_routes/2).