Basic Router With Named Segments
Description:
At the forefront of most modern web servers is the Router. This class receives and appropriately handles every new HTTP request to the server. In this kata, we'll build a simple Router class for our fictional microframework Kwipper.
Our router has three things it must accomplish to serve it's purpose:
- It determines if an incoming request's HTTP Method & Path match with a predefined route.
- It dispatches the request to the correct controller action.
- It prepares the correct parameters from any named segments in the request's path.
For this set of behavior, the Router class implements three methods: route?
, dispatch
and segments
, respectively.
class Router
def route?(request_info)
# the request_info argument is an incoming URL string
# return true or false if it matches a key in ROUTES
end
def dispatch
# return the values from the matching route in ROUTES
end
def segments
# return a hash where the keys are the names of each segment
# as defined in the ROUTES hash and the values are the matched
# segments from the incoming request_info URL string
end
end
The Router will be initialized with a ROUTES
hash representing the routes of our Kwipper app. This hash will be used by each of the methods above to accomplish thier goal.
ROUTES = {
# a static route
"GET /home" => ["HomeController", :index],
# a named segment route
"GET /posts/:slug/comments/:id/edit" => ["CommentsController", :edit]
}
The segments that begin with a colon are named segments. The strings following the colons are the segment names, these will be the keys of the hash returned from the segments method.
def route?
When a request comes into our imaginary app, the route?
method is the first method that will be called. It will be called with a string argument, request_info
. For example: "GET /path"
where /path
is any path. It should return truthy
if the request_info
string matches a route key in the ROUTES
hash. Keep named segments in mind as well. Given a request_info
string such as "GET /posts/test-post/comments/12/edit"
, it should match the named segment route key "GET /posts/:slug/comments/:id/edit"
from the ROUTES
hash.
def dispatch
Second, the dispatch
method is called to determine which controller action should handle the request. Notice the values in the ROUTES
hash are Arrays containing a controller class and an action name. These are the controllers and actions that will be handling requests to their corresponding routes. The Router's dispatch method should return these two values when given a request_info
string.
def segments
Finally, the segments
method comes into play. It's job is to return part of the "params" hash that is generated by named segments. When route?
is called with a request_info
string that matches a named segment route, subsequent calls to the segments method should return a hash. The keys of this hash are the names of the segments and the values are the parts of the path that correspond to each named segment.
For example, given that route?
is called with a request_info
string "GET /posts/test-post/comments/12/edit"
, and a matching named segment route "GET /posts/:slug/comments/:id/edit"
exists, a subsequent call to the segments
method should return { slug: "test-post", id: "12" }
.
Similar Kata:
Stats:
Created | May 12, 2015 |
Published | May 12, 2015 |
Warriors Trained | 85 |
Total Skips | 21 |
Total Code Submissions | 778 |
Total Times Completed | 21 |
Ruby Completions | 21 |
Total Stars | 2 |
% of votes with a positive feedback rating | 67% of 3 |
Total "Very Satisfied" Votes | 1 |
Total "Somewhat Satisfied" Votes | 2 |
Total "Not Satisfied" Votes | 0 |
Total Rank Assessments | 5 |
Average Assessed Rank | 5 kyu |
Highest Assessed Rank | 3 kyu |
Lowest Assessed Rank | 6 kyu |