Beta

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:

  1. It determines if an incoming request's HTTP Method & Path match with a predefined route.
  2. It dispatches the request to the correct controller action.
  3. 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" }.

Data Structures
Regular Expressions
Algorithms

More By Author:

Check out these other kata created by DiegoSalazar

Stats:

CreatedMay 12, 2015
PublishedMay 12, 2015
Warriors Trained85
Total Skips21
Total Code Submissions778
Total Times Completed21
Ruby Completions21
Total Stars2
% of votes with a positive feedback rating67% of 3
Total "Very Satisfied" Votes1
Total "Somewhat Satisfied" Votes2
Total "Not Satisfied" Votes0
Total Rank Assessments5
Average Assessed Rank
5 kyu
Highest Assessed Rank
3 kyu
Lowest Assessed Rank
6 kyu
Ad
Contributors
  • DiegoSalazar Avatar
Ad