Building a Basic Todo List REST API in Node.js with Express

ACT
3,017 views

Open Source Your Knowledge, Become a Contributor

Technology knowledge has to be shared and made accessible for free. Join the movement.

Create Content

Discover Express

"Express provides a thin layer of fundamental web application feature, without obscuring Node.js features that you know and love"

from expressjs.com

Before using Express, it has to be installed in the project using NPM.

NPM - The Node Package Manager

NPM is a tool shipped with Node.js that helps the user to manage packages of Node.js applications.

Here is a quick (non-exhaustive) recap of some of the main commands:

For more information, please see the official documentation

A quick word about packages

A package is a file or directory that is described by a package.json. This can happen in a bunch of different ways!

A package is any of the following:

a) a folder containing a program described by a package.json file
b) a gzipped tarball containing (a)
c) a url that resolves to (b)
d) a <name>@<version> that is published on the registry with (c)
e) a <name>@<tag> that points to (d)
f) a <name> that has a latest tag satisfying (e)
g) a git url that, when cloned, results in (a).

Noting all these package possibilities, it follows that even if you never publish your package to the public registry, you can still get a lot of benefits of using npm:

from https://docs.npmjs.com/how-npm-works/packages

Install Express

Now, it's time for you to initialize the project and then to install express package in the Node.js application.

Exercise: Install the Express Package
Project Structure
 /
  |
  | - app.js
  |
  | - package.json

Please find below the content of the package.json file:

{
  "name": "NodeTodoList",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.15.3"
  }
}

The generated package.json contains as dependency the 'express' module in version "^4.15.3". The ^ is called a caret range. It says that express will be installed with a version that is compatible with 4.15.3

More Information on Dependencies Versions in Node.js

Dependencies are specified in a simple object that maps a package name to a version range. The version range is a string which has one or more space-separated descriptors. Dependencies can also be identified with a tarball or git URL.

See semver for more details about specifying version ranges.

version Must match version exactly

  • >version Must be greater than version
  • >=version etc
  • <version
  • <=version
  • ~version "Approximately equivalent to version" See semver
  • ^version "Compatible with version" See semver
  • 1.2.x 1.2.0, 1.2.1, etc., but not 1.3.0
  • http://... See 'URLs as Dependencies' below
  • ***** Matches any version
  • "" (just an empty string) Same as *
  • version1 - version2 Same as >=version1 <=version2.
  • range1 || range2 Passes if either range1 or range2 are satisfied.
  • git... use a git url as dependency
  • ...

from https://docs.npmjs.com/files/package.json#dependencies

Hello World with Express

One of the key features of Express is that it gives you an easy way to route the request to the right handler function.

Using require('express') gives you a reference to a function that will create an Express application.

const express = require('express')
var app = express();

Now that we have create a new Express application, we can handle HTTP requests with:

app.METHOD(PATH, HANDLER)

Where:

  • app is an instance of express.
  • METHOD is an HTTP request method, in lowercase.
  • PATH is a path on the server.
  • HANDLER is the function executed when the route is matched.

Let's try it to create an handler that will treat a GET request on the '/' path.

GET Method with Express
1
2
3
4
5
6
7
8
9
const express = require('express');
const port = 9000;
const app = express();
var todos = ['buy the milk', 'rent a car', 'feed the cat'];
app.get('/', (request, response) => response.status(200).json(todos));
app.listen(port);
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Here are some informations about the commands used above:

Building REST application

Express can help us to write a RESTfull API for our TodoList application:

  • GET / retrieve the list of tasks
  • POST / create a new task
  • PUT /:id update the task of id id
  • DELETE /:id

POST

To consume the message body of a request, there is an important subtlety to take into account: it's a stream.

When receiving a POST or PUT request, the request body might be important to your application. Getting at the body data is a little more involved than accessing request headers. The request object that's passed in to a handler implements the ReadableStream interface. This stream can be listened to or piped elsewhere just like any other stream. We can grab the data right out of the stream by listening to the stream's 'data' and 'end' events.

from https://nodejs.org/en/docs/guides/anatomy-of-an-http-transaction/

To consume all the chunks of the body, we have thus to listen for the 'data' event and retrieve each part of data. The 'end' event means that the entire body has been consumed.

DRY: use the parser-body module

Parsing a message body is such a common operation that there is already a middleware for that named body-parser:

Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. The next middleware function is commonly denoted by a variable named next.

Middleware functions can perform the following tasks:

  • Execute any code.
  • Make changes to the request and the response objects.
  • End the request-response cycle.
  • Call the next middleware function in the stack.

from http://expressjs.com/en/guide/using-middleware.html

var bodyParser = require('body-parser');
...
app.use(bodyParser.urlencoded({'extended':'true'}));            // parse application/x-www-form-urlencoded
app.use(bodyParser.json());                                     // parse application/json

Now that we can handle body parsing, let's move on completing our RESTful api.

Exercise: Complete POST method
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const express = require('express');
const bodyParser = require('body-parser');
const port = 9000;
const app = express();
var todos = [{id:1, title:'buy the milk'}, {id:2, title:'rent a car'}, {id:3, title:'feed the cat'}];
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
app.get('/', (request, response) => response.status(200).json(todos));
app.post('/', (request, response) => {
var newTodo = request.???TODO???
newTodo.id = todos.length +1;
todos.push(newTodo);
response.status(201).json(newTodo);
});
app.listen(port);
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Now that we have started to build a REST API, let's move on how to use parameters.

Open Source Your Knowledge: become a Contributor and help others learn. Create New Content