How create a REST API with Node.js and Express

This post will show you how you can quickly build a simple REST API with JavaScript, Node.js and Express. Why these technologies instead of other widely used like WCF of ASP.NET Web API? My goal wasn’t to build a production ready API. It’s was just to mock a real REST service thus the reason why I started to use these tools is the simplicity and rapidity with which I could have something working.

Node.js and Express installation

  1. The first thing you have to do is to install Node.js if it’s not already. Just download it from the website (see here), click, click, next and it’s completed!
  2. Open the Node.js command prompt, go in the directory in which you want to create the server and install Express (which is the middle ware we use to create the web server):
    $> npm install express
    

That’s it. It’s time to create our API.

The Todo List API

The example I took is a basic Todo List. A Task is described by a name, a description, a due date, a status and a unique identifier. The API uses JSON for data transmission and here is its functional description:

  • GET /tasks/ : return the tasks list
  • GET /tasks/:id : return the task identified by the given :id
  • POST /tasks/ : create a new task corresponding to the JSON object given in the body request
  • PUT /tasks/:id : update the task with values of the JSON object given in the body request
  • DELETE /tasks/:id : delete the task with the given id

These methods should return:

  • an HTTP 200 status code if they are invoked by other HTTP verbs than GET and the operation is successful;
  • an HTTP 404 error code if the task we try to access doesn’t exist.

Implementation

Data

The purpose of this post is to focus on how to create a Web API. Thus I deliberately simplified as many as possible the data persistence layer. In the given example, tasks are stored in memory: in a Javascript Array. I just created a simple class ‘TaskRepository’ that creates a simple abstraction of the Javascript array. Here is its public interface:

function TaskRepository() {}
/**
 * Find a task by id
 * Param: id of the task to find
 * Returns: the task corresponding to the specified id
 */
TaskRepository.prototype.find = function (id) {}
/**
 * Find the index of a task
 * Param: id of the task to find
 * Returns: the index of the task identified by id
 */
TaskRepository.prototype.findIndex = function (id) {}
/**
 * Retrieve all tasks
 * Returns: array of tasks
 */
TaskRepository.prototype.findAll = function () {
    return this.tasks;
}
/**
 * Save a task (create or update)
 * Param: task the task to save
 */
TaskRepository.prototype.save = function (task) {}
/**
 * Remove a task
 * Param: id the of the task to remove
 */
TaskRepository.prototype.remove = function (id) {}

Create an Express Server

To create an instance of an express server and to configure it to parse JSON objects contained in request body just write the following snippet:

var express = require('express');
var app = express();
app.configure(function() {
    app.use(express.bodyParser()); // used to parse JSON object given in the request body
});

Get the task list

Let’s configure the router to return all tasks when requests are made with an HTTP GET on ‘/tasks’ url :

/**
 * HTTP GET /tasks
 * Returns: the list of tasks in JSON format
 */
app.get('/tasks', function (request, response) {
    response.json({tasks: taskRepository.findAll()});
});

You can find further information about application routing here

Get a task

You can retrieve a specific task by making a HTTP GET request on the following URL: ‘/tasks/:id’ with :id equals to the taskId you want to retrieve. If no task is found the return is a HTTP 404 status code.

/**
 * HTTP GET /tasks/:id
 * Param: :id is the unique identifier of the task you want to retrieve
 * Returns: the task with the specified :id in a JSON format
 * Error: 404 HTTP code if the task doesn't exists
 */
app.get('/tasks/:id', function (request, response) {
    var taskId = request.params.id;
    try {
        response.json(taskRepository.find(taskId));
    } catch (exeception) {
        response.send(404);
    }
    
});

Create a task

To create a task you have to execute a HTTP POST on ‘/tasks’ with a serialized JSON corresponding to the task you want to create in the request body.

/**
 * HTTP POST /tasks/
 * Body Param: the JSON task you want to create
 * Returns: 200 HTTP code
 */
app.post('/tasks', function (request, response) {
    var task = request.body;
    taskRepository.save({
        title: task.title || 'Default title',
        description: task.description || 'Default description',
        dueDate: task.dueDate,
        status: task.status || 'not completed'
    });
    response.send(200);
});

Update a task

/**
 * HTTP PUT /tasks/
 * Param: :id the unique identifier of the task you want to update
 * Body Param: the JSON task you want to update
 * Returns: 200 HTTP code
 * Error: 404 HTTP code if the task doesn't exists
 */
app.put('/tasks/:id', function (request, response) {
    var task = request.body;
    var taskId = request.params.id;
    try {
        var persistedTask = taskRepository.find(taskId);
        taskRepository.save({
            taskId: persistedTask.taskId,
            title: task.title || persistedTask.title,
            description: task.description || persistedTask.description,
            dueDate: task.dueDate || persistedTask.dueDate,
            status: task.status || persistedTask.status
        });
        response.send(200);
    } catch (exception) {
        response.send(404);
    }
});

Delete a task

/**
 * HTTP PUT /tasks/
 * Param: :id the unique identifier of the task you want to update
 * Body Param: the JSON task you want to update
 * Returns: 200 HTTP code
 * Error: 404 HTTP code if the task doesn't exists
 */
app.delete('/tasks/:id', function (request, response) {
    try {
        taskRepository.remove(request.params.id);
        response.send(200);
    } catch (exeception) {
        response.send(404);
    }
});

Start the Express server

app.listen(8080); //to port on which the express server listen

The result

Here is the final result: https://gist.github.com/ixzo/4750663

Tests

Now it’s time to test our API. In your Node.js command prompt launch the server:

$> node rest_api.js

At the beginning the task list should be empty:

$ curl -i http://localhost:8080/tasks/
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 17
Date: Sun, 10 Feb 2013 12:37:45 GMT
Connection: keep-alive

{
  "tasks": []
}

Create a task

Let’s insert a new one with default values:

$ curl -i -X POST http://localhost:8080/tasks --data '{}' -H "Content-Type: application/json"
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/plain
Content-Length: 2
Date: Sun, 10 Feb 2013 12:39:13 GMT
Connection: keep-alive

OK

Now the task list should contains one task with id equals to 1:

$ curl -i http://localhost:8080/tasks/
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 146
Date: Sun, 10 Feb 2013 12:40:38 GMT
Connection: keep-alive

{
  "tasks": [
    {
      "taskId": 1,
      "title": "Default title",
      "description": "Default Description",
      "status": "not completed"
    }
  ]
}

$ curl -i http://localhost:8080/tasks/1
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 101
Date: Sun, 10 Feb 2013 12:40:15 GMT
Connection: keep-alive

{
  "taskId": 1,
  "title": "Default title",
  "description": "Default Description",
  "status": "not completed"
}

Update a task

Let’s update the description of the task by setting its value to "blabla" instead of "Default Description":

$ curl -i -X PUT http://localhost:8080/tasks/1 --data '{"description":"blabla"}' -H "Content-Type: application/json"
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/plain
Content-Length: 2
Date: Sun, 10 Feb 2013 12:42:39 GMT
Connection: keep-alive

OK

Let’s retrieve the task to see if the description is correctly updated:

$ curl -i http://localhost:8080/tasks/1
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 101
Date: Sun, 10 Feb 2013 12:40:15 GMT
Connection: keep-alive

{
  "taskId": 1,
  "title": "Default title",
  "description": "blabla",
  "status": "not completed"
}

Perfect!

Delete a task

Now it’s time the test the deletion of tasks:

$ curl -i -X DELETE http://localhost:8080/tasks/1
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/plain
Content-Length: 2
Date: Sun, 10 Feb 2013 12:43:31 GMT
Connection: keep-alive

OK

‘/tasks/1′ should return a 404 not found:

$ curl -i http://localhost:8080/tasks/1
HTTP/1.1 404 Not Found
X-Powered-By: Express
Content-Type: text/plain
Content-Length: 9
Date: Sun, 10 Feb 2013 12:44:18 GMT
Connection: keep-alive

Not Found

The task list should be empty now:

$ curl -i http://localhost:3000/tasks/
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 17
Date: Sun, 10 Feb 2013 12:44:33 GMT
Connection: keep-alive

{
  "tasks": []
}

Conclusion

Through this post I have tried to show you how you can quickly and easily create simple REST API. It’s absolutely possible to add complexity to this example to handle authentication or to support real persistence technologies like MongoDB (NoSQL) or a traditional SQL database. You can take a look to resources for other posts related to the same topic.

Resources

About these ads

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s