NashTech Insights

Building a RESTful API with Node.js and Express

Alka Vats
Alka Vats
Table of Contents

Introduction:

In today’s digital landscape, creating efficient and scalable APIs is essential for developing web and mobile applications. Representational State Transfer (REST) has become a popular architectural style for designing APIs due to its simplicity and ease of use. In this blog, we will walk you through the process of building a RESTful API using Node.js and the Express framework, complete with step-by-step examples.

If you want to learn about the best practices of node.js, you can refer here.

1. Introduction to RESTful APIs

What is a RESTful API?

A RESTful API is a set of rules and conventions for building and interacting with web services. It is based on the principles of Representational State Transfer (REST), which is an architectural style for networked applications. RESTful APIs use HTTP methods (GET, POST, PUT, DELETE) to perform various operations on resources, following a client-server model.

Key Concepts of REST

  • Resources: Everything in a RESTful API is treated as a resource. Each resource is identified by a unique URL, often referred to as an endpoint.
  • HTTP Methods: REST APIs use HTTP methods to perform actions on resources. The most common methods are GET (retrieve data), POST (create data), PUT (update data), and DELETE (remove data).
  • Stateless: The server does not store the client’s state. Each request from a client to the server must contain all the information needed to understand and fulfill the request.
  • Uniform Interface: APIs should have a consistent and standardized way of interacting, which simplifies client-server communication.
  • Representation: Resources can have multiple representations, such as JSON, XML, HTML, etc. Clients can request a specific representation.

2. Setting Up the Project

Installing Node.js and npm

Before starting, make sure you have Node.js and npm (Node Package Manager) installed on your system. You can download them from the official Node.js website.

Initializing the Project

Open your terminal and navigate to the desired project directory. Run the following command to initialize a new Node.js project:

npm init -y

This command will create a package.json file for your project.

3. Creating the Express Application

Installing Express

Express is a popular Node.js framework that simplifies the process of building web applications and APIs. Install Express by running the following command in your project directory:

npm install express

Creating the Basic Server

Create a file named app.js in your project directory. This will be the entry point for your application. Open app.js and set up a basic Express server:

const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

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

Now, if you run node app.js in your terminal, you should see the message “Server is running on port 3000” when the server starts.

4. Defining API Routes

In Express, routes are used to define different endpoints and the actions associated with them. Let’s create routes for performing CRUD operations on a hypothetical “tasks” resource.

Creating Routes for CRUD Operations

Add the following code to app.js to define routes for various CRUD operations:

app.get('/api/tasks', (req, res) => {
  // Implement logic to retrieve all tasks
  res.json({ message: 'Get all tasks' });
});

app.get('/api/tasks/:id', (req, res) => {
  const taskId = req.params.id;
  // Implement logic to retrieve a specific task by ID
  res.json({ message: `Get task with ID ${taskId}` });
});

app.post('/api/tasks', (req, res) => {
  // Implement logic to create a new task
  res.json({ message: 'Create a new task' });
});

app.put('/api/tasks/:id', (req, res) => {
  const taskId = req.params.id;
  // Implement logic to update a task by ID
  res.json({ message: `Update task with ID ${taskId}` });
});

app.delete('/api/tasks/:id', (req, res) => {
  const taskId = req.params.id;
  // Implement logic to delete a task by ID
  res.json({ message: `Delete task with ID ${taskId}` });
});

Handling Route Parameters

In the code above, :id is a route parameter that captures the task ID from the URL. You can access this parameter using req.params.id.

Parsing Request Body

To handle data sent in the request body (e.g., when creating or updating a task), you need to parse the JSON data. Add the following code at the beginning of your app.js to enable JSON parsing:

app.use(express.json());

Now your Express application is capable of parsing JSON data from the request body.

5. Implementing CRUD Operations

Setting Up Mock Data

For the sake of this example, let’s set up a simple array to simulate a database:

const tasks = [
  { id: 1, title: 'Task 1', completed: false },
  { id: 2, title: 'Task 2', completed: true },
];

Creating the Read Operation

Implement the read operation for retrieving all tasks and a specific task by ID:

app.get('/api/tasks', (req, res) => {
  res.json(tasks);
});

app.get('/api/tasks/:id', (req, res) => {
  const taskId = parseInt(req.params.id);
  const task = tasks.find(task => task.id === taskId);
  
  if (!task) {
    return res.status(404).json({ error: 'Task not found' });
  }
  
  res.json(task);
});

Implementing Create, Update, and Delete Operations

Now, let’s implement the remaining CRUD operations:

app.post('/api/tasks', (req, res) => {
  const newTask = {
    id: tasks.length + 1,
    title: req.body.title,
    completed: false,
  };
  
  tasks.push(newTask);
  res.status(201).json(newTask);
});

app.put('/api/tasks/:id', (req, res) => {
  const taskId = parseInt(req.params.id);
  const task = tasks.find(task => task.id === taskId);
  
  if (!task) {
    return res.status(404).json({ error: 'Task not found' });
  }
  
  task.title = req.body.title || task.title;
  task.completed = req.body.completed || task.completed;
  
  res.json(task);
});

app.delete('/api/tasks/:id', (req, res) => {
  const taskId = parseInt(req.params.id);
  const taskIndex = tasks.findIndex(task => task.id === taskId);
  
  if (taskIndex === -1) {
    return res.status(404).json({ error: 'Task not found' });
  }
  
  tasks.splice(taskIndex, 1);
  res.json({ message: 'Task deleted' });
});

6. Error Handling and Validation

Implementing Error Handling Middleware

To handle errors gracefully, you can implement a custom error handling middleware. Add the following code after your route definitions in app.js:

app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ error: 'Something went wrong' });
});

Validating Request Data

To validate the request data before processing, you can use various validation libraries. One popular choice is joi. Install it using the following command:

npm install joi

Then, use it to validate the request body data in your create and update routes:

const joi = require('joi');

// ...

app.post('/api/tasks', (req, res) => {
  const schema = joi.object({
    title: joi.string().required(),
    completed: joi.boolean(),
  });

  const { error } = schema.validate(req.body);
  if (error) {
    return res.status(400).json({ error: error.details[0].message });
  }

  // ...
});

app.put('/api/tasks/:id', (req, res) => {
  // Similar validation logic
});

7. Testing the API

Using Postman for API Testing

Postman is a popular tool for testing APIs. You can use it to send requests to your API endpoints and receive responses. Create a new collection in Postman and add requests for each CRUD operation using the appropriate HTTP methods.

Writing Test Cases with jest and supertest

jest is a powerful testing framework, and supertest is a library for testing HTTP assertions. Install them using the following commands:

npm install jest supertest --save-dev

Create a directory named tests in your project and add a test file (e.g., api.test.js) inside it. Here’s an example of a test suite for testing the CRUD operations:

const request = require('supertest');
const app = require('../app'); // Update the path based on your project structure

describe('API Endpoints', () => {
  it('should get all tasks', async () => {
    const response = await request(app).get('/api/tasks');
    expect(response.status).toBe(200);
    expect(response.body).toHaveLength(2); // Adjust the expected length
  });

  // Add similar test cases for other CRUD operations
});

To run the tests, add the following script to your package.json:

"scripts": {
  "test": "jest"
}

Then, run npm test in your terminal to execute the tests.

Conclusion:

In this blog, we have covered the basics of setting up an Express application, defining routes for CRUD operations, error handling, validation, and testing. RESTful APIs play a crucial role in modern application development, and the knowledge you’ve gained here will serve as a solid foundation for creating more advanced and sophisticated APIs in the future. Happy coding!

Finally, for more such posts, please follow our LinkedIn page- FrontEnd Competency.

Alka Vats

Alka Vats

Alka Vats is a Software Consultant at Nashtech. She is passionate about web development. She is recognized as a good team player, a dedicated and responsible professional, and a technology enthusiast. She is a quick learner & curious to learn new technologies. Her hobbies include reading books, watching movies, and traveling.

Leave a Comment

Your email address will not be published. Required fields are marked *

Suggested Article

%d bloggers like this: