Responding to CRUD operations

The term CRUD refers to the four basic operations one can perform on data: create, read, update, and delete. Express gives us an easy way to handle those operations by supporting the basic methods GET, POST, PUT, and DELETE:

  • GET: This method is used to retrieve the existing data from the database. This can be used to read single or multiple rows (for SQL) or documents (for MongoDB) from the database.
  • POST: This method is used to write new data into the database, and it is common to include a JSON payload that fits the data model.
  • PUT: This method is used to update existing data in the database, and a JSON payload that fits the data model is often included for this method as well.
  • DELETE: This method is used to remove an existing row or document from the database.

Express 4 has dramatically changed from version 3. A lot of the core modules have been removed in order to make it even more lightweight and less dependent. Therefore, we have to explicitly require modules when needed.

One helpful module is body-parser. It allows us to get a nicely formatted body when a POST or PUT HTTP request is received. We have to add this middleware before our business logic in order to use its result later. We write the following in src/lib/parser.js:

var bodyParser = require('body-parser'),
module;exports = function(app) {
  app.use(bodyParser.json());
  app.use(bodyParser.urlencoded({ extended: false }));
   };

The preceding code is then used in src/lib/app.js as follows:

var express = require('express'), var app = express();
require('./parser')(app);
module.exports = app;

The following example allows you to respond to a GET request on http://host/path. Once a request hits our API, Express will run it through the necessary middleware as well as the following function:

app.get('/path/:id', function(req, res, next) {
res.status(200).json({ hello: 'world'});
});

The first parameter is the path we want to handle a GET function. The path can contain parameters prefixed with :. Those path parameters will then be parsed in the request object.

The second parameter is the callback that will be executed when the server receives the request. This function gets populated with three parameters: req, res, and next.

The req parameter represents the HTTP request object that has been customized by Express and the middlewares we added in our applications. Using the path http://host/path/:id, suppose a GET request is sent to http://host/path/1?a=1&b=2. The req object would be the following:

{
params: { id: 1 }, query: { a: 1, b: 2 }
}

The params object is a representation of the path parameters. The query is the query string, which are the values stated after ? in the URL. In a POST request, there will often be a body in our request object as well, which includes the data we wish to place in our database.

The res parameter represents the response object for that request. Some methods, such as status() or json(), are provided in order to tell Express how to respond to the client.

Finally, the next() function will execute the next middleware defined in our application.

Retrieving an actor with GET

Retrieving a movie or actor from the database consists of submitting a GET request to the route: /movies/:id or /actors/:id. We will need a unique ID that refers to a unique movie or actor:

app.get('/actors/:id', function(req, res, next) {
//Find the actor object with this :id
//Respond to the client
});

Here, the URL parameter :id will be placed in our request object. Since we call the first variable in our callback function req as before, we can access the URL parameter by calling req.params.id.

Since an actor may be in many movies and a movie may have many actors, we need a nested endpoint to reflect this as well:

app.get('/actors/:id/movies', function(req, res, next) {
//Find all movies the actor with this :id is in
//Respond to the client
});

If a bad GET request is submitted or no actor with the specified ID is found, then the appropriate status code bad request 400 or not found 404 will be returned. If the actor is found, then success request 200 will be sent back along with the actor information. On a success, the response JSON will look like this:

{
"_id": "551322589911fefa1f656cc5", "id": 1,
"name": "AxiomZen", "birth_year": 2012, "__v": 0, "movies": []
}

Creating a new actor with POST

In our API, creating a new movie in the database involves submitting a POST request to /movies or /actors for a new actor:

app.post('/actors', function(req, res, next) {
//Save new actor
//Respond to the client
});

In this example, the user accessing our API sends a POST request with data that would be placed into request.body. Here, we call the first variable in our callback function req. Thus, to access the body of the request, we call req.body.

The request body is sent as a JSON string; if an error occurs, a 400 (bad request) status would be sent back. Otherwise, a 201 (created) status is sent to the response object. On a success request, the response will look like the following:

{
"__v": 0, "id": 1,
"name": "AxiomZen", "birth_year": 2012,
"_id": "551322589911fefa1f656cc5", "movies": []
}

Updating an actor with PUT

To update a movie or actor entry, we first create a new route and submit a PUT request to /movies/:id or /actors /:id, where the id parameter is unique to an existing movie/actor. There are two steps to an update. We first find the movie or actor by using the unique id and then we update that entry with the body of the request object, as shown in the following code:

app.put('/actors/:id', function(req, res) {
//Find and update the actor with this :id
//Respond to the client
});

In the request, we would need request.body to be a JSON object that reflects the actor fields to be updated. The request.params.id would still be a unique identifier that refers to an existing actor in the database as before. On a successful update, the response JSON looks like this:

{
"_id": "551322589911fefa1f656cc5",
"id": 1,
"name": "Axiomzen", "birth_year": 99, "__v": 0, "movies": []
}

Here, the response will reflect the changes we made to the data.

Removing an actor with DELETE

Deleting a movie is as simple as submitting a DELETE request to the same routes that were used earlier (specifying the ID). The actor with the appropriate id is found and then deleted:

app.delete('/actors/:id', function(req, res) {
//Remove the actor with this :id
//Respond to the client
});

If the actor with the unique id is found, it is then deleted and a response code of 204 is returned. If the actor cannot be found, a response code of 400 is returned. There is no response body for a DELETE() method; it will simply return the status code of 204 on a successful deletion.

Our final endpoints for this simple app will be as follows:

//Actor endpoints 
app.get('/actors', actors.getAll);
app.post('/actors', actors.createOne); 
app.get('/actors/:id', actors.getOne); 
app.put('/actors/:id', actors.updateOne); 
app.delete('/actors/:id', actors.deleteOne) 
app.post('/actors/:id/movies', actors.addMovie); 
app.delete('/actors/:id/movies/:mid', actors.deleteMovie);
//Movie endpoints
app.get('/movies', movies.getAll); 
app.post('/movies', movies.createOne);
app.get('/movies/:id', movies.getOne); 
app.put('/movies/:id', movies.updateOne); 
app.delete('/movies/:id', movies.deleteOne); 
app.post('/movies/:id/actors', movies.addActor); 
app.delete('/movies/:id/actors/:aid', movies.deleteActor);

In Express 4, there is an alternative way to describe your routes. Routes that share a common URL, but use a different HTTP verb, can be grouped together as follows:

app.route('/actors')
.get(actors.getAll)
.post(actors.createOne);
app.route('/actors/:id')
.get(actors.getOne)
.put(actors.updateOne)
.delete(actors.deleteOne);
app.post('/actors/:id/movies', actors.addMovie); 
app.delete('/actors/:id/movies/:mid', actors.deleteMovie);
app.route('/movies')
.get(movies.getAll)
.post(movies.createOne);
app.route('/movies/:id')
.get(movies.getOne)
.put(movies.updateOne)
.delete(movies.deleteOne);
app.post('/movies/:id/actors', movies.addActor); 
app.delete('/movies/:id/actors/:aid', movies.deleteActor);

Whether you prefer it this way or not is up to you. At least now you have a choice!

We have not discussed the logic of the function being run for each endpoint. We will get to that shortly.

Express allows us to easily CRUD our database objects, but how do we model our objects?

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.14.131.47