Topic 14 of 18 · Node Expert

Topic 4 : Using REST

Lesson TL;DRTopic 4: Using REST 📖 7 min read · 🎯 intermediate · 🧭 Prerequisites: postmanconfiguration, workingwithpackagelockjsontolockthenodemodulesversions Why this matters Up until now, you've been writing ...
7 min read·intermediate·rest · express · node-js · axios

Topic 4: Using REST

📖 7 min read · 🎯 intermediate · 🧭 Prerequisites: postman-configuration, working-with-package-lock-json-to-lock-the-node-modules-versions

Why this matters

Up until now, you've been writing backend code that just sits there — it can't talk to anything outside itself. But real applications need to communicate: a React front-end needs data from the server, a mobile app needs to send user info, different services need to exchange information. That's exactly what REST APIs are for. In this lesson, we build a proper RESTful API from scratch using Node.js and Express, test it with Postman, and then connect a React client to it using Axios — so your backend finally has something to say to the world.

What You'll Learn

  • Understand the four core HTTP methods — GET, POST, PUT, DELETE — and what each one does
  • Build a fully functional RESTful API with Express, covering all CRUD operations
  • Test every route using Postman with real request bodies and status codes
  • Consume a REST API from a React application using Axios

The Analogy

Think of a REST API as a well-run post office in Vizag. Every package (resource) has a unique address (URL). When you want to see what's in a package, you send a GET slip. When you want to drop off a new package, you hand over a POST form. To replace what's inside an existing package, you file a PUT amendment. And when a package is no longer needed, you submit a DELETE request. The post office clerks (the server) never remember your previous visit — each transaction is completely self-contained — which is exactly what "stateless" means in REST.

Chapter 1: Introduction to REST

REST (Representational State Transfer) is an architectural style for designing networked applications. It relies on a stateless, client-server communication protocol — almost always HTTP — where each request from the client contains all the information the server needs to fulfill it.

Key HTTP Methods

  1. GET — Retrieve data from the server.
  2. POST — Send data to the server to create a new resource.
  3. PUT — Update an existing resource on the server.
  4. DELETE — Delete a resource from the server.

Each method maps cleanly to a CRUD operation (Create, Read, Update, Delete), and together they cover the full lifecycle of any resource your API exposes.

graph LR
    Client -->|GET /books| Server
    Client -->|POST /books| Server
    Client -->|PUT /books/:id| Server
    Client -->|DELETE /books/:id| Server
    Server -->|JSON response| Client

Chapter 2: Setting Up a RESTful API with Express

The class decided to build a simple RESTful API to manage a list of books — a fitting choice for a city that runs on knowledge.

Step 1: Set Up the Project

Create a new directory for the project and initialise a Node.js project, then install Express.

mkdir rest-api-demo
cd rest-api-demo
npm init -y
npm install express

Step 2: Create the Server File

Create server.js to handle all incoming HTTP requests. The in-memory books array serves as the data store for this demo.

server.js

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

app.use(express.json());

let books = [
    { id: 1, title: '1984', author: 'George Orwell' },
    { id: 2, title: 'Brave New World', author: 'Aldous Huxley' },
];

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

// GET a book by ID
app.get('/books/:id', (req, res) => {
    const book = books.find(b => b.id === parseInt(req.params.id));
    if (!book) return res.status(404).send('Book not found');
    res.json(book);
});

// POST a new book
app.post('/books', (req, res) => {
    const newBook = {
        id: books.length + 1,
        title: req.body.title,
        author: req.body.author
    };
    books.push(newBook);
    res.status(201).json(newBook);
});

// PUT to update a book
app.put('/books/:id', (req, res) => {
    const book = books.find(b => b.id === parseInt(req.params.id));
    if (!book) return res.status(404).send('Book not found');
    book.title = req.body.title;
    book.author = req.body.author;
    res.json(book);
});

// DELETE a book
app.delete('/books/:id', (req, res) => {
    const bookIndex = books.findIndex(b => b.id === parseInt(req.params.id));
    if (bookIndex === -1) return res.status(404).send('Book not found');
    const deletedBook = books.splice(bookIndex, 1);
    res.json(deletedBook);
});

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

Step 3: Run the Server

node server.js

The API is now running at http://localhost:3000. You can interact with it using Postman or cURL.

Chapter 3: Testing the RESTful API with Postman

the trainer walked the class through each HTTP method in Postman, one at a time.

Step 1: Test GET Requests

GET All Books

  • URL: http://localhost:3000/books
  • Method: GET
  • Send the request to retrieve all books. The response will be a JSON array containing both entries.

GET Book by ID

  • URL: http://localhost:3000/books/1
  • Method: GET
  • Send the request to retrieve the book with ID 1.

Step 2: Test POST Request

POST a New Book

  • URL: http://localhost:3000/books
  • Method: POST
  • Set the body type to raw / JSON and send:
{
    "title": "To Kill a Mockingbird",
    "author": "Harper Lee"
}

The server responds with 201 Created and the newly created book object, including its auto-assigned id.

Step 3: Test PUT Request

PUT to Update a Book

  • URL: http://localhost:3000/books/1
  • Method: PUT
  • Body:
{
    "title": "Animal Farm",
    "author": "George Orwell"
}

The server responds with the updated book object. The record at ID 1 is now "Animal Farm".

Step 4: Test DELETE Request

DELETE a Book

  • URL: http://localhost:3000/books/1
  • Method: DELETE
  • Send the request to delete the book with ID 1. The server returns the deleted book object as confirmation.

Chapter 4: Using Axios to Consume the RESTful API in React

With the API proven in Postman, the class turned to building a React client that talks to it automatically on page load, using the Axios HTTP library.

Step 1: Create a New React Project

npx create-react-app book-api-client
cd book-api-client
npm install axios

Step 2: Create a Component to Fetch and Display Data

Create a Books component that fetches the list from the API inside a useEffect hook and renders it.

src/components/Books.js

import React, { useState, useEffect } from 'react';
import axios from 'axios';

function Books() {
    const [books, setBooks] = useState([]);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);

    useEffect(() => {
        axios.get('http://localhost:3000/books')
            .then((response) => {
                setBooks(response.data);
                setLoading(false);
            })
            .catch((error) => {
                setError(error);
                setLoading(false);
            });
    }, []);

    if (loading) {
        return <div>Loading...</div>;
    }

    if (error) {
        return <div>Error: {error.message}</div>;
    }

    return (
        <div>
            <h1>Books</h1>
            <ul>
                {books.map((book) => (
                    <li key={book.id}>
                        {book.title} - {book.author}
                    </li>
                ))}
            </ul>
        </div>
    );
}

export default Books;

Step 3: Integrate the Component into the App

Wire the Books component into the root App component.

src/App.js

import React from 'react';
import './App.css';
import Books from './components/Books';

function App() {
    return (
        <div className="App">
            <header className="App-header">
                <h1>Book API Client</h1>
            </header>
            <Books />
        </div>
    );
}

export default App;

Step 4: Run the React Application

Make sure your Express server is still running on port 3000, then start the React dev server (it will pick a different port automatically):

npm start

Navigating to http://localhost:3001 (or whichever port CRA assigns) in a browser will display the list of books fetched live from the Express API.

🧪 Try It Yourself

Task: Add a PATCH /books/:id route to server.js that allows partial updates — meaning the caller can update only title, only author, or both, without overwriting the field they did not send.

Success criterion: Sending the following body to PATCH http://localhost:3000/books/2 should update only the title and leave the author unchanged:

{
    "title": "Island"
}

Starter snippet — drop this into server.js after the PUT route:

// PATCH to partially update a book
app.patch('/books/:id', (req, res) => {
    const book = books.find(b => b.id === parseInt(req.params.id));
    if (!book) return res.status(404).send('Book not found');
    // your logic here
    res.json(book);
});

🔍 Checkpoint Quiz

Q1. REST is described as "stateless." What does that mean in practice?

A) The server stores session data in memory between requests
B) Each request must contain all the information the server needs; no session state is kept server-side
C) The client cannot send any state in the request body
D) REST only works without cookies

Q2. Given this Express route handler:

app.post('/books', (req, res) => {
    const newBook = {
        id: books.length + 1,
        title: req.body.title,
        author: req.body.author
    };
    books.push(newBook);
    res.status(201).json(newBook);
});

What HTTP status code does a successful POST return, and why is 201 preferred over 200 here?

Q3. In the React Books component, why is axios.get(...) called inside a useEffect hook with an empty dependency array []?

A) To call the API every time a book is added
B) To prevent the component from rendering at all until data arrives
C) To run the fetch exactly once after the component first mounts
D) Because Axios requires useEffect to function correctly

Q4. You want to permanently remove the book with ID 3. Which Postman configuration is correct?

A) Method: PUT, URL: http://localhost:3000/books/3, body: { "delete": true }
B) Method: DELETE, URL: http://localhost:3000/books/3, no body required
C) Method: GET, URL: http://localhost:3000/books/delete/3
D) Method: POST, URL: http://localhost:3000/books/3, body: { "action": "delete" }

A1. B — Stateless means the server holds no memory of prior requests; every call is self-contained. This makes REST APIs easier to scale horizontally.

A2. 201 Created. HTTP 200 signals a generic success, but 201 specifically communicates that a new resource was created as a result of the request — more semantically precise and machine-readable by API consumers.

A3. C — An empty dependency array tells React to run the effect only once, right after the initial render (equivalent to componentDidMount). Without it, the effect would re-run on every render, causing an infinite fetch loop.

A4. B — The DELETE method on the resource URL is the correct RESTful approach. No request body is needed; the resource is identified entirely by its URL parameter.

🪞 Recap

  • REST is a stateless, HTTP-based architectural style where GET, POST, PUT, and DELETE map directly to read, create, update, and delete operations.
  • Express makes it straightforward to define routes for each HTTP method using app.get(), app.post(), app.put(), and app.delete().
  • app.use(express.json()) must be registered as middleware before any route that reads req.body, or the body will be undefined.
  • Postman lets you manually fire any HTTP method with a custom body and inspect the exact status code and JSON response your API returns.
  • Axios in a React component, called inside useEffect with [], is the standard pattern for fetching data from a REST API on component mount.

📚 Further Reading

Like this topic? It’s one of 18 in Node Expert.

Block your seat for ₹2,500 and join the next cohort.