We now have a youtube channel. Subscribe!

Express.js | RESTFul APIs

Express.js | RESTFul APIs


Hello folks! Welcome back to a new section of our tutorial on ExpressJS. In this tutorial guide, we will be studying about ExpressJS RESTFul APIs.

An API is always required to create mobile apps, single page apps, use AJAX calls and give data to clients. An architectural style of how to structure and name these APIs and the endpoints is known as REST which is an abreviation of Representational Transfer State. HTTP 1.1 was designed having REST principles in mind. REST was introduced by Roy Thomas Fielding in the year 2000 in his Paper Fielding Dissertations.

RESTful URls and methods provides us with almost all information we need to process a request. The table given below summarizes how the various verbs ought to be used and how URls should be named. We are going to be creating a movies API toward the end; let us now discuss how it will be structured.

MethodURIDetailsFunction
GET/moviesSafe, cachableGets the list of all movies and their details
GET/movies/1234Safe, cachableGets the details of Movie id 1234
POST/moviesN/ACreates a new movie with the details provided. Response contains the URI for this newly created resource.
PUT/movies/1234IdempotentModifies movie id 1234(creates one if it doesn't already exist). Response contains the URI for this newly created resource.
DELETE/movies/1234IdempotentMovie id 1234 should be deleted, if it exists. Response should contain the status of the request.
DELETE or PUT/moviesInvalidShould be invalid.DELETE and PUT should specify which resource they are working on.


Let's now create this API in Express. We will be using JSON as our transport data format as it is easy to work with in JavaScript and has other benefits. Replace your index.js file with the movies.js file as in the code below.

index.js

var express = require('express');
var bodyParser = require('body-parser');
var multer = require('multer');
var upload = multer();

var app = express();

app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(upload.array());

//Require the Router we defined in movies.js
var movies = require('./movies.js');

//Use the Router on the sub route /movies
app.use('/movies', movies);

app.listen(3000);

Now that we have our application set up, let us concentrate on creating the API.

Start by setting up the movies.js file. We are not using a database to store the movies but are storing them in memory; so every time the server restarts, the movies added by us will vanish. This can easily be copied using a database or a file (using node fs module).

As soon as you import Express then, create a Router and export it using module.exports -

var express = require('express');
var router = express.Router();
var movies = [
   {id: 101, name: "Fight Club", year: 1999, rating: 8.1},
   {id: 102, name: "Inception", year: 2010, rating: 8.7},
   {id: 103, name: "The Dark Knight", year: 2008, rating: 9},
   {id: 104, name: "12 Angry Men", year: 1957, rating: 8.9}
];

//Routes will go here
module.exports = router;

GET routes

Let's define the GET route for getting all the movies -

router.get('/', function(req, res){
   res.json(movies);
});

To test if this is working fine, run your app, then open your terminal and enter -

curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET 
localhost:3000/movies

The following response will be displayed -

[{"id":101,"name":"Fight Club","year":1999,"rating":8.1},
{"id":102,"name":"Inception","year":2010,"rating":8.7},
{"id":103,"name":"The Dark Knight","year":2008,"rating":9},
{"id":104,"name":"12 Angry Men","year":1957,"rating":8.9}]

We have a route to all the movies. Let's now create a route to get a specific movie by its id.

router.get('/:id([0-9]{3,})', function(req, res){
   var currMovie = movies.filter(function(movie){
      if(movie.id == req.params.id){
         return true;
      }
   });
   if(currMovie.length == 1){
      res.json(currMovie[0])
   } else {
      res.status(404);//Set status to 404 as movie was not found
      res.json({message: "Not Found"});
   }
});

This'll get us the movie according to the id that we provided. To check the output, use the following command in your terminal -

curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET 
localhost:3000/movies/101

You will get the following response -

{"id":101,"name":"Fight Club","year":1999,"rating":8.1}

If you visit an invalid route, it will produce a cannot GET error whereas if you visit a valid route with an id that doesn't exist, it is going to produce a 404 error.

We are through with the GET route, let's now move on to the POST route.


POST route

Use the following route to handle the POST data -

router.post('/', function(req, res){
   //Check if all fields are provided and are valid:
   if(!req.body.name ||
      !req.body.year.toString().match(/^[0-9]{4}$/g) ||
      !req.body.rating.toString().match(/^[0-9]\.[0-9]$/g)){
      
      res.status(400);
      res.json({message: "Bad Request"});
   } else {
      var newId = movies[movies.length-1].id+1;
      movies.push({
         id: newId,
         name: req.body.name,
         year: req.body.year,
         rating: req.body.rating
      });
      res.json({message: "New movie created.", location: "/movies/" + newId});
   }
});

This'll create a new movie and store it in the movies variable. To check this route, enter the following code in your terminal -

curl -X POST --data "name = Toy%20story&year = 1995&rating = 8.5" http://localhost:3000/movies

The following response will be displayed -

{"message":"New movie created.","location":"/movies/105"}

Now to test if this was added to the movies object, run the GET request for /movies/105 again. The following response is going to be displayed -

{"id":105,"name":"Toy story","year":"1995","rating":"8.5"}

Let us move on to create the PUT route.

PUT route

The PUT route is somewhat the same as the POST route. We'll be specifying the id for the object that'll be updated/created. Create the route in the following way.

router.put('/:id', function(req, res){
   //Check if all fields are provided and are valid:
   if(!req.body.name ||
      !req.body.year.toString().match(/^[0-9]{4}$/g) ||
      !req.body.rating.toString().match(/^[0-9]\.[0-9]$/g) ||
      !req.params.id.toString().match(/^[0-9]{3,}$/g)){
      
      res.status(400);
      res.json({message: "Bad Request"});
   } else {
      //Gets us the index of movie with given id.
      var updateIndex = movies.map(function(movie){
         return movie.id;
      }).indexOf(parseInt(req.params.id));
      
      if(updateIndex === -1){
         //Movie not found, create new
         movies.push({
            id: req.params.id,
            name: req.body.name,
            year: req.body.year,
            rating: req.body.rating
         });
         res.json({message: "New movie created.", location: "/movies/" + req.params.id});
      } else {
         //Update existing movie
         movies[updateIndex] = {
            id: req.params.id,
            name: req.body.name,
            year: req.body.year,
            rating: req.body.rating
         };
         res.json({message: "Movie id " + req.params.id + " updated.", 
            location: "/movies/" + req.params.id});
      }
   }
});

The route will execute the function specified in the above table. It'll update the object with new details if it exists. If it doesn't exist, it is going to create a new object. To check this route, use the following curl command. This updates an existing movie. To create a new movie, just change the id to a non-existing id.

curl -X PUT --data "name = Toy%20story&year = 1995&rating = 8.5" 
http://localhost:3000/movies/101

The following response will be displayed -

{"message":"Movie id 101 updated.","location":"/movies/101"}

Let us move on to create the DELETE route.


DELETE route

Make use of the following code to create a delete route -

router.delete('/:id', function(req, res){
   var removeIndex = movies.map(function(movie){
      return movie.id;
   }).indexOf(req.params.id); //Gets us the index of movie with given id.
   
   if(removeIndex === -1){
      res.json({message: "Not found"});
   } else {
      movies.splice(removeIndex, 1);
      res.send({message: "Movie id " + req.params.id + " removed."});
   }
});

Check the route the same way we checked the other routes. On successful deletion(for example id 105), you will get the following output -

{message: "Movie id 105 removed."}

Finally, our movies.js file will look like the following.

var express = require('express');
var router = express.Router();
var movies = [
   {id: 101, name: "Fight Club", year: 1999, rating: 8.1},
   {id: 102, name: "Inception", year: 2010, rating: 8.7},
   {id: 103, name: "The Dark Knight", year: 2008, rating: 9},
   {id: 104, name: "12 Angry Men", year: 1957, rating: 8.9}
];
router.get('/:id([0-9]{3,})', function(req, res){
   var currMovie = movies.filter(function(movie){
      if(movie.id == req.params.id){
         return true;
      }
   });
   
   if(currMovie.length == 1){
      res.json(currMovie[0])
   } else {
      res.status(404);  //Set status to 404 as movie was not found
      res.json({message: "Not Found"});
   }
});
router.post('/', function(req, res){
   //Check if all fields are provided and are valid:
   if(!req.body.name ||
      !req.body.year.toString().match(/^[0-9]{4}$/g) ||
      !req.body.rating.toString().match(/^[0-9]\.[0-9]$/g)){
      res.status(400);
      res.json({message: "Bad Request"});
   } else {
      var newId = movies[movies.length-1].id+1;
      movies.push({
         id: newId,
         name: req.body.name,
         year: req.body.year,
         rating: req.body.rating
      });
      res.json({message: "New movie created.", location: "/movies/" + newId});
   }
});

router.put('/:id', function(req, res) {
   //Check if all fields are provided and are valid:
   if(!req.body.name ||
      !req.body.year.toString().match(/^[0-9]{4}$/g) ||
      !req.body.rating.toString().match(/^[0-9]\.[0-9]$/g) ||
      !req.params.id.toString().match(/^[0-9]{3,}$/g)){
      res.status(400);
      res.json({message: "Bad Request"});
   } else {
      //Gets us the index of movie with given id.
      var updateIndex = movies.map(function(movie){
         return movie.id;
      }).indexOf(parseInt(req.params.id));
      
      if(updateIndex === -1){
         //Movie not found, create new
         movies.push({
            id: req.params.id,
            name: req.body.name,
            year: req.body.year,
            rating: req.body.rating
         });
         res.json({
            message: "New movie created.", location: "/movies/" + req.params.id});
      } else {
         //Update existing movie
         movies[updateIndex] = {
            id: req.params.id,
            name: req.body.name,
            year: req.body.year,
            rating: req.body.rating
         };
         res.json({message: "Movie id " + req.params.id + " updated.",
            location: "/movies/" + req.params.id});
      }
   }
});

router.delete('/:id', function(req, res){
   var removeIndex = movies.map(function(movie){
      return movie.id;
   }).indexOf(req.params.id); //Gets us the index of movie with given id.
   
   if(removeIndex === -1){
      res.json({message: "Not found"});
   } else {
      movies.splice(removeIndex, 1);
      res.send({message: "Movie id " + req.params.id + " removed."});
   }
});
module.exports = router;

This completes our REST API. Now you can create much more complex applications via this simple architectural style and Express.


Alright guys! This is where we are going to be rounding up for this tutorial. In our next tutorial guide, we are going to be discussing about ExpressJS Scaffolding.

Feel free to ask your questions where necessary and we will attend to them as soon as possible. If this tutorial was helpful to you, you can use the share button to share this tutorial.

Follow us on our various social media platforms to stay updated with our latest tutorials. You can also subscribe to our newsletter in order to get our tutorials delivered directly to your emails.

Thanks for reading and bye for now.

Post a Comment

Hello dear readers! Please kindly try your best to make sure your comments comply with our comment policy guidelines. You can visit our comment policy page to view these guidelines which are clearly stated. Thank you.
© 2023 ‧ WebDesignTutorialz. All rights reserved. Developed by Jago Desain