Routing
Routes can be defined anywhere inside your /app folder. A new Raindeer application generated via rain new :app_name will create app/routes.rb.
The router observes RequestEvents (HTTP requests), matches them to a Route and converts them into RouteEvents. This RouteEvent can be observed by any node and return a response.
Defining a route
You can use simple strings to define a Route. Matching HTTP requests are automatically forwarded to a render or receive method on the node.
Raindeer.router do
route '/'
end
Then observe '/' this route in a node. See: Observing
Route Types
Raindeer.router do
get '/'
query '/'
post '/'
put '/'
patch '/'
delete '/'
end
Then observe '/' in a node. See: Observing
Note
Explicit routes will map their HTTP Verb to the action of the same name; GET calls :get
Multiple HTTP Verbs
Support multiple HTTP request types at once:
Raindeer.router do
route [GET, POST] => '/:user_id'
end
Tip
Route[] is how every route is defined behind the scenes.
Example: get '/' or route GET => '/' will become Route[GET => '/']
Params
Parameters are dynamic sections of a URL that start with a colon (:) which become available as variables in a RouteEvent.
A RouteEvents @params instance variable will contain a hash of every dynamic segment.
Nested routes
Routes can be nested like so:
Raindeer.router do
get '/users' do
get '/:id'
end
end
The above route is functionalty equivalent to:
Raindeer.router do
get '/users/:id'
end
Mid Nodes
Both configurations trigger a RouteEvent for the '/users/:id' path, however the nested example will trigger an additional RouteEvent for the '/users' path. Whether there are any observers for that path is another question and it's perfectly okay to leave an event unobserved.
Observe part of a path with side_effect:
class WatchfulEye < LowNode
observe '/users'
# Will not be called on '/users' but on '/users/*'.
def side_effect(event: RouteEvent)
# Conditionally override the response or log etc.
end
end
Special events
While matching a request with a route is the most common use-case, additional events are triggered in the router lifecycle. These events happen in the following order:
RouteEventWildcardEventStatusEvent
Wildcard events
'/*' Represents every unrouted HTTP request. When this route is defined then you can observe '/*' and receive a WildcardEvent.
Tip
Return nil from render to move on to the next observer
Wildcard events occur after routing so that routing is as fast as possible. If you want to do something before every request then redefine RequestEvent observers.
Status events
When no route is found a StatusEvent will be triggered, such as a "404". Observe the Status type followed by the status code; observe Status[404] and receive a StatusEvent when things go wrong.
Architecture
The router is a prefix tree! Also known as a Trie. It's pretty performant.
Rain::Router is event-driven like other core components. It observes RequestEvents and creates RouteEvents when a URL matches one of the defined routes.
You can call Raindeer.router in multiple files per "feature"; this is in keeping with the compositional nature of Raindeer... but by all means feel free to collate all your routes into one file if that's what you prefer.