Inteliny
DevelopmentLevel: Intermediate30mVerified Production Blueprint

How to Build a Production-Ready REST API Using Node.js, Express & MongoDB

Learn to create a scalable and secure REST API using Node.js, Express, and MongoDB

Inteliny Engineering

Principal Architect

Overview & Architecture Scope

This comprehensive guide is designed for developers looking to build a production-ready REST API using Node.js, Express, and MongoDB. By the end of this guide, you will have a fully functional REST API that includes features such as JWT authentication, role-based access control, input validation, error handling, and logging. The guide assumes you have basic knowledge of JavaScript, Node.js, and MongoDB. You will need to have Node.js and MongoDB installed on your machine to follow along.

Prerequisites & System Requirements

Ensure your development workstation or staging server fulfills the following prerequisites before initiating commands:

Node.js v18.0+ runtime environment
MongoDB v6.0+ database cluster
Active AWS or Cloudflare account with DNS access
Linux Ubuntu 22.04 LTS server instance
Basic knowledge of CLI bash & Git workflow

Target System Architecture Diagram

Browser
NGINX
Node / Express
MongoDB / Redis

Interactive Execution Checklist

0/17 Completed

Step-by-Step Implementation Guide

1

Step 1: Set Up the Project Structure

Create a new project folder and initialize a new Node.js project using npm init. Create the following folders: controllers, models, routes, services, and utils. This structure will help keep your code organized and maintainable.

Execute Command Terminal:

bash
mkdir my-api && cd my-api && npm init -y
Make sure to create the folders as described to follow along with the guide
2

Step 2: Install Required Dependencies

Install the required dependencies for the project, including Express, MongoDB, and JWT. Use npm install to install the dependencies.

Execute Command Terminal:

bash
npm install express mongoose jsonwebtoken bcryptjs
Make sure to install all the required dependencies to avoid errors
3

Step 3: Configure Express

Create a new file called app.js and require the installed dependencies. Create an instance of the Express app and configure it to use JSON parsing and URL encoding.

Execute Command Terminal:

javascript
const express = require('express'); const app = express(); app.use(express.json()); app.use(express.urlencoded({ extended: true }));
Make sure to require the dependencies and configure the Express app correctly
4

Step 4: Connect to MongoDB

Create a new file called db.js and require the mongoose dependency. Connect to the MongoDB database using the mongoose.connect method.

Execute Command Terminal:

javascript
const mongoose = require('mongoose'); mongoose.connect('mongodb://localhost/my-api', { useNewUrlParser: true, useUnifiedTopology: true });
Make sure to replace the connection string with your own MongoDB connection string
5

Step 5: Implement JWT Authentication

Create a new file called auth.js and require the jsonwebtoken dependency. Implement a function to generate a JWT token and another function to verify the token.

Execute Command Terminal:

javascript
const jwt = require('jsonwebtoken'); const generateToken = (user) => { return jwt.sign(user, process.env.SECRET_KEY, { expiresIn: '1h' }); }; const verifyToken = (req, res, next) => { const token = req.header('Authorization'); if (!token) return res.status(401).send('Access denied'); try { const decoded = jwt.verify(token, process.env.SECRET_KEY); req.user = decoded; next(); } catch (ex) { return res.status(400).send('Invalid token'); } };
Make sure to replace the secret key with your own secret key
6

Step 6: Implement Role-Based Access Control

Create a new file called roles.js and define the roles for the API. Implement a function to check if a user has a certain role.

Execute Command Terminal:

javascript
const roles = { admin: ['create', 'read', 'update', 'delete'], user: ['read'] }; const hasRole = (user, role) => { return user.roles.includes(role); };
Make sure to define the roles and implement the hasRole function correctly
7

Step 7: Implement Input Validation

Create a new file called validation.js and require the joi dependency. Implement a function to validate user input using Joi.

Execute Command Terminal:

javascript
const Joi = require('joi'); const validateUser = (user) => { const schema = Joi.object({ name: Joi.string().required(), email: Joi.string().email().required() }); return schema.validate(user); };
Make sure to require the joi dependency and implement the validateUser function correctly
8

Step 8: Implement Error Handling

Create a new file called errors.js and define a custom error class. Implement a function to handle errors and return a response to the client.

Execute Command Terminal:

javascript
class CustomError extends Error { constructor(message, statusCode) { super(message); this.statusCode = statusCode; } }; const handleError = (err, res) => { const error = new CustomError(err.message, err.statusCode); res.status(error.statusCode).send({ message: error.message }); };
Make sure to define the custom error class and implement the handleError function correctly
9

Step 9: Implement Logging

Create a new file called logger.js and require the winston dependency. Implement a function to log messages using Winston.

Execute Command Terminal:

javascript
const winston = require('winston'); const logger = winston.createLogger({ level: 'info', format: winston.format.json(), transports: [ new winston.transports.File({ filename: 'logs/error.log', level: 'error' }), new winston.transports.File({ filename: 'logs/combined.log' }) ] }); const logMessage = (message) => { logger.info(message); };
Make sure to require the winston dependency and implement the logMessage function correctly
10

Step 10: Implement Swagger Documentation

Create a new file called swagger.js and require the swagger-ui-express dependency. Implement a function to serve the Swagger UI.

Execute Command Terminal:

javascript
const swaggerUi = require('swagger-ui-express'); const swaggerDocument = require('./swagger.json'); const serveSwagger = (app) => { app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument)); };
Make sure to require the swagger-ui-express dependency and implement the serveSwagger function correctly
11

Step 11: Implement Helmet

Create a new file called helmet.js and require the helmet dependency. Implement a function to configure Helmet.

Execute Command Terminal:

javascript
const helmet = require('helmet'); const configureHelmet = (app) => { app.use(helmet()); };
Make sure to require the helmet dependency and implement the configureHelmet function correctly
12

Step 12: Implement Rate Limiting

Create a new file called rate-limiting.js and require the express-rate-limit dependency. Implement a function to configure rate limiting.

Execute Command Terminal:

javascript
const rateLimit = require('express-rate-limit'); const configureRateLimiting = (app) => { const limiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }); app.use(limiter); };
Make sure to require the express-rate-limit dependency and implement the configureRateLimiting function correctly
13

Step 13: Implement CORS

Create a new file called cors.js and require the cors dependency. Implement a function to configure CORS.

Execute Command Terminal:

javascript
const cors = require('cors'); const configureCORS = (app) => { app.use(cors()); };
Make sure to require the cors dependency and implement the configureCORS function correctly
14

Step 14: Configure Environment Variables

Create a new file called env.js and require the dotenv dependency. Implement a function to configure environment variables.

Execute Command Terminal:

javascript
const dotenv = require('dotenv'); const configureEnvironmentVariables = () => { dotenv.config(); };
Make sure to require the dotenv dependency and implement the configureEnvironmentVariables function correctly
15

Step 15: Test the API

Use a tool like Postman to test the API endpoints. Make sure to test all the endpoints and verify that they are working as expected.

Make sure to test all the endpoints and verify that they are working as expected
16

Step 16: Deploy the API

Deploy the API to a cloud platform like AWS or Google Cloud. Make sure to configure the environment variables and deploy the API to a production environment.

Make sure to deploy the API to a production environment and configure the environment variables
17

Step 17: Monitor the API

Use a tool like New Relic to monitor the API performance. Make sure to monitor the API performance and fix any issues that arise.

Make sure to monitor the API performance and fix any issues that arise

Pro Tips & Optimizations

Use a consistent coding style throughout the project
Use a version control system like Git to manage the code
Use a testing framework like Jest to test the API
Use a logging framework like Winston to log messages

Common Pitfalls to Avoid

Not validating user input
Not implementing error handling
Not configuring environment variables
Not testing the API
Conclusion & Next Steps

In this guide, we have learned how to build a production-ready REST API using Node.js, Express, and MongoDB. We have implemented features like JWT authentication, role-based access control, input validation, error handling, and logging. We have also deployed the API to a production environment and monitored its performance. By following this guide, you can build a scalable and secure REST API that meets your needs.

Production Best Practices & Hardening

Security Hardening

Disable root SSH access, enforce key-based auth, and enable UFW firewall on ports 80/443.

Memory Management

Set Node.js max-old-space-size to 80% of total RAM to avoid Linux OOM-killer crashes.

Frequently Asked Questions

Yes, all NGINX, Docker, and PM2 deployment steps can be packaged into Infrastructure as Code (IaC) playbooks.

Need Help Implementing This?

Partner with Inteliny's principal architects to audit your stack, automate CI/CD, and accelerate deployment.

How to Build a Production-Ready REST API Using Node.js, Express & MongoDB | Inteliny Knowledge Base