Routers & Routes
We have implemented a controller with a single action that returns a list of rentals. The controller and its actions by itself cannot handle requests. It is not until we bind a controller's action with a route are we able to handle requests from client.
The route serves as the public facing access point to the Blueprint application. The route is consists of an HTTP verb (e.g., GET
, DELETE
, POST
, and PUT
) and a path (e.g., /a/b/c
). In the super-rentals example, there is the single route GET /api/rentals
. Because we want our Blueprint application to serve as the API service for the super-rentals example, we need our application to define the same route as expect by the EmberJS application.
Defining Your Router
All routes are defined in a router. For our work, we are are going to define our route in the router named rental
. There are several approaches we can use when defining a router, which depends on how much reuse we want across a routes paths. The first approach is we can define all routes in a single router with nested definitions. For example:
This approach works well if you are not modularizing your router definition such that a single router focuses on a single aspect of the application. Instead, you have a single monolithic router that defines every route in your application.
As you scale your application to contain routes for many facets of the application, you will find this approach becomes hard to maintain. Moreover, it will be hard to mount a router defined inside a Blueprint module since the mounted router may define more routes than you want to expose publicly from your Blueprint application.
The second approach is to modularize your routes across different routers. This approach, however, makes it hard to reuse parts of the routes path across different router definitions. To address this problem, you can place different routers that share common base paths in the same subdirectory structure. The names of the subdirectories will constitute the base paths for the routes defined in each router.
Since we want to plan for growth, and showcase how routers in subdirectories work, we will opt for the second approach of defining routers inside of subdirectories.
As mentioned before, the super-rentals
example has a single route GET /api/rentals
. Let's assume that if we want to define other routes, they will have the base path /api
. We therefore want to define our routers in the subdirectory named api
. Let's start with the single router named rental
.
As you will notice about, we define a router with the single path /rentals
. We do not include /api
in the path definition because this router is located in the api
subdirectory. This means that routes defined in routers located in the api
subdirectory will be prefixed with /api
. If we placed this same router in the subdirectory named v1
, which is a subdirectory of api
, then the base path will be /api/v1
.
Defining routers in subdirectories is the recommended approach to versioning routes in your Blueprint application.
Binding Your Route to an Action
We have defined the route for the application, but we need the route to perform an action when the client makes a request to /api/rentals
. As previously discussed, the HTTP verb we need to respond to is the GET
verb. We already have implemented the action that returns a list of rentals. Let's bind this path to that specific action.
Update the /rental path in the router specification with the code below.
Now, you should be able to go to the url http://localhost:5000/api/rentals