Express provides default HTTP methods that we can listen to for specific routes. When implementing a full REST API, we want to start thinking about our API endpoints as resources that we perform operations upon using specific HTTP methods. The most common operations are to create, read, update, and delete (CRUD) resources. These operations are associated with the POST, GET, PUT, and DELETE HTTP methods in a RESTful API. Besides the HTTP method, there is also a significance in whether the resource is specifically identified or generic. For instance, GET /api/posts will return all blog posts, whereas GET /api/posts/123 will only return a blog post with the ID 123.
The following is a table that lists all the routes in our application, their associated HTTP methods, and what they actually do:
Route | HTTP method/verb | Description |
/api/posts | GET | Get all blog posts |
/api/posts | POST | Create a new blog post |
/api/posts/:post_id | GET | Get a specific blog post using its ID |
/api/posts/:post_id | PUT | Update a specific blog post using its ID |
/api/posts/:post_id | DELETE | Delete a specific blog post using its ID |
Strictly speaking, there is no reason we couldn't have a DELETE /api/posts route that would delete all posts, or a /api/posts/:post_id that creates a new post with the specified ID. However, conventionally, these operations would be too powerful or have undesired complications or ambiguities about their behavior.
Our implementation of the /middleware/rest.js middleware is a factory of sorts to provide a consistent implementation for our REST APIs. Our factory has several mappings provided by resource-router-middleware that automatically trigger certain methods based on the incoming HTTP method and resource identifiers.
Method | Description |
load | A callback to load a given resource by an ID of this type from the store |
list | A callback to read the list of all resources of this type |
read | A callback to read a specific resource of this type |
create | A callback to create a new resource of this type and save it to the store |
update | A callback to update a specific resource of this type and save it to the store |
delete | A callback to delete a specific resource of this type and remove it from the store |
Ultimately, our /middleware/rest.js middleware serves as an abstraction between the route configuration, which provides the resource configuration and store, and the API structure, which should be the same for all our REST APIs. It's potentially possible that we may eventually want more granular control over our routes. For example, what if the DELETE route was only allowed if the current user was the author of the blog post? However, as we will see in practice in later sections in this chapter, it's possible to accommodate these customizations without losing the value of having a factory that sets up consistent default behavior for us.
This abstraction between the route configuration and REST API implementation isn't the only way to build a REST API in Express. However, as we will see in Chapter 8, Relationships, it provides a logical foundation for which future enhancements--such as JSON API serialization and, eventually, database persistence with MongoDB--is much easier and more consistent to implement.