class Athena::Routing::Route
- Athena::Routing::Route
- Reference
- Object
Overview
Provides an object-oriented way to represent an HTTP route, including the path, methods, schemes, host, and/or conditions required for it to match.
Ultimately, ART::Route
s are compiled into ART::CompiledRoute
that represents an immutable
snapshot of a route, along with ART::CompiledRoute::Token
s representing each route parameter.
By default, a route is very liberal in regards to what allows when matching.
E.g. Matching anything that matches the #path
, but with any HTTP method and any scheme.
The #methods
and #schemes
properties can be used to restrict which methods/schemes the route allows.
# This route will only handle `https` `POST` requests to `/path`.
route1 = ART::Route.new "/path", schemes: "https", methods: "POST"
# This route will handle `http` or `ftp` `GET`/`PATCH` requests to `/path`.
route2 = ART::Route.new "/path", schemes: {"https", "ftp"}, methods: {"GET", "PATCH"}
Expressions
In some cases you may want to match a route using arbitrary dynamic runtime logic.
An example use case for this could be checking a request header, or anything else on the underlying ART::RequestContext
and/or ART::Request
instance.
The #condition
property can be used for just this purpose:
route = ART::Route.new "/contact"
route.condition do |context, request|
request.headers["user-agent"].includes? "Firefox"
end
This route would only match requests whose user-agent
header includes Firefox
.
Be sure to also handle cases where headers may not be set.
WARNING Route conditions are NOT taken into consideration when generating routes via an ART::Generator::Interface
.
Parameters
Route parameters represent variable portions within a route's #path
.
Parameters are uniquely named placeholders wrapped within curly braces.
For example, /blog/{slug}
includes a slug
parameter.
Routes can have more than one parameter, but each one may only map to a single value.
Parameter placeholders may also be included with static portions for a string, such as /blog/posts-about-{category}
.
This can be useful for supporting format based URLs, such as /users.json
or /users.csv
via a /users.{_format}
path.
Parameter Validation
By default, a placeholder is happy to accept any value.
However in most cases you will want to restrict which values it allows, such as ensuring only numeric digits are allowed for a page
parameter.
Parameter validation also allows multiple routes to have variable portions within the same location.
I.e. allowing /blog/{slug}
and /blog/{page}
to co-exist, which is a limitation for some other Crystal routers.
The #requirements
property accepts a Hash(String, String | Regex)
where the keys are the name of the parameter and the value is a pattern
in which the value must match for the route to match. The value can either be a string for exact matches, or a Regex
for more complex patterns.
Route parameters may also be inlined within the #path
by putting the pattern within <>
, instead of providing it as a dedicated argument.
For example, /blog/{page<\\d+>}
(note we need to escape the \
within a string literal).
routes = ART::RouteCollection.new
routes.add "blog_list", ART::Route.new "/blog/{page}", requirements: {"page" => /\d+/}
routes.add "blog_show", ART::Route.new "/blog/{slug}"
matcher.match "/blog/foo" # => {"_route" => "blog_show", "slug" => "foo"}
matcher.match "/blog/10" # => {"_route" => "blog_list", "page" => "10"}
TIP: Checkout ART::Requirement
for a set of common, helpful requirement regexes.
Optional Parameters
By default, all parameters are required, meaning given the path /blog/{page}
, /blog/10
would match but /blog
would NOT match.
Parameters can be made optional by providing a default value for the parameter, for example:
ART::Route.new "/blog/{page}", {"page" => 1}, {"page" => /\d+/}
# ...
matcher.match "/blog" # => {"_route" => "blog_list", "page" => "1"}
CAUTION: More than one parameter may have a default value, but everything after an optional parameter must also be optional.
For example within /{page}/blog
, page
will always be required and /blog
will NOT match.
#defaults
may also be inlined within the #path
by putting the value after a ?
.
This is also compatible with #requirements
, allowing both to be defined within a path.
For example /blog/{page<\\d+>?1}
.
TIP: The default value for a parameter may also be nil
, with the inline syntax being adding a ?
with no following value, e.g. {page?}
.
Be sure to update any type restrictions to be nilable as well.
Priority Parameter
When determining which route should match, the first matching route will win. For example, if two routes were added with variable parameters in the same location, the first one that was added would match regardless of what their requirements are. In most cases this will not be a problem, but in some cases you may need to ensure a particular route is checked first.
Special Parameters
The routing component comes with a few standardized parameters that have special meanings. These parameters could be leveraged within the underlying implementation, but are not directly used within the routing component other than for matching.
_format
- Could be used to set the underlying format of the request, as well as determining the content-type of the response._fragment
- Represents the fragment identifier when generating a URL. E.g./article/10#summary
with the fragment beingsummary
._locale
- Could be used to set the underlying locale of theART::Request
based on which route is matched.
ART::Route.new(
"/articles/{_locale}/search.{_format}",
{
"_locale" => "en",
"_format" => "html",
},
{
"_locale" => /en|fr/,
"_format" => /html|xml/,
}
)
This route supports en
and fr
locales in either html
or xml
formats with a default of en
and html
.
TIP: The trailing .
is optional if the parameter to the right has a default.
E.g. /articles/en/search
would match with a format of html
but /articles/en/search.xml
would be required for matching non-default formats.
Extra Parameters
The defaults defined within a route do not all need to be present as route parameters. This could be useful to provide extra context to the controller that should handle the request.
ART::Route.new "/blog/{page}", {"page" => 1, "title" => "Hello world!"}
Slash Characters in Route Parameters
By default, route parameters may include any value except a /
, since that's the character used to separate the different portions of the URL.
Route parameter matching logic may be made more permissive by using a more liberal regex, such as .+
, for example:
ART::Route.new "/share/{token}", requirements: {"token" => /.+/}
Special parameters should NOT be made more permissive.
For example, if the pattern is /share/{token}.{_format}
and {token}
allows any character, the /share/foo/bar.json
URL will consider foo/bar.json
as the token and the format will be empty.
This can be solved by replacing the .+
requirement with [^.]+
to allow any character except dots.
Related to this, allowing multiple parameters to accept /
may also lead to unexpected results.
Sub-Domain Routing
The #host
property can be used to require the HTTP host header to match this value in order for the route to match.
mobile_homepage = ART::Route.new "/", host: "m.example.com"
homepage = ART::Route.new "/"
In this example, both routes match the same path, but one requires a specific hostname.
The #host
parameter can also be used as route parameters, including #defaults
and #requirements
support:
mobile_homepage = ART::Route.new(
"/",
{"subdomain" => "m"},
{"subdomain" => /m|mobile/},
"{subdomain}.example.com"
)
homepage = ART::Route.new "/"
TIP: Inline defaults and requirements also works for #host
values, "{subdomain<m|mobile>?m}.example.com"
.
Defined in:
route.crConstructors
Instance Method Summary
-
#add_defaults(defaults : Hash(String, _)) : self
Adds the provided defaults, overriding previously set values.
-
#add_requirements(requirements : Hash(String, Regex | String)) : self
Adds the provided requirements, overriding previously set values.
-
#clone
Returns a copy of
self
with all instance variables cloned. -
#compile : CompiledRoute
Compiles and returns an
ART::CompiledRoute
representing this route. -
#condition : Condition | Nil
Returns the optional
ART::Route::Condition
callback used to determine if this route should match. -
#condition(&condition : ART::RequestContext, ART::Request -> Bool) : self
Sets the optional
ART::Route::Condition
callback used to determine if this route should match. -
#condition=(condition : Condition | Nil)
Returns the optional
ART::Route::Condition
callback used to determine if this route should match. -
#default(key : String) : String | Nil
Returns the default with the provided key, if any.
-
#defaults : Hash(String, String | Nil)
Returns a hash representing the default values of a route's parameters if they were not provided in the request.
-
#defaults=(defaults : Hash(String, _)) : self
Sets the hash representing the default values of a route's parameters if they were not provided in the request to the provided defaults.
-
#has_default?(key : String) : Bool
Returns
true
if this route has a default with the provided key, otherwisefalse
. -
#has_requirement?(key : String) : Bool
Returns
true
if this route has a requirement with the provided key, otherwisefalse
. -
#has_scheme?(scheme : String) : Bool
Returns
true
if this route allows the provided scheme, otherwisefalse
. -
#host : String | Nil
Returns the hostname that the HTTP host header must match in order for this route to match.
-
#host=(pattern : String | Regex) : self
Sets the hostname that the HTTP host header must match in order for this route to match to the provided pattern.
-
#methods : Set(String) | Nil
Returns the set of valid HTTP methods that this route supports.
-
#methods=(methods : String | Enumerable(String)) : self
Sets the set of valid HTTP method(s) that this route supports.
-
#path : String
Returns the URL that this route will handle.
-
#path=(pattern : String) : self
Sets the path required for this route to match to the provided pattern.
-
#requirement(key : String) : Regex | Nil
Returns the requirement with the provided key, if any.
-
#requirements : Hash(String, Regex)
Returns a hash representing the requirements the route's parameters must match in order for this route to match.
-
#requirements=(requirements : Hash(String, Regex | String)) : self
Sets the hash representing the requirements the route's parameters must match in order for this route to match to the provided requirements.
-
#schemes : Set(String) | Nil
Returns the set of valid URI schemes that this route supports.
-
#schemes=(schemes : String | Enumerable(String)) : self
Sets the set of valid URI scheme(s) that this route supports.
-
#set_default(key : String, value : String | Nil) : self
Sets the default with the provided key to the provided value.
-
#set_requirement(key : String, requirement : Regex | String) : self
Sets the requirement with the provided key to the provided value.
Constructor Detail
Instance Method Detail
Adds the provided defaults, overriding previously set values.
Adds the provided requirements, overriding previously set values.
Compiles and returns an ART::CompiledRoute
representing this route.
The route is only compiled once and future calls to this method will return the same compiled route,
assuming no changes were made to this route in between.
Returns the optional ART::Route::Condition
callback used to determine if this route should match.
See [Routing Expressions][Athena::Routing::Route--expressions] for more information.
Sets the optional ART::Route::Condition
callback used to determine if this route should match.
route = ART::Route.new "/foo"
route.condition do |context, request|
request.headers["user-agent"].includes? "Firefox"
end
See [Routing Expressions][Athena::Routing::Route--expressions] for more information.
Returns the optional ART::Route::Condition
callback used to determine if this route should match.
See [Routing Expressions][Athena::Routing::Route--expressions] for more information.
Returns a hash representing the default values of a route's parameters if they were not provided in the request. See [Optional Parameters][Athena::Routing::Route--optional-parameters] for more information.
Sets the hash representing the default values of a route's parameters if they were not provided in the request to the provided defaults. See [Optional Parameters][Athena::Routing::Route--optional-parameters] for more information.
Returns true
if this route has a default with the provided key, otherwise false
.
Returns true
if this route has a requirement with the provided key, otherwise false
.
Returns true
if this route allows the provided scheme, otherwise false
.
Returns the hostname that the HTTP host header must match in order for this route to match. See [Sub-Domain Routing][Athena::Routing::Route--sub-domain-routing] for more information.
Sets the hostname that the HTTP host header must match in order for this route to match to the provided pattern. See [Sub-Domain Routing][Athena::Routing::Route--sub-domain-routing] for more information.
Returns the set of valid HTTP methods that this route supports. See [ART::Route][] for more information.
Sets the set of valid HTTP method(s) that this route supports. See [ART::Route][] for more information.
Returns the URL that this route will handle. See [Routing Parameters][Athena::Routing::Route--parameters] for more information.
Sets the path required for this route to match to the provided pattern.
Returns the requirement with the provided key, if any.
Returns a hash representing the requirements the route's parameters must match in order for this route to match. See [Parameter Validation][Athena::Routing::Route--parameter-validation] for more information.
Sets the hash representing the requirements the route's parameters must match in order for this route to match to the provided requirements. See [Parameter Validation][Athena::Routing::Route--parameter-validation] for more information.
Returns the set of valid URI schemes that this route supports. See [ART::Route][] for more information.
Sets the set of valid URI scheme(s) that this route supports. See [ART::Route][] for more information.
Sets the default with the provided key to the provided value.
Sets the requirement with the provided key to the provided value.