Request Body & Payloads
Request Body & Payloads
Level 2 — HTTP Anatomy The actual data (like a JSON object, a file, or form inputs) sent inside an HTTP Request or returned in an HTTP Response.
1. Prerequisites
- HTTP Methods (Verbs) — Not all methods are allowed to have a body!
- JSON (JavaScript Object Notation) — The most common format for a payload.
2. Term Category
HTTP Standard / Data Transfer (Universal Standard): Request Body & Payloads is a fundamental concept in this technology stack. Level 2 — HTTP Anatomy
3. Explanation
(1) Design Motivation — "Why did we design this?"
If you want to read a user's profile, you can just put their ID in the URL (/users/5). But what if you are submitting a massive registration form with a username, password, biography, profile picture, and home address?
You cannot put all of that data into the URL. URLs have character limits, and URLs are saved in browser histories (so your password would be visible to anyone looking at your history!).
To solve this, HTTP allows you to attach a Body (also called a Payload) to your request. It is a secure, theoretically unlimited-size block of data sent "inside the envelope" of the HTTP message, completely hidden from the URL.
(2) Reality Metaphor
When you send a package in the mail:
- The URL is the address printed on the outside of the box.
- The Headers are the "Fragile" stickers and postage stamps on the outside.
- The Body (Payload) is the actual gift sitting inside the box.
(3) The Strict Rule: GET vs POST
POST,PUT,PATCH: These methods are designed to send data to the server, so they ALLOW a Body.GET,DELETE: These methods are designed to just point at a URL and say "Read this" or "Destroy this". According to the HTTP specification,GETrequests CANNOT have a Body. (If you try to attach a body to aGETrequest usingfetch(), the browser will throw a fatal error and crash your code).
(4) Code Examples
Sending a JSON Body
const userData = {
username: "chienteku",
password: "supersecretpassword123"
};
fetch('https://api.example.com/register', {
method: 'POST', // Must be POST/PUT/PATCH to have a body!
headers: {
'Content-Type': 'application/json' // Telling the server what's inside the box
},
// The Body MUST be converted to a raw string!
body: JSON.stringify(userData)
});
4. Common Mistakes & Pitfalls
Mistake 1: Trying to send a body in a GET request
The mistake: A developer has a very complex search filter (Price: $10-50, Color: Red, Size: M). They want to send this data to the server to get a list of products, so they put it in the body of a GET request.
Why it's wrong: The HTTP/1.1 specification explicitly forbids GET requests from having a body. fetch() enforces this strictly and will instantly throw a TypeError.
Solution: If you are reading data (GET), you must put all your filters into the URL as Query Parameters instead! If the data is truly too massive for a URL, you must compromise and use a POST request instead, even though you are technically just "reading" data.
Mistake 2: Attaching a Request Body to HTTP GET or DELETE Requests
The mistake: Sending a JSON payload inside a GET request body.
Why it's wrong: HTTP/1.1 and HTTP/2 specifications state that request bodies on GET requests have no defined semantics. Many proxies, firewalls, and CDNs drop GET request bodies completely.
Incorrect:
GET /api/search HTTP/1.1
Content-Type: application/json
{"query": "shoes"} // ❌ Proxies drop GET request bodies!
Fix:
GET /api/search?q=shoes HTTP/1.1 ; Pass parameters in query string or use POST for complex queries
Mistake 3: Failing to Enforce Payload Size Limits on Incoming Server Request Bodies
The mistake: Configuring backend body parsers without setting a maximum limit parameter.
Why it's wrong: Unrestricted request body parsers allow malicious clients to send 500MB JSON payloads, causing server out-of-memory crashes (Denial of Service).
Incorrect:
// Express without size limit
app.use(express.json()); // ❌ Vulnerable to payload memory crashes!
Fix:
// Enforce strict payload limit
app.use(express.json({ limit: '100kb' }));
5. Practice Exercises
Exercise 1: Streaming Request Body Chunk Accumulator & Max Size Guard
Scenario: A Node.js HTTP server parses incoming stream chunks, enforcing a strict maximum byte limit to prevent Memory Exhaustion Denial of Service.
Requirements:
- Write accumulateRequestBody(stream, maxBytes).
- Listen to 'data' chunks.
- Throw 413 Payload Too Large if byte length exceeds maxBytes.
Answer
Implementation
async function accumulateRequestBody(stream, maxBytes = 1_000_000) {
let totalBytes = 0;
const chunks = [];
for await (const chunk of stream) {
totalBytes += chunk.length;
if (totalBytes > maxBytes) {
const err = new Error("Payload Too Large");
err.statusCode = 413;
throw err;
}
chunks.push(chunk);
}
return Buffer.concat(chunks).toString("utf-8");
}
// Verification tests
async function* createMockStream(chunkList) {
for (const chunk of chunkList) {
yield Buffer.from(chunk);
}
}
accumulateRequestBody(createMockStream(["hello ", "world"]), 100).then(body => {
console.assert(body === "hello world", "Test 1 Failed");
});
accumulateRequestBody(createMockStream(["a".repeat(200)]), 100).catch(err => {
console.assert(err.statusCode === 413, "Test 2 Failed: Must throw 413 on size overflow");
});
Technical Explanation
- Streamed Payload Accumulation: HTTP request bodies are transmitted asynchronously as streams of data chunks.
- 413 Payload Too Large: HTTP status code 413 indicates request body exceeds server size limits.
- Memory DoS Protection: Enforcing byte limits prevents attackers from crashing servers with giant payload memory buffers.
Exercise 2: Request Body JSON Schema Validator
Scenario: An API endpoint validator verifies that incoming parsed JSON request bodies contain required fields and valid data types.
Requirements:
- Write validateBodySchema(bodyObj, requiredFields).
- Verify existence and non-null values for requiredFields.
Answer
Implementation
function validateBodySchema(bodyObj, requiredFieldsMap) {
if (!bodyObj || typeof bodyObj !== "object") {
return { valid: false, errors: ["Missing or non-object body"] };
}
const errors = [];
for (const [field, expectedType] of Object.entries(requiredFieldsMap)) {
const val = bodyObj[field];
if (val === undefined || val === null) {
errors.push(`Field '${field}' is required`);
} else if (typeof val !== expectedType) {
errors.push(`Field '${field}' must be of type ${expectedType}`);
}
}
return {
valid: errors.length === 0,
errors
};
}
// Verification tests
const schema = { name: "string", age: "number" };
const v1 = validateBodySchema({ name: "Alice", age: 30 }, schema);
console.assert(v1.valid === true, "Test 1 Failed");
const v2 = validateBodySchema({ name: "Alice", age: "thirty" }, schema);
console.assert(v2.valid === false && v2.errors.length === 1, "Test 2 Failed");
Technical Explanation
- Input Validation Principle: Never trust client inputs; always validate request body structure and types before processing.
- Schema Validation Contracts: Schema definitions enforce consistent data contracts between frontend and backend.
- 400 Bad Request Feedback: Returning clear validation error lists helps client developers fix bad request payloads.
Exercise 3: Raw Binary Octet-Stream Body Processor
Scenario: A file upload endpoint processes application/octet-stream binary request bodies, calculating SHA-256 checksums of the raw payload.
Requirements:
- Write processBinaryPayload(binaryBuffer, mockCrypto).
- Calculate hash of raw binary buffer.
- Return byte size and checksum.
Answer
Implementation
function processBinaryPayload(binaryBuffer, mockCrypto) {
if (!binaryBuffer || !Buffer.isBuffer(binaryBuffer)) {
return { error: "Expected Buffer payload" };
}
const checksum = mockCrypto
? mockCrypto.hash(binaryBuffer)
: `hash_${binaryBuffer.length}`;
return {
byteLength: binaryBuffer.length,
checksum,
type: "application/octet-stream"
};
}
// Verification tests
const buf = Buffer.from([0x00, 0x01, 0x02, 0x03]);
const res = processBinaryPayload(buf);
console.assert(res.byteLength === 4, "Test 1 Failed");
console.assert(res.type === "application/octet-stream", "Test 2 Failed");
Technical Explanation
- application/octet-stream: Standard MIME type for unformatted raw binary data transfers (files, images, compiled binaries).
- Binary Buffer Manipulation: Node.js Buffer represents fixed-length sequences of raw memory bytes.
- Payload Integrity Verification: Calculating checksums (SHA-256) verifies binary payload was not corrupted during transit.
6. Related Terms
- HTTP Headers — How you tell the server what format the body is in (e.g.,
Content-Type). - JSON (JavaScript Object Notation) — The format you must convert your payload into.
- Content-Type & MIME Types — Related concept: Content-Type & MIME Types.
- Query Parameters & Path Variables — Related concept: Query Parameters & Path Variables.
- URL Encoding (Percent-Encoding) — Related concept: URL Encoding (Percent-Encoding).
7. Key Takeaways
- The Body (Payload) is the actual data you are sending or receiving.
POST,PUT, andPATCHuse bodies to send data to the server.GETandDELETEare generally forbidden from having bodies.- You must convert your JavaScript objects into strings (via
JSON.stringify()) before putting them in the body. - Highly sensitive data (passwords, tokens) must ALWAYS go in the Body or Headers, never in the URL.