How to use Node.js, Express.js and Multer Restful API for Image Uploader?

Creating a RESTful Web API with Node.js and Express.js from scratch

Creating a RESTful Web API with Node.js and Express.js from scratch

In this article, I’ll show you step by step how to create a RESTful Web API with Node.js and Express.js by building a simple and useful Todo API. This article assumes you have basic javascript knowledge and terminal using capabilities.

In this article, I’ll show you step by step how to create a RESTful Web API with Node.js and Express.js by building a simple and useful Todo API. This article assumes you have basic javascript knowledge and terminal using capabilities.

You can also build a Web API in Node.js by using another framework except Express.js but Express.js is one of the most popular web framework for Node.js.

You can found the final source code of this Web API in this github repository.

Let’s start to create our mentioned Web API.

Before start

If you have never used Node.js or npm package manager you should install them.

To check whether the Node.js is already installed on your computer, open your terminal and run node -v command. If you see your Node.js version it's installed. Otherwise go to below link.

Click here to download and install Node.js (You can choose LTS version)

And if you don’t have any IDE or text editor for writing javascript I advice you Visual Studio Code.

Click here to download VS Code (Optional)

About express-generator

In fact we could use <a href="https://expressjs.com/en/starter/generator.html" target="_blank">express-generator</a> tool which designed to creating an Express Web API quickly but I want to create this API from scratch because of that tool puts some extra files and folder structures that we don't need them now. But you can use this useful tool next time on creating new Web API. I won't use it now due to keep article simple.

Creating Project

Go to your workspace root folder and create a new folder there named "todo-api".

Then create "package.json" and "server.js" files into "todo-api" folder like below.

package.json

{
    "name": "todo-api",
    "version": "1.0.0",
    "scripts": {
        "start": "node server.js"
    },
    "dependencies": {
        "express": "^4.16.4"
    }
}

server.js

const http = require('http');
const express = require('express');
const app = express();
app.use(express.json());
app.use('/', function(req, res) {
    res.send('todo api works');
});
const server = http.createServer(app);
const port = 3000;
server.listen(port);
console.debug('Server listening on port ' + port);

After creating above files open your terminal in the "todo-api" folder and run npm installcommand.

This command will be install your project dependencies which pointed at the "package.json" file.

After finished package download process, downloaded dependency files will be installed into"node_modules" folder at the root of the "todo-api" folder.

After finished package installing then run npm start to start our Web API.

Now our Web API listening. To see result open your web browser then write localhost:3000 to address bar and press enter.

As result you’ll see our request handler response in your browser: “todo api works”.

This is a dead simple Express.js Web API. And it needs the some development. For example we need to an api endpoint to get todo items. So let’s add a new API endpoint for this.

Create a new folder named "routes" in the root of the "todo-api" folder.

Then create a "items.js" file inside of "routes" folder and put following codes inside it.

Your final folder structure should be like below;

/todo-api
/node_modules
/routes
    items.js
package.json
server.js

items.js

const express = require('express');
const router = express.Router();
const data = [
    {id: 1, title: 'Finalize project', order: 1, completed: false, createdOn: new Date()},
    {id: 2, title: 'Book ticket to London', order: 2, completed: false, createdOn: new Date()},
    {id: 3, title: 'Finish last article', order: 3, completed: false, createdOn: new Date()},
    {id: 4, title: 'Get a new t-shirt', order: 4, completed: false, createdOn: new Date()},
    {id: 5, title: 'Create dinner reservation', order: 5, completed: false, createdOn: new Date()},
];
router.get('/', function (req, res) {
    res.status(200).json(data);
});
router.get('/:id', function (req, res) {
    let found = data.find(function (item) {
        return item.id === parseInt(req.params.id);
    });
    if (found) {
        res.status(200).json(found);
    } else {
        res.sendStatus(404);
    }
});
module.exports = router;

Initial code of "items.js" file contains two endpoints. First one gets all todo items and second one gets one item which matches given id parameter.

Before testing items routes we should register it in the "server.js" file.

Modify "server.js" file like below to register new item routes.

server.js

const http = require('http');
const express = require('express');
const itemsRouter = require('./routes/items');
const app = express();
app.use(express.json());
app.use('/items', itemsRouter);
app.use('/', function(req, res) {
    res.send('todo api works');
});
const server = http.createServer(app);
const port = 3000;
server.listen(port);
console.debug('Server listening on port ' + port);

Now run npm start to start our Web API.

Then open your web browser and write localhost:3000/items to address bar and press enter.

You’ll see todo items json array in the response body.

And write localhost:3000/items/3 to address bar and press enter.

You’ll see the todo item which has id 3 in the response body.

But not finished up yet.

CRUD Operations and HTTP methods

I think we’ll need CRUD operations to Create, Read, Update and Delete todo items.

We have already two endpoints for getting items. So we need Create, Update and Delete endpoints.

Let’s add also these endpoints into the items.js file.

Our final "items.js" file and endpoints should be like below.

const express = require('express');
const router = express.Router();

const data = [
  {id: 1, title: 'Finalize project',          order: 1, completed: false, createdOn: new Date()},
  {id: 2, title: 'Book ticket to London',     order: 2, completed: false, createdOn: new Date()},
  {id: 3, title: 'Finish last article',       order: 3, completed: false, createdOn: new Date()},
  {id: 4, title: 'Get a new t-shirt',         order: 4, completed: false, createdOn: new Date()},
  {id: 5, title: 'Create dinner reservation', order: 5, completed: false, createdOn: new Date()},
];

router.get('/', function (req, res) {
  res.status(200).json(data);
});

router.get('/:id', function (req, res) {
  let found = data.find(function (item) {
    return item.id === parseInt(req.params.id);
  });

  if (found) {
    res.status(200).json(found);
  } else {
    res.sendStatus(404);
  }
});

router.post('/', function (req, res) {
  let itemIds = data.map(item => item.id);
  let orderNums = data.map(item => item.order);

  let newId = itemIds.length > 0 ? Math.max.apply(Math, itemIds) + 1 : 1;
  let newOrderNum = orderNums.length > 0 ? Math.max.apply(Math, orderNums) + 1 : 1;

  let newItem = {
    id: newId,
    title: req.body.title,
    order: newOrderNum,
    completed: false,
    createdOn: new Date()
  };

  data.push(newItem);

  res.status(201).json(newItem);
});

router.put('/:id', function (req, res) {
  let found = data.find(function (item) {
    return item.id === parseInt(req.params.id);
  });

  if (found) {
    let updated = {
      id: found.id,
      title: req.body.title,
      order: req.body.order,
      completed: req.body.completed
    };

    let targetIndex = data.indexOf(found);

    data.splice(targetIndex, 1, updated);

    res.sendStatus(204);
  } else {
    res.sendStatus(404);
  }
});

router.delete('/:id', function (req, res) {
  let found = data.find(function (item) {
    return item.id === parseInt(req.params.id);
  });

  if (found) {
    let targetIndex = data.indexOf(found);

    data.splice(targetIndex, 1);
  }

  res.sendStatus(204);
});

module.exports = router;

Short Explanation

I wanna explain shortly some points of our last codes.

First of all you must have noticed that our api works on a static data and keeps it on memory. All of our GET, POST, PUT and DELETE http methods just manipulate a json array. The purpose of this is to keep article simple and draw attention to the Web API structure.

Due to this situation our POST method has some extra logic such as calculating next item ids and order numbers.

So you can modify logic and data structures in these http methods to use a database or whatever you want.

Testing API with Postman

We have tested the GET methods of our Web API in our web browser and seen responses. But we can’t test directly POST, PUT and DELETE http methods in web browser.

If you want to test also other http methods you should use Postman or another http utility.

Now I’ll show you how to test the Web API with Postman

Before we start click here and install Postman.

When you first launch Postman after installing you’ll see start window. Close this start window by clicking close button on top right corner. Then you must see following screen.

An empty Postman request

Sending GET Request

Before sending a request to API we should start it by running npm startcommand as we do before.

After start the Web API and seeing “Server listening on…” message write localhost:3000/itemsto address bar as seen below and click Send button. You'll see todo items array as API response like below.

Sending a GET request with Postman

You can try similarly by giving an item id in request url like this localhost:3000/items/3

Sending POST Request

To sending a POST request and create a new todo item write localhost:3000/items to address bar and change HTTP verb to POST by clicking arrow at front of the address bar as seen below.

Sending a POST request with Postman

Before sending the POST request you should add request data to body of the request by clicking body tab and selecting raw and JSON as seen below.

Attaching a JSON body to POST request in Postman

Now click Send button to send POST request to the Web API. Then you must get “201 Created” http response code and seeing created item in the response body.

To see the last status of todo items send a get request to localhost:3000/itemsaddress. You must see newly created item at the end of the list.

Sending PUT Request

Sending PUT request is very similar to sending POST request.

The most obvious difference is request url should be pointed specific item like this localhost:3000/items/3

And you should choose PUT as http verb instead of POST and send all of the required data in the request body unlike POST.

For example you could send a JSON body in the PUT request as below.

An example JSON body for PUT request

{
    "title": "New title of todo item",
    "order": 3,
    "completed": false
}

When you click Send button you must get “204 No Content” http response code. You can check item you updated by sending a get request.

Sending DELETE Request

To send a DELETE request, change the request url to address a specific item id like this localhost:3000/items/3

And select DELETE as http verb and click Send button.

You must get “204 No Content” http response code as result of the DELETE operation.

Send a get request and see the last status of list.

About the DELETE Http Request

I want to say a few words about DELETE http request. You must have noticed something in our delete code. DELETE request returns “204 No Content” every situation.

Http DELETE requests are idempotent. So what that mean? If you delete a resource on server by sending DELETE request, it’s removed from the collection. And every next DELETE request on the same resource won’t change outcome. So you won’t get “404 Not Found” in the second request. Each request returns same response whether succeed or not. That’s mean idempotent operation.

Conclusion

Finally we’ve tested all http methods of our Web API.

As you can see, it works just fine.

Thanks for reading ❤

If you liked this post, share it with all of your programming buddies!

How to Build a RESTful API using Node and Express 🗽

How to Build a RESTful API using Node and Express 🗽

🗽 A REST API is an integral component of a web application. In this tutorial, we’ll be learning how to build a Rest API in Node.js and Express.js by building a simple todo app API 🗽

🗽 A REST API is an integral component of a web application. In this tutorial, we’ll be learning how to build a Rest API in Node.js and Express.js by building a simple todo app API 🗽

This tutorial assumes an intermediate knowledge of javascript and experience working on the command line. The source code for the final project can be found here.

Getting Started

To get started create a new folder and call it todo.

$ mkdir todo
$ cd todo

In your todo folder create a new file called app.js

$ touch app.js

The next thing for us to do is to install Node. you can install node here. After node has been installed then we’ll install express with npm. Node comes with npm so we won’t need to install npm.

Initialize The App

Navigate on the command line to the root of your app and run.

npm init 

Click the return key repeatedly for every questions asked of you on the command line.

This will create a package.json file for you.

Install Dependencies And Set Up Babel

$ npm install express —-save

We’ll also need to install babel because we’ll be writing ES6 syntax, **Babel **helps to turn our codes from **ES6 **to ES5. why do we have to compile our code down to **ES5 **? well, there are some ES6 features that our browsers and node are yet to understand, and older browsers do not understand ES6 codes, so we use babel to compile our code to *ES5 *so that both old browsers and new browsers can understand. Our Purpose for using babel here is so that *ES6 features *that are not part of node yet can be compiled down to *ES5 *that node understands.

$ npm install babel-cli --save

We’ll also be installing babel-preset-es2015, the presets contains a set of plugins, these plugins are for ES6 features, by installing and configuring babel-preset-es2015 we tell babel to convert any ES6 feature we use that are contained in the preset to their ES5 equivalent.

$ npm install babel-preset-es2015 --save

Now we need to create a .babelrc file, in the babelrc file, we’ll set babel to use the es2015 preset we installed as its preset when compiling to ES5.

At the root of our app, we’ll create a .babelrc file.

$ touch .babelrc

In the babelrc file type the following to set up your preset.

{  
   "presets": ["es2015"]
}

This tells babel to use es2015 as its preset, note that ES2015 is another name for ES6.

Create A Dummy Database

The last thing we’ll need to do before we get started creating our Apis is to create a dummy **database **we’ll use.

Create a folder and name it db.

$ mkdir db

In the folder create a file and call it db.js

$ cd db
$ touch db.js

In db.js create a javascript object to create a dummy database

const todos =  [
    {
      id: 1,
      title: "lunch",
      description: "Go for lunc by 2pm"
    }
];

export default todos;

Setup The App And Create Our First Endpoint

Now let’s get started creating our todo app

import express from 'express';
import db from './db/db';
// Set up the express app
const app = express();
// get all todos
app.get('/api/v1/todos', (req, res) => {
  res.status(200).send({
    success: 'true',
    message: 'todos retrieved successfully',
    todos: db
  })
});
const PORT = 5000;

app.listen(PORT, () => {
  console.log(`server running on port ${PORT}`)
});


We imported express which we installed at the beginning of the course, app.get makes a get request to the server with the route/endpoint provided as the first parameter, the endpoint is meant to return all the todos in the database. The second parameter is a function that runs every time we hit that endpoint. the function takes two parameters which are req and res. The req object contains information about our request and the response object contains information about the response and methods we can use to send information back to the client.

**res.status(200) **is used to send back the status of the request, 200 means ok and it indicates a successful request. Status codes are ways for client like web app or mobile app to check wether things went wrong or not.if we get a 404(which means Not Found)we don’t need to check the payload because we know that nothing is coming that we are really interested in. If 200 comes back we can check the payload because we know we are expecting something. You can learn more about HTTP status codes here.

res.send() is used to send back a response to the client, the resource passed into the send as a parameter is what gets sent back to the client. in this case, we send back an object which contains some information, the todos property of the object contains the data we imported at the top of app.js from our dummy database.

**app.listen **creates a web server for us, it takes two parameters, the first parameter is the port we want our application to listen on t, whatever port we provide, in our case, 5000 will be the port our server will be running on in our system. the second parameter is optional, it is a callback function of what should happen when the server gets created, in our case we are logging a message to the console. when the sever gets created then we can access our endpoint ’/api/v1/todos’ from there. the server will run on a port 5000 on a localhost on our machine. so we’ll have our localhost:port/api route. The endpoint we created will be accessed like this localhost:5000/api/v1/todos.

Now to run this code let’s go to the command line.we’ll normally run our node app from the command line like this.

$ node app.js 

But this will throw an error because our code is in ES6, to successfully run our code we’ll have to run it with babel-node which will compile it to ES5. babel-node comes with the babel-cli which we installed at the beginning of the course.

$ node_modules/.bin/babel-node app.js

Now we can go to postman and test our endpoint, postman is an application we use to test our endpoints. you can download postman here.

To test the endpoint we’ll go to localhost:5000/api/v1/todos.

Take a look at the ‘GET’ before localhost:5000/api/v1/todos, remember our endpoint is a get request, that is why we set that dropdown to ‘GET, if our endpoint was a post request i.e we had app.post then we would have set that to POST.

Getting our server started by running this every single time is stressful, to simplify this process we are going to do two things, first, we are going to install nodemon, Secondly, we’ll create a script in our package,json to start our server.

Let’s install nodemon, run the following in your terminal.

$ npm install nodemon --save-dev

Nodemon watches your app for file changes and restarts the server every time a file changes in your app. This eases your work because you won’t have to start and restart the server manually every time you change files in your app

Lets create the script, in your package.json, inside the script part include this

"start": "node_modules/.bin/nodemon app.js --exec babel-node --"

You know what babel-node does.

Your package.json scripts should look like this

{
"name": "todo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon app.js --exec babel-node --"
},
"author": "",
"license": "ISC",
"dependencies": {
"babel-cli": "^6.26.0",
"babel-preset-es2015": "^6.24.1"
"express": "^4.16.3"
}
}

Now every time we want to start our app we just run the following script on the terminal.

npm run start

This will run the start script in our package.json file.

Let’s create an endpoint to add todos, but before then let’s install a package called body-parser, body-parser parses incoming request bodies in a middleware before your handlers, available under the req.bodyproperty.

When you are sending data to the server, the data could be coming from a form or it could be a json, what body parser does is that it parses this data that is coming from the client in an object called req.body, so for example if I have a JSON data coming from the client to the server.

{
   "name": "Ola",
   "school": "unilag"
}

What body parser does is that it parses this JSON data and makes it available under the req.body as a property. remember req is the first property we provide for our callback when we make an API request, and remember I said req contains information about the request that is coming from the client, so body parser makes the data coming from the form or any *JSON *data coming from the client available as a property under the req.body, so we can access the *JSON *data from req.body as.

req.body.name
req.body.school

So lets install body-parser

$ npm install body-parser --save

Now lets import it in app.js

import bodyParser from 'body-parser';

Now we will configure body parser for our application like this.

const app = express();
// Parse incoming requests data
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

Create Todo App

Now lets get to creating an endpoint to create a todo.

app.post('/api/v1/todos', (req, res) => {
  if(!req.body.title) {
    return res.status(400).send({
      success: 'false',
      message: 'title is required'
    });
  } else if(!req.body.description) {
    return res.status(400).send({
      success: 'false',
      message: 'description is required'
    });
  }
 const todo = {
   id: db.length + 1,
   title: req.body.title,
   description: req.body.description
 }
 db.push(todo);
 return res.status(201).send({
   success: 'true',
   message: 'todo added successfully',
   todo
 })
});

In this endpoint, we are not making a request to the server to get data but rather we are posting data. just like we explained, the data coming in are parsed into req.body as properties, so we have req. body.title, etc.

We create a todo object with the information we got from the client through body-parser and then push it to the dummy db array as a new todo.

Let’s test this out in postman, we would have to pass in some data and send them to the server to test this out, on postman, when you select POST, click on n body before Headers which is before Authorization and pass in your values in the field.

localhost:5000/api/v1/todos, ensure you set the HTTP method in your postman to POST.

Take a look at the ‘POST’ before localhost:5000/api/v1/todos, remember our endpoint is a post request, that is why we set that dropdown to POST.Ensure the radio button x-www-form-urlencoded is checked or use raw where you would pass JSON data like this.

{
"title": "breakfast",
"description": "get breakfast"
}

Get A Single Todo

Now let’s create an endpoint to get a single todo from the database. Type the following:

app.get('/api/v1/todos/:id', (req, res) => {
  const id = parseInt(req.params.id, 10);
  db.map((todo) => {
    if (todo.id === id) {
      return res.status(200).send({
        success: 'true',
        message: 'todo retrieved successfully',
        todo,
      });
    } 
});
 return res.status(404).send({
   success: 'false',
   message: 'todo does not exist',
  });
});

Just, as usual, this endpoint takes two parameters, the route and the callback function. the different thing here is that the route in this endpoint has a :id, there are times we want to pass parameters to our endpoints because we will need them in our application, to pass those parameters we use :param.

The endpoint created above is meant to get a single todo, to get a single todo we’ll need a unique way to identify this todo in the database, so if we know the id of the todo we want to get we can then fetch it from the database, so every time we make a request to this endpoint we pass along the id of the todo we want to get, the callback function will then query the database for the todo with that application.

What is going on in the endpoint above is that we pass the id of the todo we want to get as a parameter to route, to get the value of id passed to the route we use req.params.id, req.params is an object that contains all the parameters passed to the routes, we convert the id to an int and then we loop through our dummy database db to find the todo whose id will be equal to the one we got from the URL, the matching todo is then returned as the single todo.

Let’s test this out, fetch the total todos in the database to see what we currently have.

Now let’s add a new todo to the database

Lets fetch all the todos in the database again

Now we have the new todo we just added to the database.

Let’s test our endpoint now, go to localhost:5000/api/v1/todos/:id, replace :id with the id of the todo you want to get. in our case the todo with and id of 2, Set the http method to GET.

Delete Todo

Now let’s create an endpoint to delete todos from the database.

app.delete('/api/v1/todos/:id', (req, res) => {
  const id = parseInt(req.params.id, 10);

  db.map((todo, index) => {
    if (todo.id === id) {
       db.splice(index, 1);
       return res.status(200).send({
         success: 'true',
         message: 'Todo deleted successfuly',
       });
    }
  });


    return res.status(404).send({
      success: 'false',
      message: 'todo not found',
    });

 
});

So what are we doing here? well, basically we are passing the id of the todo we want to delete as a parameter to the route /api/v1/todos/:id. we fetch that id with req.params.id, So for us to delete an item with this id we have to first search for it in the database, we did that by mapping through the db array and check the id of the current todo in the iteration against the id we got from route till we find a match, we then use array method splice() to remove that item from the database. you can learn more about array.splice and how it works here. In the case where we do not find anything we return a message to the user stating ‘todo not found’.

Now lets test this out, first let’s fetch the todos in our database to see what we have.

Now lets add a new todo

let’s fetch all our todos again

As you can see we now have two todos in our database, the previous one that was there initially(we hard coded this in the app) is the todo with an id of 1, and the new one we added is the todo with an id of 2.

Now lets’s remove the todo with an id of 1 by going to the endpoint we just created. Navigate to localhost:5000/api/v1/todos/:id, the id in this case is 1, just replace :id with 1 in the endpoint.

Now let’s fetch all the endpoint to see if we truly deleted the todo.

Now we have only the todo with and id of 2.

Lets try to delete a Todo with an id that does not exist.

We get a message back that the todo is not found.

Update Todo

Now let’s create an endpoint to update todos.

app.put('/api/v1/todos/:id', (req, res) => {
  const id = parseInt(req.params.id, 10);
  let todoFound;
  let itemIndex;
  db.map((todo, index) => {
    if (todo.id === id) {
      todoFound = todo;
      itemIndex = index;
    }
  });

  if (!todoFound) {
    return res.status(404).send({
      success: 'false',
      message: 'todo not found',
    });
  }

  if (!req.body.title) {
    return res.status(400).send({
      success: 'false',
      message: 'title is required',
    });
  } else if (!req.body.description) {
    return res.status(400).send({
      success: 'false',
      message: 'description is required',
    });
  }

  const updatedTodo = {
    id: todoFound.id,
    title: req.body.title || todoFound.title,
    description: req.body.description || todoFound.description,
  };

  db.splice(itemIndex, 1, updatedTodo);

  return res.status(201).send({
    success: 'true',
    message: 'todo added successfully',
    updatedTodo,
  });
});

Just as usual we get the id of the todo we want to update from the URL, we loop through our dummy db to find the todo with that id, if we don’t find the todo then we return a message to the user saying todo not found. If we find the todo then we get new input supplied by the user, the new input is parsed by body parser to the req.body, we get the updated entries from req.body and create an updated todo object with it. We then use db.splice to remove the old todo that match our iteration when we looped through the dummy db and replace it with the updatedTodo that we created.

Let’s test this out.

Let’s get all the todos we have in our database currently, Note that every time your server restarts you lose the entries you have in memory, that’s why we lose todo we added through postman when our server restarts except for the one we hardcoded in the app.

Now lets update the todo with the id of 1.

Now we have come to the end of this tutorial,

Middleware

What is a middleware? from the express doc 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.

Router middleware

From the terminal navigate to root of your app.

$ cd todo

Create a new directory called routes.

$ mkdir routes

in your routes folder create a new file called index.js.

$ cd routes
$ touch index.js

Now in index.js write the following code

import express from 'express';
import db from '../db/db';

const router = express.Router();

We import express and then create a route handler with express.Router()

In your app.js move the code for your endpoint and paste it in index.js inside of the routes folder. instead of app.get, user router.get and do the same for the remaining endpoints.You should have something like this when you are done.

router.get('/api/v1/todos', (req, res) => {
  res.status(200).send({
    success: 'true',
    message: 'todos retrieved successfully',
    todos: db,
  });
});

router.get('/api/v1/todos/:id', (req, res) => {
  const id = parseInt(req.params.id, 10);
  db.map((todo) => {
    if (todo.id === id) {
      return res.status(200).send({
        success: 'true',
        message: 'todo retrieved successfully',
        todo,
      });
    }
  });
  return res.status(404).send({
    success: 'false',
    message: 'todo does not exist',
  });
});

router.post('/api/v1/todos', (req, res) => {
  if (!req.body.title) {
    return res.status(400).send({
      success: 'false',
      message: 'title is required',
    });
  } else if (!req.body.description) {
    return res.status(400).send({
      success: 'false',
      message: 'description is required',
    });
  }
  const todo = {
    id: db.length + 1,
    title: req.body.title,
    description: req.body.description,
  };
  db.push(todo);
  return res.status(201).send({
    success: 'true',
    message: 'todo added successfully',
    todo,
  });
});


router.put('/api/v1/todos/:id', (req, res) => {
  const id = parseInt(req.params.id, 10);
  let todoFound;
  let itemIndex;
  db.map((todo, index) => {
    if (todo.id === id) {
      todoFound = todo;
      itemIndex = index;
    }
  });

  if (!todoFound) {
    return res.status(404).send({
      success: 'false',
      message: 'todo not found',
    });
  }

  if (!req.body.title) {
    return res.status(400).send({
      success: 'false',
      message: 'title is required',
    });
  } else if (!req.body.description) {
    return res.status(400).send({
      success: 'false',
      message: 'description is required',
    });
  }

  const newTodo = {
    id: todoFound.id,
    title: req.body.title || todoFound.title,
    description: req.body.description || todoFound.description,
  };

  db.splice(itemIndex, 1, newTodo);

  return res.status(201).send({
    success: 'true',
    message: 'todo added successfully',
    newTodo,
  });
});

router.delete('/api/v1/todos/:id', (req, res) => {
  const id = parseInt(req.params.id, 10);
  let todoFound;
  let itemIndex;
  db.map((todo, index) => {
    if (todo.id === id) {
      todoFound = todo;
      itemIndex = index;
    }
  });

  if (!todoFound) {
    return res.status(404).send({
      success: 'false',
      message: 'todo not found',
    });
  }
  db.splice(itemIndex, 1);

  return res.status(200).send({
    success: 'true',
    message: 'Todo deleted successfuly',
  });
});

To make use of this routes in our app we need to import it into app.js, to import it into app.js we need to export it from index.js inside of the route folder, let’s do that.

in index.js file, type in the following code to export router

message: 'Todo deleted successfuly',
  });
});
export default router;

Now in app.js, import the router

import router from './routes/index.js';

the newly imported router is a middleware, to make use of middleware in express you use app.use(middleware)

app.use(bodyParser.urlencoded({ extended: false }));
app.use(router);

Now let’s run our code to be sure that we’ve broken nothing.

Refactor The Callback Functions

from the root of your application create a new folder called todosController

$ mkdir todosControllers

in todosControllers folder create a file called todos

$ cd todosControllers
$ touch todos.js

Now inside todos.js we are going to create a class, this class is going to hold all our callback functions as its methods, whenever we need to make use of any of the methods we’ll create an instance of the class and get the method we need. let’s create this class.

/* eslint-disable class-methods-use-this */
import db from '../db/db';

class TodosController {
  getAllTodos(req, res) {
    return res.status(200).send({
      success: 'true',
      message: 'todos retrieved successfully',
      todos: db,
    });
  }

  getTodo(req, res) {
    const id = parseInt(req.params.id, 10);
    db.map((todo) => {
      if (todo.id === id) {
        return res.status(200).send({
          success: 'true',
          message: 'todo retrieved successfully',
          todo,
        });
      }
    });
    return res.status(404).send({
      success: 'false',
      message: 'todo does not exist',
    });
  }

  createTodo(req, res) {
    if (!req.body.title) {
      return res.status(400).send({
        success: 'false',
        message: 'title is required',
      });
    } else if (!req.body.description) {
      return res.status(400).send({
        success: 'false',
        message: 'description is required',
      });
    }
    const todo = {
      id: db.length + 1,
      title: req.body.title,
      description: req.body.description,
    };
    db.push(todo);
    return res.status(201).send({
      success: 'true',
      message: 'todo added successfully',
      todo,
    });
  }

  updateTodo(req, res) {
    const id = parseInt(req.params.id, 10);
    let todoFound;
    let itemIndex;
    db.map((todo, index) => {
      if (todo.id === id) {
        todoFound = todo;
        itemIndex = index;
      }
    });

    if (!todoFound) {
      return res.status(404).send({
        success: 'false',
        message: 'todo not found',
      });
    }

    if (!req.body.title) {
      return res.status(400).send({
        success: 'false',
        message: 'title is required',
      });
    } else if (!req.body.description) {
      return res.status(400).send({
        success: 'false',
        message: 'description is required',
      });
    }

    const newTodo = {
      id: todoFound.id,
      title: req.body.title || todoFound.title,
      description: req.body.description || todoFound.description,
    };

    db.splice(itemIndex, 1, newTodo);

    return res.status(201).send({
      success: 'true',
      message: 'todo added successfully',
      newTodo,
    });
  }

  deleteTodo(req, res) {
    const id = parseInt(req.params.id, 10);
    let todoFound;
    let itemIndex;
    db.map((todo, index) => {
      if (todo.id === id) {
        todoFound = todo;
        itemIndex = index;
      }
    });

    if (!todoFound) {
      return res.status(404).send({
        success: 'false',
        message: 'todo not found',
      });
    }
    db.splice(itemIndex, 1);

    return res.status(200).send({
      success: 'true',
      message: 'Todo deleted successfuly',
    });
  }
}

const todoController = new TodosController();
export default todoController;

To use the methods in this class we created an instance of the class and export it. now in our routes files(routes/index.js) we will import the class instance we just created and use its methods as callbacks instead of the anonymous function we were using before, let’s replace all of this functions with a method that does exactly the same thing they do.

First we import the object, go to index.js in routes folder and do this.

import todoController from '../todosControllers/todos';

Now replace the function with their equivalent method of the todoController object. our index.js file should look like this.

import express from 'express';
import TodoController from '../todosController/todos';

const router = express.Router();

router.get('/api/v1/todos', TodoController.getAllTodos);
router.get('/api/v1/todos/:id', TodoController.getTodo);
router.post('/api/v1/todos', TodoController.createTodo);
router.put('/api/v1/todos/:id', TodoController.updateTodo);
router.delete('/api/v1/todos/:id', TodoController.deleteTodo);

export default router;

Now let’s test our app to see if it still works.

Configure Sequelize

To get started we’ll start by installing some dependencies. First, we'll install```sequelize-cli````, sequelize-cli creates a command line interface for us to run Sequelize related commands in our app.

$ npm install -save sequelize-cli

To configure Sequelize for our project we are going to create a** .sequelizerc** file in the root of our app

$ touch .sequelizerc

inside the file type the following

const path = require('path');

module.exports = {
 "config": path.resolve('./config', 'config.json'),
 "models-path": path.resolve('./models'),
 "migrations-path": path.resolve('./migrations')
};

The sequelizerc file is going to bootstrap our application with the above paths, the config.json file is going to contain the configuration for our application, the models path will contain our application models, migrations will contain the different migrations for our application. the migration files are used to create our app’s table using the models that we create. the models contain the design for our application tables

The next thing to do is to install Sequelize and some other dependencies,

$ npm install --save sequelize pg pg-hstore

pg is a PostgreSQL client for Node.js, pg is responsible for creating our application’s database connection. pg-hstore is a node package for serializing and deserializing JSON data to hstore format. read more about pg-hstore here.

Next run

$ sequelize init

this is going to bootstrap our application with the path specified in .sequelizerc file. After running it you should have a config folder which contains a config.json file, a model folder which contains some configurations for the models and a migration folder.

let’s go through the index.js file in the models folder, some required node modules were imported, the line with config.use_env_variable checks if any environment variable is set, if it is set then we use the settings for that environment variable otherwise we use the alternative settings provided for that environment. the process.env gives access to the node env, but this will not work unless we have a dotenv package installed, this will give us access to the node environment from our application.

Configure dotenv

$ npm install --save dotenv

after installation, require the dotenv file as early as possible in your application. I’ll require mine at the top of index.js file in the models folder

require('dotenv').config()

we required the dotenv module and call the method config on it. the next thing we need to do is to create .env file, this will contain all our node environment variables. At the root of your app create a .env file

$ touch .env

now to set up Postgres for our application we can either use the settings provided in the config.json file, we’ll just replace the required information with the information we Setup when we installed Postgres or we can use an environment variable. in the development section, delete everything there and replace it with this

"development": {
  "use_env_variable": "DATABASE_URL"
},

now our model configuration is going to make use of this environment variable when we are on development. remember we had something like this in our model:

if (config.use_env_variable) {
  var sequelize = new
  Sequelize(process.env[config.use_env_variable], config);
} else {
  var sequelize = new Sequelize(config.database, config.username,
  config.password, config);
}

so we are checking if our config is set, in this case, our config variable is set to development object, this line of code is doing that.

var env       = process.env.NODE_ENV || 'development';
var config    = require(__dirname + '/../config/config.json')[env];

we set the env to development by default, then we required the config.json file and pull out the development environment. so config variable is equal to our development object set in config.json file. so we then check if use_env_variable is set, if it is we use process.env[config.use_env_variable] which translates to process.env['DATABASE_URL'] to get the value set in that environment. but we don’t have DATABASE_URL```` set in our node environment. to do that we will go to our .env``` file and set it, so the .env file is where we set custom node_env we want to have access to in our code. in your .env file type the following:

DATABASE_URL=postgres://username:[email protected]:5432/database_name

If you don’t have a password setup then your configuration should be in this format:

DATABASE_URL=postgres://[email protected]:5432/database_name

so our models will make use of this DATABASE_URL to set up our database, replace username with your Postgres username, mine is postgres, replace password with your password and database_name with the name of your database. so in my case, we’ll have something like this:

DATABASE_URL=postgres://postgres:[email protected]:5432/todo-app

then create your Postgres database from your terminal like this:

$ createdb todoapp

ensure you have Postgres installed otherwise this will not work.

note that anything we set in our .env file is available in our node environment and can be accessed with process.env.whatWeSet in our case process.env.DATABASE_URL````. NODE_ENVis equal to whatever we set it to be. we could set it to development, production or testing, depending on what environment we want to work on. we could set it in the** .env** file also. In our case, if it is not set we just default to development:var env = process.env.NODE_ENV || ‘development’```.

Creating our models

Now that we have our configurations out of the way, the next thing is to create our models, Each todo is going to have todo items, so a todo can have many items under it, so we can then say that the relationship between a todo and the todo item is a one to many relationship. Now to create this relationship we first have to create our models, run the following command to create our models

Todo models

$ node_modules/.bin/sequelize model:create --name Todo --attributes title:string

  • — name refers to the name of the model
  • — attribute refers to the attributes the model should have

this will generate a todo.js file in our model and the todo model should look something like this:

'use strict';
module.exports = (sequelize, DataTypes) => {
  var Todo = sequelize.define('Todo', {
  title: DataTypes.STRING
}, {});
Todo.associate = function(models) {
// associations can be defined here
};
return Todo;
};

A migration file will also be automatically generated in the migration folder and it should look like this:

'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Todos', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
title: {
  type: Sequelize.STRING
},
createdAt: {
  allowNull: false,
  type: Sequelize.DATE
},
updatedAt: {
  allowNull: false,
  type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Todos');
}
};

TodoItem

We’ll do the same thing for todo items, run the following command in your terminal

$ node_modules/.bin/sequelize model:create --name TodoItem --attributes description:string

the todoItem model should look something like this:

'use strict';
module.exports = (sequelize, DataTypes) => {
  var TodoItem = sequelize.define('TodoItem', {
    description: DataTypes.STRING
  }, {});
TodoItem.associate = function(models) {
// associations can be defined here
};
return TodoItem;
};

the migration file

'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('TodoItems', {
id: {
  allowNull: false,
  autoIncrement: true,
  primaryKey: true,
  type: Sequelize.INTEGER
},
description: {
  type: Sequelize.STRING
},
createdAt: {
  allowNull: false,
  type: Sequelize.DATE
},
updatedAt: {
  allowNull: false,
  type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('TodoItems');
}
};

Refactoring

we are going to refactor some part of our code to make use of Es6, change the functions to arrow functions and all vars to const

module.exports = (sequelize, DataTypes) => {
const Todo = sequelize.define('Todo', {
title: {
type: DataTypes.STRING,
allowNull: false,
},
});
Todo.associate = (models) => {
// associations can be defined here
Todo.hasMany(models.TodoItem, {
foreignKey: 'todoId',
});
};
return Todo;
};

in the above code we modified our todo.js file, first we included an extra attribute to the title field allowNull: false what this attribute does is that it made the title field not nullable, meaning that the database is going to throw an error if we attempt to add an empty or null value to the title field, the DataTypes.string means that we only expect a string value in this field, anything other than that the database is going to throw an error

Also, we created a relationship between out Todo and TodoItem, like we said earlier, every single Todo has many todoItem, that relationship is defined with the hasMany many method of the Todo Model. The** foreignKey: ‘todoId’, **means that todoId is going to be the foreign key column in todoItem, you can read more about foreign keys here.

we will also make the same modification to ur TodoItem

module.exports = (sequelize, DataTypes) => {
const TodoItem = sequelize.define('TodoItem', {
description: {
type: DataTypes.STRING,
allowNull: false,
},
});
TodoItem.associate = (models) => {
// associations can be defined here
TodoItem.belongsTo(models.Todo, {
foreignKey: 'todoId',
onDelete: 'CASCADE',
});
};
return TodoItem;
};

Every single Todo has many TodoItems and each TodoItem belongs to one Todo, that is why we have the TodoItem.belongsTo define in our model above. The onDelete: ‘Cascade’ means if we delete a todo then the associated todoITem should also be deleted

Now that we have our models ready we can now run our migrations, in the migration folder we’ll have a set of migration files, The files contain scripts for creating and dropping our database tables, the migration scripts were created to model what we defined in our models, again, the scripts are responsible for creating and dropping our tables every time we run it. The up function is responsible for creating our tables and its columns, the **down function **is responsible for undoing what the up function runs.

we are going to be modifying our migration scripts since we modified our model files, this is to ensure consistency between our model and migrations

since we are going to be having a** foreingkey: todoId** in the TodoItem as we defined in our models, we are going to modify the migration script for TodoItem to include a todoId

we are going to include this in the migration file for TodoItem

todoId: {
 type: Sequelize.INTEGER,
 onDelete: 'CASCADE',
 references: {
 model: 'Todos',
 key: 'id',
 as: 'todoId',
 },
 },

the **references **contains a property called model, this tells us the model this ForeignKey refers to, in our case it is the Todos, the next attribute is the key attribute which tells us what the todoId in todoItems maps to in Todos models, in this case it is the id of the Todos table, what this means is that the id of the todo table is the same as the todoId in the TodoItem table

the new migrations file should look something like this:

module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('TodoItems', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
description: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
},
todoId: {
type: Sequelize.INTEGER,
onDelete: 'CASCADE',
references: {
model: 'Todos',
key: 'id',
as: 'todoId',
},
},
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('TodoItems');
}
};

Now we are ready to run our migration, running migrations we run the script in the migrations files and create our tables. Before running the migrations, on your terminal export your database url like this:

export DATABASE_URL=postgres://[email protected]:5432/database_name

Run the migration like this:

node_modules/.bin/sequelize db:migrate

you should see something like this run in your terminal

== 20180908120703-create-todo: migrating =======
== 20180908120703-create-todo: migrated (0.025s)
== 20180908121020-create-todo-item: migrating =======
== 20180908121020-create-todo-item: migrated (0.013s)

If you check your database you will see that your table has been created and the relationship has been defined

Now it is time to persist our data, to interact with the database we created we are going to be using the models we created, with the models we have access to enormous methods we can use to interact with our database, we can perform CRUD operations through this methods,

In the controller of our todo app i.e todo.jsimport the model

import models from '../models';

This will go to the index.js fileand import dbexported at the bottom of the file. through this model, we can interact with the database.

Create Todo

Now let’s modify createTodomethod, the method to create todo currently looks like this

createTodo(req, res) {
if (!req.body.title) {
  return res.status(400).send({
    success: 'false',
    message: 'title is required',
});
} else if (!req.body.description) {
  return res.status(400).send({
    success: 'false',
    message: 'description is required',  
});
}
const todo = {
  id: db.length + 1,
  title: req.body.title,
  description: req.body.description,
};
db.push(todo);
return res.status(201).send({
  success: 'true',
  message: 'todo added successfully',
  todo,
});
}

Now instead of using db.push(todo) to push a new todo to our db object we are going to make use of the create method provided by our models, also we’ll remove the description field since the todos tabel does not have a field for description, the description will be added in the todoItem table

Now our createTodo method looks like this:

createTodo(req, res) {
  if (!req.body.title) {
    return res.status(400).send({
      success: 'false',
      message: 'title is required',
    });
}
const todo = {
  title: req.body.title,
};
models.Todo.create(todo).then((todo) => {
  return res.status(201).send({
     success: 'true',
     message: 'todo added successfully',
     todo,
   });
});
}

The .then function runs when the todo has been successfully added to the database, the parameter passed into the function in the .then is the todo response from the database after the create operation is completed, so what we are basically saying in a layman language is that the line of code should create a todo in the database, and because a database interaction will take a few milliseconds to complete we don’t want to wait for that operation to finish before we move to the next line of code, so we continue to the next line of code but when that database operation finish executing the code in the .then should run with the returned result which we passed as a parameter called todo to the function. This whole operation is called Promises in javascript, you can study more on promises here.

Our returned response looks like this:

Now we have a problem, we can create another todo with the same title and it will be added to the database, we need a way to ensure that a todo with same title doesn’t get added to the database. To do this we have to first check if the todo we are trying to add to the database exists already, if it does then we return a message to the user, if it doesn’t exist already then we add it to the database. so we have to search the database for the title that the user provide to us, if the title exists already then we will return a message to the user, otherwise, we’ll add the todo top the database

After implementing this our createTodo should now look like this

createTodo (req, res) {
  if (!req.body.title) {
    return res.status(400).send({
      success: 'false',
      message: 'title is required',
    });
  }
  models.Todo.findOne({
    where: { title: req.body.title }
  })
  .then((todoFound) => {
    if (todoFound) {
      return res.status(403).send({
       success: 'true',
        message: 'A todo with that title exist already', 
      });
    }
    const todo = {
      title: req.body.title,
    };
    models.Todo.create(todo).then((todo) => {
      return res.status(201).send({ 
        success: 'true',
        message: 'todo added successfully',
        todo,
      }); 
    });
  })
}

Now we are using the findOne method to check if a todo with the title provided already exist, if it does the we return a message, otherwise we go ahead to add the todo.

Attempting to add a Todo that already exist our response looks like this

Get All Todos

Now let’s modify our getAllTodos method, the code currently looks like this

getAllTodos(req, res) {
  return res.status(200).send({
    success: 'true',
    message: 'todos retrieved successfully',
    todos: db,
  });
}

Now we need to make use of the findAll method provided by our models to find all todos

the modification looks like this:

getAllTodos(req, res) {
  models.Todo.findAll()
  .then(todos => res.status(200).send({
    success: 'true',
    message: 'todos retrieved successfully',
    todos,
  }));
}

the response looks like this:

Get a single Todo

the old code for get a single todo

getTodo(req, res) {
  const id = parseInt(req.params.id, 10);
  db.map((todo) => {
    if (todo.id === id) {
      return res.status(200).send({
        success: 'true',
        message: 'todo retrieved successfully',
        todo, 
      });  
    }
  });
  return res.status(404).send({
    success: 'false',
    message: 'todo does not exist',
  });
}

The new code looks like this:

getTodo(req, res) {
  const id = parseInt(req.params.id, 10);
  models.Todo.findById(id)
  .then((todo) => {
    if (todo) {
      return res.status(200).send({
        success: 'true',
        message: 'todo retrieved successfully',
        todo,
      });
    }
    return res.status(404).send({
      success: 'false',
      message: 'todo does not exist',
    });
  });
}

We use the findById method and pass the Id of the todo we wish to get, if the todo exist then we get a response and if the todo does not exist we get a response telling us that the todo does not exist

Note: If you are using sequelize v5, findById was replaced by findByPk

Todo that does not exist in the database

Conclusion

This marks the end of this tutorial, as practised and before the next part of this series you can modify the endpoint for update and delete to make use of our models, Also we’ll not be working with the todoItem model we created, you can take that up as a challenge and add description to the todos that we already created. Cheers!!

Secure Node.js, Express.js and PostgreSQL API using Passport.js

Secure Node.js, Express.js and PostgreSQL API using Passport.js

The comprehensive step by step tutorial on building secure Node.js, Express.js, Passport.js, and PostgreSQL Restful Web Service

The comprehensive step by step tutorial on building secure Node.js, Express.js, Passport.js, and PostgreSQL Restful Web Service. Previously, we have shown you a combination of Node.js, Express.js, and PostgreSQL tutorial. Now, we just add a security for that RESTful Web Service endpoints. Of course, we will start this tutorial from scratch or from zero application. We will use JWT for this Node.js, Express.js, Passport.js, and PostgreSQL tutorial.

Table of Contents:

The following tools, frameworks, and modules are required for this tutorial:

We assume that you have installed PostgreSQL server in your machine or can use your own remote server (we are using PostgreSQL 9.5.13). Also, you have installed Node.js in your machine and can run node, npm or yarn command in your terminal or command line. Next, check their version by type this commands in your terminal or command line.

node -v
v8.12.0
npm -v
6.4.1
yarn -v
1.10.1

That the versions that we are uses. Let’s continue with the main steps.

1. Create Express.js Project and Install Required Modules

Open your terminal or node command line the go to your projects folder. First, install express generator using this command.

sudo npm install express-generator -g

Next, create an Express.js app using this command.

express secure-node --view=ejs

This will create Express.js project with the EJS view instead of Jade view template because using ‘–view=ejs’ parameter. Next, go to the newly created project folder then install node modules.

cd secure-node && npm install

You should see the folder structure like this.

There’s no view yet using the latest Express generator. We don’t need it because we will create a RESTful API.

2. Add and Configure Sequelize.js Module and Dependencies

Before installing the modules for this project, first, install Sequelize-CLI by type this command.

sudo npm install -g sequelize-cli

To install Sequelize.js module, type this command.

npm install --save sequelize

Then install the module for PostgreSQL.

npm install --save pg pg-hstore

Next, create a new file at the root of the project folder.

touch .sequelizerc

Open and edit that file then add this lines of codes.

const path = require('path');

module.exports = {
&nbsp; "config": path.resolve('./config', 'config.json'),
&nbsp; "models-path": path.resolve('./models'),
&nbsp; "seeders-path": path.resolve('./seeders'),
&nbsp; "migrations-path": path.resolve('./migrations')
};

That files will tell Sequelize initialization to generate config, models, seeders and migrations files to specific directories. Next, type this command to initialize the Sequelize.

sequelize init

That command will create config/config.json, models/index.js, migrations and seeders directories and files. Next, open and edit config/config.json then make it like this.

{
&nbsp; "development": {
&nbsp; &nbsp; "username": "djamware",
&nbsp; &nbsp; "password": "[email&nbsp;protected]@r3",
&nbsp; &nbsp; "database": "secure_node",
&nbsp; &nbsp; "host": "127.0.0.1",
&nbsp; &nbsp; "dialect": "postgres"
&nbsp; },
&nbsp; "test": {
&nbsp; &nbsp; "username": "root",
&nbsp; &nbsp; "password": "[email&nbsp;protected]@r3",
&nbsp; &nbsp; "database": "secure_node",
&nbsp; &nbsp; "host": "127.0.0.1",
&nbsp; &nbsp; "dialect": "postgres"
&nbsp; },
&nbsp; "production": {
&nbsp; &nbsp; "username": "root",
&nbsp; &nbsp; "password": "[email&nbsp;protected]@r3",
&nbsp; &nbsp; "database": "secure_node",
&nbsp; &nbsp; "host": "127.0.0.1",
&nbsp; &nbsp; "dialect": "postgres"
&nbsp; }
}

We use the same configuration for all the environment because we are using the same machine, server, and database for this tutorial.

Before run and test connection, make sure you have created a database as described in the above configuration. You can use the psql command to create a user and database.

psql postgres --u postgres

Next, type this command for creating a new user with password then give access for creating the database.

postgres-# CREATE ROLE djamware WITH LOGIN PASSWORD '[email&nbsp;protected]@r3';
postgres-# ALTER ROLE djamware CREATEDB;

Quit psql then log in again using the new user that previously created.

postgres-# \q
psql postgres -U djamware

Enter the password, then you will enter this psql console.

psql (9.5.13)
Type "help" for help.

postgres=>

Type this command to creating a new database.

postgres=> CREATE DATABASE secure_node;

Then give that new user privileges to the new database then quit the psql.

postgres=> GRANT ALL PRIVILEGES ON DATABASE secure_node TO djamware;
postgres=> \q

3. Create or Generate Models and Migrations

We will use Sequelize-CLI to generating a new model. Type this command to create a model for Products and User model for authentication.

sequelize model:create --name Product --attributes prod_name:string,prod_desc:string,prod_price:float
sequelize model:create --name User --attributes username:string,password:string

That command creates a model file to the model’s folder and a migration file to folder migrations. Next, modify models/user.js and then import this module.

var bcrypt = require('bcrypt-nodejs');

Add the new methods to the User model, so the user.js class will be like this.

module.exports = (sequelize, DataTypes) => {
&nbsp; const User = sequelize.define('User', {
&nbsp; &nbsp; username: DataTypes.STRING,
&nbsp; &nbsp; password: DataTypes.STRING
&nbsp; }, {});
&nbsp; User.beforeSave((user, options) => {
&nbsp; &nbsp; if (user.changed('password')) {
&nbsp; &nbsp; &nbsp; user.password = bcrypt.hashSync(user.password, bcrypt.genSaltSync(10), null);
&nbsp; &nbsp; }
&nbsp; });
&nbsp; User.prototype.comparePassword = function (passw, cb) {
&nbsp; &nbsp; bcrypt.compare(passw, this.password, function (err, isMatch) {
&nbsp; &nbsp; &nbsp; &nbsp; if (err) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return cb(err);
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; cb(null, isMatch);
&nbsp; &nbsp; });
&nbsp; };
&nbsp; User.associate = function(models) {
&nbsp; &nbsp; // associations can be defined here
&nbsp; };
&nbsp; return User;
};

For the models/product.js there’s no action needed, leave it as default generated the model class.

4. Create Routers for RESTful Web Service and Authentication

To authenticating users and secure the resources or endpoint create this file as a router.

touch routes/api.js

Open and edit routes/api.js then declares all require variables.

const express = require('express');
const jwt = require('jsonwebtoken');
const passport = require('passport');
const router = express.Router();
require('../config/passport')(passport);
const Product = require('../models').Product;
const User = require('../models').User;

Create a router for signup or register the new user.

router.post('/signup', function(req, res) {
&nbsp; console.log(req.body);
&nbsp; if (!req.body.username || !req.body.password) {
&nbsp; &nbsp; res.status(400).send({msg: 'Please pass username and password.'})
&nbsp; } else {
&nbsp; &nbsp; User
&nbsp; &nbsp; &nbsp; .create({
&nbsp; &nbsp; &nbsp; &nbsp; username: req.body.username,
&nbsp; &nbsp; &nbsp; &nbsp; password: req.body.password
&nbsp; &nbsp; &nbsp; })
&nbsp; &nbsp; &nbsp; .then((user) => res.status(201).send(user))
&nbsp; &nbsp; &nbsp; .catch((error) => {
&nbsp; &nbsp; &nbsp; &nbsp; console.log(error);
&nbsp; &nbsp; &nbsp; &nbsp; res.status(400).send(error);
&nbsp; &nbsp; &nbsp; });
&nbsp; }
});

Create a router for sign in or login with username and password.

router.post('/signin', function(req, res) {
&nbsp; User
&nbsp; &nbsp; &nbsp; .find({
&nbsp; &nbsp; &nbsp; &nbsp; where: {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; username: req.body.username
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; })
&nbsp; &nbsp; &nbsp; .then((user) => {
&nbsp; &nbsp; &nbsp; &nbsp; if (!user) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return res.status(401).send({
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; message: 'Authentication failed. User not found.',
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; user.comparePassword(req.body.password, (err, isMatch) => {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(isMatch && !err) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var token = jwt.sign(JSON.parse(JSON.stringify(user)), 'nodeauthsecret', {expiresIn: 86400 * 30});
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; jwt.verify(token, 'nodeauthsecret', function(err, data){
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log(err, data);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; res.json({success: true, token: 'JWT ' + token});
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; res.status(401).send({success: false, msg: 'Authentication failed. Wrong password.'});
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; })
&nbsp; &nbsp; &nbsp; })
&nbsp; &nbsp; &nbsp; .catch((error) => res.status(400).send(error));
});

Create a secure router to get and post product data.

router.get('/product', passport.authenticate('jwt', { session: false}), function(req, res) {
&nbsp; var token = getToken(req.headers);
&nbsp; if (token) {
&nbsp; &nbsp; Product
&nbsp; &nbsp; &nbsp; .findAll()
&nbsp; &nbsp; &nbsp; .then((products) => res.status(200).send(products))
&nbsp; &nbsp; &nbsp; .catch((error) => { res.status(400).send(error); });
&nbsp; } else {
&nbsp; &nbsp; return res.status(403).send({success: false, msg: 'Unauthorized.'});
&nbsp; }
});

router.post('/product', passport.authenticate('jwt', { session: false}), function(req, res) {
&nbsp; var token = getToken(req.headers);
&nbsp; if (token) {
&nbsp; &nbsp; Product
&nbsp; &nbsp; &nbsp; .create({
&nbsp; &nbsp; &nbsp; &nbsp; prod_name: req.body.prod_name,
&nbsp; &nbsp; &nbsp; &nbsp; prod_desc: req.body.prod_desc,
&nbsp; &nbsp; &nbsp; &nbsp; prod_price: req.body.prod_price
&nbsp; &nbsp; &nbsp; })
&nbsp; &nbsp; &nbsp; .then((product) => res.status(201).send(product))
&nbsp; &nbsp; &nbsp; .catch((error) => res.status(400).send(error));
&nbsp; } else {
&nbsp; &nbsp; return res.status(403).send({success: false, msg: 'Unauthorized.'});
&nbsp; }
});

Create a function for extract the token.

getToken = function (headers) {
&nbsp; if (headers && headers.authorization) {
&nbsp; &nbsp; var parted = headers.authorization.split(' ');
&nbsp; &nbsp; if (parted.length === 2) {
&nbsp; &nbsp; &nbsp; return parted[1];
&nbsp; &nbsp; } else {
&nbsp; &nbsp; &nbsp; return null;
&nbsp; &nbsp; }
&nbsp; } else {
&nbsp; &nbsp; return null;
&nbsp; }
};

Finally, export the router as a module.

module.exports = router;

5. Run and Test Secure Node.js, Express.js, Passport.js, and PostgreSQL Web Service

To run and test this secure Node.js, Express.js, Passport.js, and PostgreSQL Web Service, run the PostgreSQL instance first then run this command from the Terminal.

nodemon

or

npm start

To test the secure Product endpoint, open the Postman then type fill all required fields like this image.

You should get the response message Unauthorized and status code 401. Next, test signup using the Postman by changing the method to POST, add the address localhost:3000/api/signup, add the header Content-type with value application/json and the body of request raw text like this.

{ "username":"[email&nbsp;protected]", "password":"qqqq1111" }

You should get this response when executing successfully.

Next, test to log in with the above signed/registered username and password by changing the URL to localhost:3000/api/signin. You should get this response when executes successfully.

Now, you can back using the previous GET method with additional header using the token get from the sign in/log in response. You should see the Product data like below.

That it’s, the secure Node.js, Express.js, Passport.js, and PostgreSQL Web Service. You can get the working source code from our GitHub.

Learn More

The Complete Node.js Developer Course (2nd Edition)

Learn and Understand NodeJS

Node JS: Advanced Concepts

GraphQL: Learning GraphQL with Node.Js

Angular (Angular 2+) & NodeJS - The MEAN Stack Guide

The Complete Python & PostgreSQL Developer Course

SQL & Database Design A-Z™: Learn MS SQL Server + PostgreSQL

The Complete SQL Bootcamp

The Complete Oracle SQL Certification Course