Routing¶
Routes are declared in config/routes.raku with a declarative DSL. A routes
block builds a router that maps an incoming method and path to a controller
action or an inline handler.
1 2 3 4 5 6 7 8 9 10 | |
The draw block¶
routes (and its alias draw) takes a block and returns a
MVC::Keayl::Router. Inside the block the verb helpers register routes on that
router.
At boot the application loads the routes file with load-routes:
1 | |
load-routes evaluates the file and returns the router its routes block built.
Verb helpers¶
get, post, put, patch, delete, and options each declare a route for
that method. The target is given with to:
1 2 | |
A 'controller#action' string target is split into a controller and an action.
A Callable target is kept as an inline handler. A GET route also answers
HEAD.
match and via¶
match registers one path for several verbs. via accepts a single verb, a
list of verbs, the string 'all', or * for every verb:
1 2 3 | |
root¶
root maps GET / to a target and names the route root:
1 | |
Path patterns¶
A path can carry dynamic segments, a glob, optional groups, a format, and per-segment constraints. The matched values become params on recognition.
1 2 3 4 | |
A :segment matches a single path segment, stopping at a / or a .. A
*glob matches everything that remains, including slashes. Anything inside
(...) is optional.
format => True appends an optional (.:format) segment without writing it out:
1 | |
defaults supplies values for params that are absent from the path, and
constraints restricts a segment to a pattern. A request whose segment fails the
constraint falls through to the next route:
1 2 3 | |
Resources¶
resources declares the seven REST routes for a resource in one call:
1 | |
| Verb | Path | Action | Name |
|---|---|---|---|
| GET | /users |
index | users |
| POST | /users |
create | users |
| GET | /users/new |
new | new-user |
| GET | /users/:id |
show | user |
| GET | /users/:id/edit |
edit | edit-user |
| PATCH / PUT | /users/:id |
update | user |
| DELETE | /users/:id |
destroy | user |
Pass several names to declare more than one resource at once:
1 | |
Limiting actions¶
only and except choose which of the seven actions to generate:
1 2 | |
Member and collection routes¶
A block adds extra routes. member routes act on a single record (/:id),
collection routes act on the set:
1 2 3 4 5 6 7 8 | |
on does the same for a single route without a block:
1 2 3 | |
Member route names are suffixed with the singular (preview-photo), collection
routes with the plural (search-photos).
Resource options¶
| Option | Effect |
|---|---|
path |
Override the URL segment (/team instead of /people). |
as |
Override the helper name base. |
controller |
Override the target controller. |
module |
Prefix the controller (admin/posts). |
param |
Rename the member key (:slug instead of :id). |
path-names |
Rename the new and edit URL segments. |
1 2 3 4 5 | |
Singular resources¶
resource declares a resource with no index and no :id, for a thing there is
only one of per request (a profile, an account):
1 | |
| Verb | Path | Action | Name |
|---|---|---|---|
| GET | /profile/new |
new | new-profile |
| POST | /profile |
create | profile |
| GET | /profile |
show | profile |
| GET | /profile/edit |
edit | edit-profile |
| PATCH / PUT | /profile |
update | profile |
| DELETE | /profile |
destroy | profile |
The controller defaults to the plural (profiles). resource takes the same
options as resources (only, except, path, as, controller, module,
path-names, and member/collection blocks).
Nesting¶
Resources nest inside a resource block. A nested resource is scoped under the parent member, and its key is named after the parent:
1 2 3 | |
This produces /magazines/:magazine_id/ads, /magazines/:magazine_id/ads/:id,
and so on, with helper names prefixed by the parent singular (magazine-ads,
magazine-ad, new-magazine-ad, edit-magazine-ad). Plural and singular
resources nest either way, and nesting can go more than one level deep, though
nesting more than one level deep is usually a sign the routes want flattening.
Shallow nesting¶
shallow keeps the collection routes (index, new, create) nested but lifts the
member routes (show, edit, update, destroy) to the top level, so member URLs stay
short:
1 2 3 | |
Collection routes stay at /magazines/:magazine_id/ads, while member routes move
to /ads/:id. The member helpers drop the parent prefix (ad rather than
magazine-ad). shallow-path overrides the shallow member segment and
shallow-prefix overrides the shallow member name prefix:
1 | |
Namespaces and scopes¶
namespace prefixes the path, the controller module, and the helper name all at
once:
1 2 3 | |
scope controls each of those independently:
1 2 3 | |
controller sets the controller for the routes inside, so a target can be just
an action and a bare path defaults its action:
1 2 3 4 | |
An optional scope segment is written with parentheses, which suits an i18n locale prefix that may or may not be present:
1 2 3 | |
Scopes nest and compose their prefixes.
Concerns¶
A concern is a reusable block of routes. Define it once with concern, then mix
it into resources with the concerns option or a concerns call inside a block:
1 2 3 4 | |
Concern routes nest under the resource that mixes them in, so
/posts/:post_id/comments and /photos/:photo_id/comments both appear.
Constraints and defaults¶
A constraints block restricts the routes inside it. Segment keys constrain path
params, while subdomain, host, format, protocol, port, and method
constrain request attributes:
1 2 3 4 5 6 7 | |
A custom constraint is a callable that receives the request context, or an object
with a matches method:
1 2 3 | |
Request constraints are checked during recognition against a context hash:
1 | |
A defaults block supplies default params for the routes inside it:
1 2 3 | |
Redirects and mounting¶
A route can redirect instead of dispatching to a controller. redirect takes a
string or a block that computes the location from the params, and an optional
status:
1 2 | |
mount attaches a sub-app at a path. The mount matches the mount point and
everything below it, capturing the remainder as mounted_path:
1 | |
URL helpers¶
MVC::Keayl::Routing::UrlHelpers generates paths and URLs from named routes.
path-for fills the segments, turns leftover params into a sorted query string,
and handles anchor and trailing-slash:
1 2 3 4 5 | |
url-for builds an absolute URL from default-url-options (host, protocol,
port), each overridable per call. The name-path and name-url helpers also
resolve through FALLBACK:
1 2 3 4 5 | |
Custom and polymorphic helpers¶
direct registers a helper computed by a block. polymorphic-path and
url-for dispatch a record to its route by class name and persistence state, and
resolve customizes that mapping:
1 2 | |
1 2 3 4 | |
Recognition¶
The router answers recognize($method, $path), returning a match or an
undefined match when nothing fits. A context hash supplies request attributes
for request constraints:
1 2 3 4 5 6 7 | |
recognition-status distinguishes a hit from a wrong method and from an unknown
path, and allowed-methods lists the verbs a path answers:
1 2 3 4 5 | |
route-named($name) looks a route up by its name, and route-table returns the
name / verbs / pattern / target of every route, which keayl routes prints.