📨 Processing POST Requests and JSON Body with the Node.js http Module

Introduction

HTTP POST requests are commonly used to send data from a client to a server. Unlike GET requests, where data is passed through the URL, POST requests typically include data in the request body. When using Node.js's built-in http module, the request body is received as a stream of data, which must be collected and parsed before it can be used.

Information

The http module does not automatically parse request bodies. Developers must read the incoming data stream and convert JSON into JavaScript objects manually.

Learning Objectives

  • Understand how POST requests work.
  • Read incoming request data using streams.
  • Parse JSON request bodies safely.
  • Handle invalid JSON gracefully.
  • Return appropriate JSON responses and HTTP status codes.

How a POST Request Works

🌐 Client Sends POST Request
đŸ“Ļ JSON Data Is Sent in the Request Body
📡 Server Receives Data in Chunks
🧩 Server Combines All Chunks
🔄 Parse JSON into a JavaScript Object
📨 Process Data and Send Response

Understanding the Request Stream

Incoming request data is streamed to the server in one or more chunks. Two important events are used while reading the request body:

EventPurpose
dataTriggered whenever a chunk of request data arrives.
endTriggered after all request data has been received.

Reading the Request Body

The following example collects all incoming chunks into a single string before processing the request.

Reading the request body

let body = "";

req.on("data", chunk => {
  body += chunk;
});

req.on("end", () => {
  console.log(body);
});

Parsing JSON Data

After receiving the complete request body, use JSON.parse() to convert the JSON string into a JavaScript object.

Parse JSON request body

req.on("end", () => {
  const data = JSON.parse(body);

  console.log(data);
});

Important

Invalid JSON causes JSON.parse() to throw an exception. Always wrap it in a try...catch block.

Building a Complete POST Endpoint

Processing POST requests

const http = require("http");

const users = [];

const server = http.createServer((req, res) => {

  if (req.url === "/users" && req.method === "POST") {

    let body = "";

    req.on("data", chunk => {
      body += chunk;
    });

    req.on("end", () => {

      try {

        const user = JSON.parse(body);

        users.push(user);

        res.writeHead(201, {
          "Content-Type": "application/json"
        });

        res.end(JSON.stringify({
          message: "User created successfully",
          data: user
        }));

      } catch (error) {

        res.writeHead(400, {
          "Content-Type": "application/json"
        });

        res.end(JSON.stringify({
          error: "Invalid JSON"
        }));

      }

    });

    return;
  }

  res.writeHead(404, {
    "Content-Type": "application/json"
  });

  res.end(JSON.stringify({
    error: "Route not found"
  }));

});

server.listen(3000, () => {
  console.log("Server running on port 3000");
});

Processing Flow

POST Request Received
Read Incoming Data Chunks
Combine into One String
Parse JSON
Valid JSON
Invalid JSON
Store or Process Data
Return 201 Created
Return 400 Bad Request

Example Client Request

HTTP POST request

POST /users HTTP/1.1
Host: localhost:3000
Content-Type: application/json

{
  "id": 1,
  "name": "Alice",
  "email": "alice@example.com"
}

Successful Response

201 Created

{
  "message": "User created successfully",
  "data": {
    "id": 1,
    "name": "Alice",
    "email": "alice@example.com"
  }
}

Invalid JSON Response

400 Bad Request

{
  "error": "Invalid JSON"
}

Using fetch() to Send a POST Request

Frontend example

fetch("http://localhost:3000/users", {
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    id: 1,
    name: "Alice",
    email: "alice@example.com"
  })
})
.then(response => response.json())
.then(data => {
  console.log(data);
});

Validating Incoming Data

After parsing the JSON, validate the required fields before processing the request.

Simple validation

if (!user.name || !user.email) {

  res.writeHead(400, {
    "Content-Type": "application/json"
  });

  return res.end(JSON.stringify({
    error: "Name and email are required"
  }));

}

HTTP Status Codes

Status CodeMeaningUsage
200OKSuccessful request.
201CreatedResource successfully created.
400Bad RequestInvalid JSON or validation failure.
404Not FoundUnknown route.
500Internal Server ErrorUnexpected server-side error.

Common Mistakes

MistakeRecommended Solution
Parsing JSON before the stream ends.Wait for the end event.
Ignoring invalid JSON.Use try...catch around JSON.parse().
Not validating request data.Check required fields before processing.
Missing Content-Type response header.Set application/json for JSON responses.

Best Practices

  • Always wait until the entire request body has been received.
  • Handle malformed JSON using try...catch.
  • Validate required fields before saving or processing data.
  • Return meaningful HTTP status codes and error messages.
  • Use Content-Type: application/json for JSON APIs.
  • Consider limiting the maximum request body size to protect against excessively large payloads.

Best Practice

For production applications, validate request bodies thoroughly, enforce reasonable payload size limits, sanitize user input, and separate request parsing, validation, and business logic into dedicated modules for better maintainability.

Official Documentation

Node.js HTTP Module Documentation

Summary

Summary

Processing POST requests with the Node.js http module involves reading the incoming request stream, combining data chunks, parsing the JSON body safely, validating client input, and returning appropriate JSON responses. Mastering these concepts provides a solid foundation for building RESTful APIs before moving to higher-level frameworks.