What is a REST API? Build Your First One Using Node.js and Express (2025 Guide)

09/07/2025

What is a REST API? Build Your First One Using Node.js and Express (2025 Guide)

This beginner-friendly tutorial explains what a REST API is and how it works. Follow step-by-step to build your first RESTful API using Node.js and Express. Learn how to set up routes, handle requests, and create a simple CRUD backend for web or mobile apps.

What is REST API? Build Your First One with Node + Express

Connecting applications: The backbone of modern web communication.

In today's interconnected digital world, applications rarely live in isolation. Your favorite mobile app talks to a server, a website fetches data from external services, and even parts of your own application might communicate internally. This seamless exchange of information is facilitated by APIs (Application Programming Interfaces).

Among the many API architectural styles, REST (Representational State Transfer) is by far the most popular and widely adopted for web services. It's the blueprint for how applications on the internet talk to each other. In this guide, we'll demystify what a REST API is and then walk through building your very first one using Node.js and the popular Express.js framework.

What Exactly is a REST API?

REST is an architectural style for designing networked applications. It's not a protocol like HTTP; rather, it uses HTTP's methods and conventions to enable communication between client and server.

At its core, a REST API is about resources. Everything is a resource (e.g., a user, a product, an order), and each resource is identified by a unique URL (URI).

Key Principles of REST:

  • Client-Server: Clear separation between the client (frontend) and the server (backend). They can evolve independently.
  • Stateless: Each request from a client to a server must contain all the information needed to understand the request. The server should not store any client context between requests.
  • Cacheable: Responses from the server can be cached to improve performance.
  • Uniform Interface: A consistent way for clients to interact with resources, regardless of their type or the underlying implementation. This is achieved through:
    • Resource Identification: Each resource has a URI (e.g., `/users`, `/products/123`).
    • Resource Manipulation through Representations: Clients send representations (e.g., JSON, XML) of a resource to the server to create or update it.
    • Self-descriptive Messages: Messages exchanged contain enough information for the recipient to understand how to process them.
    • Hypermedia as the Engine of Application State (HATEOAS): Resources include links to related resources, guiding the client on possible next actions (less common in simple APIs).

HTTP Methods (Verbs) and Their RESTful Use:

REST APIs leverage standard HTTP methods to perform actions on resources. This table summarizes their typical usage:

HTTP Method RESTful Action Example URI Description
GET Retrieve (Read) `/books`, `/books/123` Fetches one or more resources. Should be idempotent and safe.
POST Create `/books` Submits data to create a new resource. Not idempotent.
PUT Update (Replace) `/books/123` Replaces an existing resource with new data. Idempotent.
PATCH Update (Partial) `/books/123` Applies partial modifications to a resource. Not necessarily idempotent.
DELETE Delete `/books/123` Removes a resource. Idempotent.

Build Your First REST API with Node.js + Express

Prerequisites:

  • Node.js installed on your machine.
  • Basic understanding of JavaScript.
  • A code editor (like VS Code).
  • A tool to test API endpoints (e.g., Postman, Insomnia, or even `curl` in your terminal).

Step 1: Project Setup

Create a new directory for your project and initialize npm:


mkdir my-first-rest-api
cd my-first-rest-api
npm init -y
            

Now, install Express.js:


npm install express
            

Step 2: Create `server.js` (or `app.js`)

Create a file named `server.js` in your project root. This will be the entry point for your API.


// server.js
const express = require('express');
const app = express();
const PORT = 3000;

// Middleware to parse JSON bodies from incoming requests
app.use(express.json());

// Simple in-memory data store for demonstration
let books = [
    { id: '1', title: 'The Great Gatsby', author: 'F. Scott Fitzgerald' },
    { id: '2', title: '1984', author: 'George Orwell' },
    { id: '3', title: 'To Kill a Mockingbird', author: 'Harper Lee' }
];

// --- API Endpoints ---

// GET all books
app.get('/books', (req, res) => {
    res.status(200).json(books);
});

// GET a single book by ID
app.get('/books/:id', (req, res) => {
    const { id } = req.params;
    const book = books.find(b => b.id === id);

    if (!book) {
        return res.status(404).json({ message: 'Book not found' });
    }
    res.status(200).json(book);
});

// POST a new book
app.post('/books', (req, res) => {
    const { title, author } = req.body;
    if (!title || !author) {
        return res.status(400).json({ message: 'Title and author are required' });
    }

    const newBook = { id: String(books.length + 1), title, author };
    books.push(newBook);
    res.status(201).json(newBook); // 201 Created status
});

// PUT (full update) a book by ID
app.put('/books/:id', (req, res) => {
    const { id } = req.params;
    const { title, author } = req.body;
    const bookIndex = books.findIndex(b => b.id === id);

    if (bookIndex === -1) {
        return res.status(404).json({ message: 'Book not found' });
    }
    if (!title || !author) {
        return res.status(400).json({ message: 'Title and author are required for full update' });
    }

    books[bookIndex] = { ...books[bookIndex], title, author };
    res.status(200).json(books[bookIndex]);
});

// PATCH (partial update) a book by ID
app.patch('/books/:id', (req, res) => {
    const { id } = req.params;
    const updates = req.body;
    const bookIndex = books.findIndex(b => b.id === id);

    if (bookIndex === -1) {
        return res.status(404).json({ message: 'Book not found' });
    }

    // Apply partial updates
    books[bookIndex] = { ...books[bookIndex], ...updates };
    res.status(200).json(books[bookIndex]);
});

// DELETE a book by ID
app.delete('/books/:id', (req, res) => {
    const { id } = req.params;
    const initialLength = books.length;
    books = books.filter(b => b.id !== id);

    if (books.length === initialLength) {
        return res.status(404).json({ message: 'Book not found' });
    }
    res.status(204).send(); // 204 No Content for successful deletion
});


// Start the server
app.listen(PORT, () => {
    console.log(`Server is running on http://localhost:${PORT}`);
});
            
Explanation:
  • `app.use(express.json());`: This middleware is crucial. It tells Express to parse incoming requests with JSON payloads, making `req.body` available.
  • We define an in-memory `books` array. In a real application, this would be a database.
  • Each `app.METHOD('/path', callback)` defines a route.
  • `req.params`: Accesses route parameters (e.g., `:id`).
  • `req.body`: Accesses the request body (for POST/PUT/PATCH).
  • `res.status().json()`: Sends a JSON response with a specific HTTP status code.
  • `res.status(204).send()`: For DELETE, 204 means success with no content to return.

Step 3: Run Your API

Open your terminal in the project directory and run:


node server.js
            

You should see `Server is running on http://localhost:3000` in your console.

Step 4: Test Your API

Use a tool like Postman, Insomnia, or `curl` to test the endpoints:

Test 1: GET all books

  • Method: `GET`
  • URL: `http://localhost:3000/books`
  • Expected Response: JSON array of all books.

Test 2: GET a single book

  • Method: `GET`
  • URL: `http://localhost:3000/books/1`
  • Expected Response: JSON object of the book with ID 1.

Test 3: POST a new book

  • Method: `POST`
  • URL: `http://localhost:3000/books`
  • Headers: `Content-Type: application/json`
  • Body (JSON):
    
    {
        "title": "The Hitchhiker's Guide to the Galaxy",
        "author": "Douglas Adams"
    }
                        
  • Expected Response: JSON object of the newly created book (with a new ID) and 201 status.

Test 4: PUT (full update) a book

  • Method: `PUT`
  • URL: `http://localhost:3000/books/1`
  • Headers: `Content-Type: application/json`
  • Body (JSON):
    
    {
        "id": "1",
        "title": "The Great Gatsby (Updated)",
        "author": "F. Scott Fitzgerald"
    }
                        
  • Expected Response: Updated JSON object of the book with ID 1.

Test 5: DELETE a book

  • Method: `DELETE`
  • URL: `http://localhost:3000/books/2`
  • Expected Response: 204 No Content status.

Beyond the Basics: Best Practices

  • Meaningful URLs: Use nouns for resources (e.g., `/users`, `/products`), not verbs (`/getUsers`, `/createProduct`).
  • Use Proper HTTP Status Codes: 200 OK, 201 Created, 204 No Content, 400 Bad Request, 401 Unauthorized, 404 Not Found, 500 Internal Server Error, etc.
  • Error Handling: Provide clear, consistent error responses (e.g., JSON objects with error codes and messages).
  • API Versioning: Essential for evolving APIs without breaking existing clients (e.g., `/v1/books`, `/v2/books`).
  • Authentication & Authorization: For real-world APIs, you'll need to secure your endpoints (e.g., with JWTs, OAuth).
  • Database Integration: Replace the in-memory `books` array with a database (e.g., MongoDB with Mongoose, PostgreSQL with Sequelize/Prisma).
Remember: This example uses an in-memory array. Any changes you make via POST/PUT/DELETE will be lost when you restart the `node server.js` process.

Congratulations! You've just built your first REST API. This foundational knowledge is crucial for anyone looking to build modern web applications, mobile apps, or integrate disparate systems.

REST APIs are the communication standard of the web. Keep building, keep learning, and soon you'll be designing complex, efficient, and scalable APIs!

Happy API Building! 🛠️