How to create routes using Express and Postman..

Yudhajit Adhikary
15 min readSep 11, 2021

In this article we will see how to develop api endpoint using NodeJS and Postman. We will divide this article into several parts so that it’s easy for us to understand.

1. Brief definition of NodeJs.

2. Brief definition of Postman

3. Setting up Express and Basic routes

4. API and Restful API Design

5. Middleware and the Request Response Cycle

6. Implementing Post,Patch, Get and Delete request in Api

7. Conclusion

  1. Brief definition of Express:

Express is a fast, unopinionated minimalist web framework for Node.js ” — official web site: Expressjs.com

Express.js is a web application framework for Node.js. It provides various features that make web application development fast and easy which otherwise takes more time using only Node.js.

Express.js is based on the Node.js middleware module called connect which in turn uses http module. So, any middleware which is based on connect will also work with Express.js. For more details please go through the official website .

2. Brief definition of Postman:

Postman is an API client that makes it easy for developers to create, share, test and document APIs. This is done by allowing users to create and save simple and complex HTTP/s requests, as well as read their responses. The result — more efficient and less tedious work. For more details please go through the documentation .

3. Setting up Express and Basic routes:

After a brief description of what are Postman and NodeJs, Let’s see how our final codebase will actually look like:

Folder structure

So before we start with explanation of our codebase folder , let first understand what is our aim ,what we are going to create ? We will actually create a tour management api , where we will perform all the CRUD (Create,Read,Update,Delete ) operations like creating a new tour , updating an existing tour, deleting a tour etc using Express js and we will test our api ends on Postman. So our codebase will be having a controller folder which will have the controller functions like creating , updating , deleting tours, we are having two files inside, tourController.js will contain the controller functions of tours, where as userController.js will contain the controller functions of users. dev-data is a folder where we are having some dummy tour data that we will populating in our api as the sample tour dataset, tours-simple.json is having those sample data . node-modules will be created when we will run npm i on our integrated terminal of vscode, we will come on that part later . Public folder is having two html files these are not required for now , I have added that just to show you some add-on feature of express like how we can show html page in our api endpoint , about this we will discuss in the last section of this article. Next routes folder is having the endpoints means the router which we will create and will test in Postman. tourRoutes.js will contain the routes for tours , whereas userRoutes.js will contain the routes for users. .eslintrc.json is the file where we can config the eslint rules of our application, we will not be discussing about eslint in this article our main focus will be on creating restful api. Similarly .prettierrc is the file to define prettier which are helpful to resolve lint issue of our application. app.js is the file which will be responsible for setting up our express js , config.env is the environment config file where we used to keep all the constant values which will be same throughout the application , config.env also contains constants that changes depending on which environment our application is running like development or production. package.json is used to store the metadata associated with the project as well as to store the list of dependency packages. In order to add dependency packages to your projects, you need to create package.json file. The file makes it easy for others to manage and install the packages associated with the project.While app.js is responsible to setup express in our application , server.js is responsible to run our express application in the server .

So first we will create our package.json file , so we will open our integrated terminal of vscode and run npm init , this command will ask some questions to create our package.json file, you can answer those or can skip by pressing enter. Finally you will see a package.json file will get created.So now we have to install our main package express, to install that we will run npm i express in our terminal.

Now we will create our app.js file:

const express = require('express');
const morgan = require('morgan');
const tourRouter = require('./routes/tourRoutes');
const userRouter = require('./routes/userRoutes');
const app = express();
console.log(app.get('env'))
// 1) MIDDLEWARES
if (process.env.NODE_ENV === 'development') {
app.use(morgan('dev'));
}
app.use(express.json());
app.use(express.static(`${__dirname}/public`));
app.use((req, res, next) => {
console.log('Hello from the middleware 👋');
next();
});
app.use((req, res, next) => {
req.requestTime = new Date().toISOString();
next();
});
// 3) ROUTES
app.use('/api/v1/tours', tourRouter);
app.use('/api/v1/users', userRouter);
module.exports = app;

In app.js, we are first importing express and morgan ,morgan is HTTP request logger middleware for node.js, this package is used to see req data right in console.Then we are importing the routes of our application. We are creating variable called app which represent the result of calling express. app.get(‘env’) is the variable which determines in which environment we are running our code.

if (process.env.NODE_ENV === 'development') {
app.use(morgan('dev'));
}

We are checking if the node environment is development , we are using morgan middleware.

app.use(express.json());

it a method inbuilt in express to recognise the incoming Request Object as a JSON Object . This function is the first middleware which we are using in our application.

app.use(express.static(`${__dirname}/public`));

by this we are telling express to take all static files from public folder of our codebase.

app.use((req, res, next) => {
console.log('Hello from the middleware 👋');
next();
});
app.use((req, res, next) => {
req.requestTime = new Date().toISOString();
next();
});

We are creating a middleware function we will discuss about what is middleware later.

app.use('/api/v1/tours', tourRouter);
app.use('/api/v1/users', userRouter);

Then we are define the base routes of our application separately for tours and users , we will look into tours routes in this article .We are adding router from the respective route file . Like let’s assume we are having a route like /api/v1/tours/viewTours to show all tours ,then the base route of the url is /api/v1/tours which will be same for all routes related to tours and the remaining part is /viewTours which will depend based on our requirement and how we want our routes to look like , those will be defined in files inside routes folder.

module.exports = app;

Lastly we are exporting our express object. Now let’s see server.js:

const dotenv = require('dotenv');
const app = require('./app');
dotenv.config({ path: './config.env' });
const port = process.env.PORT || 3000;
app.listen(port, () =>
{ console.log(`App running on port ${port}...`);});

In server.js we will ask express to listen to port 3000 to startup in server, express is 100% NodeJs under the hud. So here we are importing dotenv. Dotenv is a zero-dependency module that loads environment variables from a .env file into process.env, to install it we have to run npm i dotenv in our integrated terminal ,then we are importing our express object from app.js .

dotenv.config({ path: './config.env' });

Here we are asking dotenv to take the env variables from config.env.

const port = process.env.PORT || 3000;

We are defining the port in which we want to run our application, if we are not having PORT defined in config.env , we will define it as 3000.

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

Express is 100% NodeJs under hud, we are passing port and calling the callback function where we have added a console.log message just to tell our user that our application is running successfully. Let’s now see our config.env file:

NODE_ENV=developmentPORT=3000USERNAME=YudhaPASSWORD=123456

In config.env we used to define all the variable which are constant throughout our application or frequently used constant , the main benefit of this is that we can update the values of those variables which are used in many places of our codebase just by changing it in this one file.

So before going to our other files let’s understand few concepts of express, api , restful api , middleware and request response cycle. So let’s begin ..

4. API and Restful API Design

So what is Api ? Api stands for application programming interface , a piece of software that can be used by another piece of software, in order to allow application to talk to each other. It’s not necessary for Api to always be a webapi, but Api can be used with , Nodejs for http API( Node API), Browser DOMJS Api, or with object-oriented programming when exporting method to the public .

There are some specific characteristics which makes an api ,a restful api those are:

a. Separate Api into logical resource :

All data we are using should be divided into logical resource. Resource object is a representation of something , which has data associated to it , any information that can be named like user, tours etc.

b. Expressing structured resource band URLs:

We should define urls with proper structured resource format:

https://www.tours.com/addNewTour

https://www.tours.com->urls

addNewTour->Endpoint

c. using HTTPS methods(verbs):

We have to perform Create, Read,Update,Delete methods .

Create -> POST /tour

Read-> GET/tours/7

Update->[PUT->Client is suppose to put entire update object]

,[PATCH->Client send only the part of object that have been changed]

Delete->DELETE/tour/7

d. Send data as JSON:

We have to send data in Json format :

If there is a data coming from api looks like this:

{

“id”:5,

“tourName”: “Manali”

“rating”: “4.5”

}

in express we will actually convert the data into a proper format of response like this:

{

“status”: “success”,

“data”:{

“id”:5,

“tourName”: “Manali”,

“rating”: “4.5”

}

}

This formatting is called enveloping the response from Api.

e. Be stateless:

All state should be on the client, this means that each request must contain all the information necessary to process a certain request, the server should not have to remember previous request. Let’s try to understand it with an example. Let say there is a api tour/next where we are performing GET method to get the next page, so to go to the next page index we have to have two variables currentpage:contains currentpage index and nextpage:contains nextpage index, so to handle such situation we have to add code something like this:

GET/ tour/next →WEB SERVER

currentPage=5

nextPage=currentPage+1

send(nextPage)

In this case the state is actually on server

But in restful api the next page will come from the client so server do not have to remember previous request.

GET/tour/6 →WEB SERVER

5. Middleware and the Request Response Cycle:

Middleware Stack

The essence of express is Request Response Cycle, Express Application receives a request when someone hit the server , then a request and response object that means data is used and processed in order to generate and set back a meaningful response to the client . And to process the data we used something called Middleware, which can manipulate the request or response object, it’s called middleware because it’s a function which executes between the receiving the request and sending the response. Actually we can say that in express everything is a middleware. Order of middleware stack is actually executed in the order those are defined in the code.Each and every request, response coming from incoming request use to move and processed through each middleware. At the end of middleware we used to call next() function, this next() function actually calls the next middleware function that is defined in the chain of middleware.

6. Implementing Post,Patch,Get and Delete request in Api:

So let see how to implement https methods , let’s see our TourRoutes.js:

const express = require('express');const tourController = require('./../controllers/tourController');const router = express.Router();router.param('id', tourController.checkID);router.route('/').get(tourController.getAllTours).post(tourController.checkBody, tourController.createTour);router
.route('/:id')
.get(tourController.getTour).patch(tourController.updateTour).delete(tourController.deleteTour);module.exports = router;

In TourRoutes.js, we are first importing express, then we are importing tourController which contains all the logical function of implementing the http functional of tour routes. Then we are defining the routes , routing means basically to determine how an application respond to a certain client request.

router.route('/').get(tourController.getAllTours).post(tourController.checkBody, tourController.createTour);

So we are actually using two routes ,first one is /api/v1/tours , you may remember this is the base route we have defined in app.js , so ‘/’ actually means the base route , so in this route we will be showing all the tours.The functionality of doing so is actually defined in tourController.js. To get all tours we have to implement get request on that api, so we are calling a callback function or middleware getAllTours which is defined in tourController.js. On the same route we will also implement post operation to add new tours, for that we are implementing a chain of middleware. Here the first middleware is checkbody which actually validating whether the user is entering valid entries and mandatory data to create a new tour and then createTour which is creating the new tour.

router
.route('/:id')
.get(tourController.getTour).patch(tourController.updateTour).delete(tourController.deleteTour);

Second is /api/v1/tours/:id, where we are performing three http operations, first one is get operation to get the details of specific tour which will be having the specific id , id will actually come from client side means if client hits /api/v1/tours/56 then it’s actually refers that user wants to operate http operation on the tour which is having the id 56.

router.param('id', tourController.checkID);

router.param is actually used to define how route will reacts when user hits some url which is having id in the end of the url, so when user hits such url, this checkID middleware function will first get triggered to check whether the user have entered valid id , or if there is any tours having the same id , if not it will throw error message . We have discussed previously that middleware functions used to get triggered in the order they are called , so once this id validation is done then the other http functions are called. So in /api/v1/tours/:id route we are performing three http operations, first one is get operation to get the tour details having specific id .The callback function or middleware getTour function will do that job, second is patch function to update tour details of the tour having the specific id , the updateTour function will handle the functionality , similarly third one is delete operation to delete tour having the specific id, to implement deletion of the tour we are calling deleteTour function. Lastly we are exporting the routes. Now let’s see tourController.js:

const fs = require('fs');const tours = JSON.parse(fs.readFileSync(`${__dirname}/../dev-data/data/tours-simple.json`));exports.checkID = (req, res, next, val) => {// console.log(`Tour id is: ${val}`);if (req.params.id * 1 > tours.length) {return res.status(404).json({status: 'fail',message: 'Invalid ID'});}next();};exports.checkBody = (req, res, next) => {if (!req.body.name || !req.body.price) {return res.status(400).json({status: 'fail',message: 'Missing name or price'});}next();};exports.getAllTours = (req, res) => {// console.log(req.requestTime);res.status(200).json({status: 'success',requestedAt: req.requestTime,results: tours.length,data: {tours}});};exports.getTour = (req, res) => {// console.log(req.params);const id = req.params.id * 1;const tour = tours.find(el => el.id === id);res.status(200).json({status: 'success',data: {tour}});};exports.createTour = (req, res) => {// console.log(req.body);const newId = tours[tours.length - 1].id + 1;const newTour = Object.assign({ id: newId }, req.body);tours.push(newTour);fs.writeFile(`${__dirname}/dev-data/data/tours-simple.json`,JSON.stringify(tours),err => {res.status(201).json({status: 'success',data: {tour: newTour}});});};exports.updateTour = (req, res) => {res.status(200).json({status: 'success',data: {tour: '<Updated tour here...>'}});};exports.deleteTour = (req, res) => {res.status(204).json({status: 'success',data: null});};

In TourController.js we are defining all function which are associated with tour routes. So first we are importing fs package , this package is used to read or write data from a static file. To install this package we have to run npm i fs in our integrated terminal.

const tours = JSON.parse(fs.readFileSync(`${__dirname}/../dev-data/data/tours-simple.json`));

We will actually read data from the static file named tours-simple.json which is inside dev-data folder. So we are reading data from tours-simple.json and storing it in variable called tours .

exports.checkID = (req, res, next, val) => {// console.log(`Tour id is: ${val}`);if (req.params.id * 1 > tours.length) {return res.status(404).json({status: 'fail',message: 'Invalid ID'});}next();};

So the middleware usually used to have req, res , let’s take a get operation , if client requests for get operation on ‘/’ routes , the function to handle such request actually looks like this :

app.get(‘/’,(req, res)=>{

call back function we want to perform

}

req represents the request body which client is sending, res represent the response we will be sending back to client,

In checkID function, we are checking whether user is entering valid id before dealing with the routes having id at it’s end , we are checking whether request param id is larger than tours length, if it’s true it means user has entered invalid id, we will send response with status code 404 and return json response having params, status: ‘fail’ , message: ‘Invalid id’ , then we are calling next() function, next() function calls the next middleware function defined in the middleware stack if any.

exports.checkBody = (req, res, next) => {if (!req.body.name || !req.body.price) {return res.status(400).json({status: 'fail',message: 'Missing name or price'});}next();};

In checkBody function, we are actually checking whether the user is giving all the mandatory fields while creating a new tour. Name and price are the mandatory fields for creating new tours.So we are checking whether request body is having name and price fields, if those are not there we will return error message ‘Missing name or price’ with status code 400, then we are calling next() function which will call the next middleware function define in the middleware stack if any.

exports.getAllTours = (req, res) => {// console.log(req.requestTime);res.status(200).json({status: 'success',requestedAt: req.requestTime,results: tours.length,data: {tours}});};

In getAllTours function, we are getting all the tours present in our application, so we are setting response status as 200, and we are sending response json which is having params like status: ‘success’, requestAt will have time at which request was made, results will have the number of tours present in our application, and lastly in data we are passing our tours variable which we defined above.

GET OPERATION IN POSTMAN
exports.getTour = (req, res) => {// console.log(req.params);const id = req.params.id * 1;const tour = tours.find(el => el.id === id);res.status(200).json({status: 'success',data: {tour}});};

In getTour function, we are getting the tour having the id we are specifying in the url(ex: /api/v1/tours/2) where id is 2.So in this function we are using find function and checking if there is any tour which is having id equal to param id.If there is a match we are storing that in our tour variable. then we are sending our res status code 200 and sending response data having status= ‘success’ and data having our tour object.

GET OPERATION ON POSTMAN
exports.createTour = (req, res) => {// console.log(req.body);const newId = tours[tours.length - 1].id + 1;const newTour = Object.assign({ id: newId }, req.body);tours.push(newTour);fs.writeFile(`${__dirname}/dev-data/data/tours-simple.json`,JSON.stringify(tours),err => {res.status(201).json({status: 'success',data: {tour: newTour}});});};

In createTour function, we are creating new tour by taking data from req body. So we are creating newId by adding last tour id with one , then we are creating our newTour , so we are creating an object with id as newId and other req.data, then we are pushing our newTour into our tours variable, then we are replacing data of our tours-simple.json with our latest tours value. Finally we are sending res status code 201 and sending response data having status= ‘success’ and data having our newTour object.

POST OPERATION IN POSTMAN
exports.updateTour = (req, res) => {res.status(200).json({status: 'success',data: {tour: '<Updated tour here...>'}});};

In updateTour function, we are updating the existing tour having the id similar to req.param.id, and passing response status 200.

PATCH OPERATION IN POSTMAN
exports.deleteTour = (req, res) => {res.status(204).json({status: 'success',data: null});};

In deleteTour function, we are deleting the tour having the id similar to req.param.id, and passing response status 200.

7. Conclusion:

So in this article we discuss how to create restful api and perform CRUD operation using express and postman. We will be continuing our discussion in next article , in next article we will be discussing how to setup , integrate MongoDb and how to define schema in MongoDb using Mongoose.I am attaching the GitHub code link as a reference of this article:

HAPPY CODING !!

--

--

Yudhajit Adhikary

Web developer by profession,Photographer,Blog Writer,Singer,Pianist,Seeker of Solution