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
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
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:
| Event | Purpose |
|---|---|
| data | Triggered whenever a chunk of request data arrives. |
| end | Triggered 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
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
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 Code | Meaning | Usage |
|---|---|---|
| 200 | OK | Successful request. |
| 201 | Created | Resource successfully created. |
| 400 | Bad Request | Invalid JSON or validation failure. |
| 404 | Not Found | Unknown route. |
| 500 | Internal Server Error | Unexpected server-side error. |
Common Mistakes
| Mistake | Recommended 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
Official Documentation
Node.js HTTP Module Documentation