← Back to all tutorials

Handling POST Requests (& Middleware)

Handle POST requests to create new resources, understand Express middleware, and learn how request data flows through the middleware chain.

Handling POST Requests (& Middleware)

In this episode you will learn how to properly handle POST requests — receiving JSON data from the client, processing it, and sending back a response. You will also understand middleware — a core Express concept that processes requests before they reach your route handlers.

What Is Middleware?

Middleware functions run between the incoming request and the route handler. They have access to the request object, the response object, and a next() function that passes control to the next middleware or route handler.

Request → Middleware 1 → Middleware 2 → Route Handler → Response

Middleware Anatomy

function myMiddleware(req, res, next) {
    // Do something with req or res
    console.log('Request received:', req.method, req.url);
    next();  // Pass control to the next middleware/route
}
ParameterPurpose
reqThe request object — you can read or modify it
resThe response object — you can end the request or modify headers
nextA function that passes control to the next middleware in the stack

If you do not call next(), the request hangs — Express waits forever for the response. Always call next() unless you are sending a response.

Built-in Middleware

// Parse JSON request bodies
app.use(express.json());

// Parse URL-encoded form data
app.use(express.urlencoded({ extended: true }));

// Serve static files
app.use(express.static('public'));
MiddlewareWhat It Does
express.json()Parses JSON bodies and puts the result in req.body
express.urlencoded()Parses form submissions and puts the result in req.body
express.static()Serves files from a directory (HTML, CSS, images)

Custom Middleware

// Logging middleware
app.use((req, res, next) => {
    console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
    next();
});

// Output:
// [2024-01-15T10:30:00.000Z] GET /api/ninjas
// [2024-01-15T10:30:05.000Z] POST /api/ninjas

app.use() without a path applies the middleware to every request. With a path, it applies only to matching routes.

Handling a POST Request

// In routes/ninjas.js
router.post('/', (req, res) => {
    // req.body contains the parsed JSON data
    const { name, rank, available } = req.body;

    // Validate the data
    if (!name || !rank) {
        return res.status(400).json({
            error: 'Name and rank are required'
        });
    }

    // For now, just echo back the data
    // (we'll save to MongoDB later)
    res.status(201).json({
        message: 'Ninja created',
        ninja: { name, rank, available }
    });
});

Testing with Postman

POST http://localhost:3000/api/ninjas

Body (raw JSON):
{
    "name": "Ryu",
    "rank": 5,
    "available": true
}

Response: 201 Created
{
    "message": "Ninja created",
    "ninja": { "name": "Ryu", "rank": 5, "available": true }
}

Middleware Order

// This order matters!
app.use(express.json());    // 1. Parse body FIRST
app.use(loggerMiddleware);  // 2. Log the request
app.use('/api/ninjas', ninjaRoutes);  // 3. Handle routes

// If express.json() comes AFTER the routes,
// req.body will be undefined in your handlers!

Middleware runs in the order it is defined. Body-parsing middleware must come before route handlers, otherwise req.body will be undefined.

Third-Party Middleware

// CORS — allows requests from other domains
npm install cors

const cors = require('cors');
app.use(cors());

// Morgan — HTTP request logger
npm install morgan

const morgan = require('morgan');
app.use(morgan('dev'));
PackagePurpose
corsEnables Cross-Origin Resource Sharing (lets your React front-end call the API)
morganLogs HTTP requests with method, URL, status code, and response time
helmetSets security-related HTTP headers

Updated index.js

const express = require('express');
const ninjaRoutes = require('./routes/ninjas');

const app = express();

// Middleware
app.use(express.json());
app.use((req, res, next) => {
    console.log(req.method, req.url);
    next();
});

// Routes
app.use('/api/ninjas', ninjaRoutes);

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

Key Takeaways

  • Middleware functions run between the request and the route handler — they process, transform, or validate incoming data
  • Every middleware must call next() to pass control forward, or send a response to end the cycle
  • express.json() is essential — it parses the JSON body and puts it in req.body
  • Middleware order matters — body parsers must come before route handlers
  • POST requests send data in the request body; validate the data before processing
  • Return res.status(400) for bad input and res.status(201) for successful creation