NodeJs1: Server request/responses with Postman, CORS, and JWT authentification

NodeJs is a server-side javascript environment for app development.

We use ExpressJs, an open-source NodeJs framework, to handle HTTPS requests with routing support.

The REST (Representational State Transfer) API exchanges data between applications through HTTPS methods like GET, PUT, POST, and DELETE. (Client-> API -> Database -> Database data).

To start a NodeJs server we import/require express methods, each route will include an endpoint and its handler function:

- npm Init         //We start up a package.json file

//The endpoint sets where the request and response is gonna take place
const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.send("Hello World!");
});

//listen() sets the localhost: endpoint 
app.listen(3000, () => console.log("Server is up and running"))

//node server.js to start the server

The endpoint is the part of the URL that comes after /.

Contrary to React, the server needs to re-start in order to update, to avoid that we npm i nodemon.

//In the package.json we create a custom script 
"scripts": {
  "start": "nodemon server.js"      //now is npm start
}
Alternative to nodemon: Supervisor

Supervisor is a Node.js process manager, it monitors and restarts the the application on crashes or file changes. Typically used in production, it offers similar functionality to Nodemon but is not a dependency or library.

//If Nodemon restarts become unreliable or get stuck 
[nodemon] restarting due to changes...

//we globally install it and start it with
npm install supervisor -g
supervisor server.js     //depending on its path position server/server.js

For more information on using fetch in client-server request/response interactions, see this link.

Postman is a scalable testing tool, it can retrieve information sent by the server routes.

Queries are the url part that comes after a ?...=, it is used to pass information from the endpoint to the server routes.

//We request them with req.query.___, and add them to the endpoint
//we add a query with ?(name set in route)=(query value) in the URL
app.get('/', (req, res) => {
  let cava = req.query.v
  res.send("Hello World! , we have the " + cava );
});
Postaman Get method for a URL with query
Multiple queries for Math operations routes

To add multiple queries to the url we use &:

http://localhost:3000/add?value1=12&value2=21

Queries values are strings by default, we convert them for math functions.

//We first add the route endpoint and then the query values

app.get("/add", function (req, res) {
    let sum1 = Number( req.query.value1 )
    let sum2 = Number( req.query.value2 )   
    res.send("The result is " + (sum1 + sum2 ));
});

Parameters are properties attached to the URL, prefixed with (:) on the endpoint, and requested with req.params.___.

//http://localhost:3000/add1/12/74

//we pass its multiple values in the Endpoint
app.get("/add1/:primo/:second", function (req, res) {
  let sum1 = Number( req.params.primo )
  let sum2 = Number( req.params.second )
  res.send("The result is " + (sum1 + sum2 ));
});

Postman allows testing of custom headers for use in server.js.

//We can use Auth bearer token or custom headers
function authenticate(req, res, next) {
  let token = req.header("Authorization");
  console.log("Postman tested token " + token);  //
}

router.post("/sign-up", async (req, res) => {
  const {name, email, password} = req.body;

  let token = req.header("token");
  console.log( token )
}
Tests for server headers

For more information about Middlewares check here.

Modify a JSON file with Postman POST data

To body-parse request body elements we use() the express.json() built-in middleware. We install file-system (fs) which will allow us to update server files.

//Unlike normal middleware, it doesn't need to be included in routes
//This allows request.body to be available in route paths.
app.use(express.json())

npm i file-system
const fs = require("fs")

We request the body from Postman Post and update the imported JSON array using fs.

//we set the new object ID to be the last of the JSON.
const quotes = require("./quotes.json");  //[{}, {}, {}, ...]

app.post("/quotes", function(req, res){
  const corpo = req.body
  corpo.id = quotes.length

  quotes.push( corpo )
  fs.writeFileSync("./quotes.json", JSON.stringify(quotes));

  res.send( "Pushed one" )
})
Postman POST and updated JSON (with changed ID)

Both Post and Put Postman methods can update and create elements, Put is idempotent, its results remain the same not matter how many times it's repeated.

PUT and DELETE method update on JSON file

To update the JSON file with the Postman POST body, we filter both its ID and its parameter so it keeps the updated object ID.

//Splice() uses the index so we need to lower it
app.put("/quotes/:id", function(req, res){
  const messo= req.body
  let index= Number( req.params.id )

  if( index > quotes.length-1 || messo.id > quotes.length-1 ){
    res.send("object to update not present")
  }else
    quotes.splice( index-1 , 1, messo )

    fs.writeFileSync("./quotes.json", JSON.stringify(quotes));
    res.send("We updated the Json array")
  }
})

To DELETE a JSON element by its ID parameter, we filter() it and use the matching element index to splice().

//album returns an array, we [0] to extract its index
app.delete("/quotes/:id", function(req, res){
  let canc = Number( req.params.id )

  let album = quotes.filter((el) => {
    return el.id == canc
  });

  const index = quotes.indexOf(album[0]);
  quotes.splice( index, 1 )
  
  fs.writeFileSync("./quotes.json", JSON.stringify(quotes));
  res.status(200).json({ succes: true });
})

CORS and JWT autentification

CORS, Cross-Origin Resource Sharing, allows servers to set specific origins for their request. Origins are defined by their protocol HTTP and port number.

HTTP is a stateless protocol, it won't record any request data, so to authenticate the user and to share data between the browser and server we used sessions.

Session objects track users by comparing their cookies (string files downloaded on website access) to the ID session. When users make a request (log in) it checks if they have an already open session and what permits they have.

Sessions need storage space and extra security when sent to the server, they make the app harder to scale, and it's hard to implement on apps that contain many back-end micro-services or don't use the browser for their cookies.

Sessions cookies and session ID

The JSONWebToken (JWT) registers the user directly to the app without any sessions. JSON stands for Javascript Object Notation, a text-based data format transferable between all languages and standard syntax for APIs.

The JWT is made of clains (string sections) separated by a comma, clains are encoded in code-64.

The first header clain contains the hashing algorithm and the token type. The second contains the JSON object sent to the user, visible to anyone. The third is a secret hash, kept by the server and it resets if the original request changes.

JWT token

Implementing JWT registration to the server

The JWT user server will have this structure.

/server
server.js
/utils
  generateJWT.js
  auth.js
/routes
  user.js

Check the CORS section to know more about the configuration.

//Implement the CORS middleware
const express = require("express");
const app = express();
app.use(express.json());    //req.body parser
const cors = require("cors");

const corsOptions = {
  origin: "http://localhost:3000"    
};
app.use(cors(corsOptions));

const user = require("./routes/user.js");
app.use("/user", user);

The /user route will handle all user server calls, check the Express routing section for more.

Server routing, bcrypt and File-System modules

We request the user destructed form data to update/check the database, using bcrypt for the password and fs to edit the database js file.

//We either filter or add depending on sign-in/sign-up
const express = require("express");
const bcrypt = require("bcrypt");   
const fs = require("fs"); 
const router = express.Router(); 

const usersDb = require("../database/db.json");
const generateJWT = require("../utils/generateJWT");

const authenticate = require("../middleware/authentificate.js");

router.post("/sign-up", async (req, res) => {
  const { name, email, password } = req.body;

  try {
    const user = await usersDb.filter(user => user.email === email);
    if (user.length > 0) {
      return res.status(400).json({error: "User already exist!"});
    }

    const salt = await bcrypt.genSalt(10);
    const bcryptPassword = await bcrypt.hash(password, salt);
    let newUser = {
      id: usersDb.length,
      name: name,
      email: email,
      password: bcryptPassword
    }

    usersDb.push(newUser);
    await fs.writeFileSync('./database/db.json', JSON.stringify(usersDb));
     
    const jwtToken = generateJWT(newUser.id);
    return res.status(201).send({jwtToken: jwtToken, isAuthenticated: true});

  } catch (error) {
    console.error(error.message);
    res.status(500).send({error: error.message});
  }
});

module.exports = router;
Created Post user in teh JSON database and JWT user response.send()

We set the utilities following the JWT section

We store the JWT key in a safe place, like an env file.

//Exported and used as middleware in /user
const jwt = require("jsonwebtoken");
require("dotenv").config();

function generateJWT(user_id) {
  const payload = {
    user: {
      id: user_id
    }
  };

  return jwt.sign(payload, process.env.jwtSecret, { expiresIn: "1h" });
}

module.exports = generateJWT;
Sign-in JWT and JWTBearer on Postman with code 200 res.send()

Last updated

Was this helpful?