Most API developers nail the happy path. But HTTP is a protocol with decades of baggage, and some edge cases can silently break your API in production.
Here are 5 HTTP edge cases every API developer should know about — with code examples and fixes.
1. Duplicate HTTP Headers
The HTTP spec (RFC 9110) allows multiple headers with the same name. Most frameworks merge them — but not always the way you expect.
// Express.js example
// If a client sends: X-Custom: foo AND X-Custom: bar
app.get('/test', (req, res) => {
console.log(req.headers['x-custom']);
// Output: 'foo, bar' (comma-joined string)
});
The trap: If you're parsing a header value and expecting a single string, duplicate headers will silently corrupt your logic.
Fix: Always validate header values. If you expect a single value, take the first one explicitly:
const value = req.headers['x-custom']?.split(',')[0]?.trim();
2. Empty Body on 204 No Content... or Is It?
HTTP 204 means "no content" — but nothing stops a buggy client or proxy from sending a body with it. Conversely, some frameworks accidentally attach a body to 204 responses.
// This is technically invalid but common
res.status(204).json({ message: 'deleted' }); // BAD!
// Correct
res.status(204).end();
The trap: Some HTTP clients will throw if they try to parse a body from a 204. Others silently ignore it.
Fix: Never send a body with 204. If you need to return data after deletion, use 200 instead.
3. Transfer-Encoding: chunked vs Content-Length
When your API streams data, it uses Transfer-Encoding: chunked. But if both Content-Length AND Transfer-Encoding are present, the spec says Transfer-Encoding wins.
HTTP/1.1 200 OK
Content-Length: 50
Transfer-Encoding: chunked
# The client SHOULD ignore Content-Length
The trap: Some proxies strip Transfer-Encoding but keep Content-Length, causing truncated responses.
Fix: Never set both. If streaming, let your framework handle Transfer-Encoding and omit Content-Length:
app.get('/stream', (req, res) => {
res.setHeader('Content-Type', 'application/json');
// Don't set Content-Length when streaming!
stream.pipe(res);
});
4. HEAD Requests Must Match GET (But Return No Body)
A HEAD request should return the exact same headers as a GET — including Content-Length — but with an empty body. Many APIs get this wrong.
// Common mistake: different response for HEAD
app.head('/api/users', (req, res) => {
res.status(200).end(); // Missing Content-Length!
});
// Correct: compute the same response, skip the body
app.head('/api/users', async (req, res) => {
const users = await getUsers();
const body = JSON.stringify(users);
res.set('Content-Length', Buffer.byteLength(body));
res.status(200).end();
});
The trap: CDNs and caches use HEAD to validate cached responses. If your HEAD and GET headers don't match, caching breaks silently.
5. The 301 Redirect Method Switch
When a client receives a 301 Moved Permanently redirect, browsers historically change the method from POST to GET. Your POST data disappears.
# Client sends POST /old-endpoint
# Server responds: 301 Location: /new-endpoint
# Browser follows up with: GET /new-endpoint <-- METHOD CHANGED!
Fix: Use 307 Temporary Redirect or 308 Permanent Redirect — these preserve the original HTTP method:
app.post('/old-endpoint', (req, res) => {
res.redirect(308, '/new-endpoint'); // POST stays POST
});
Quick Reference
| Edge Case | Risk | Fix |
|---|---|---|
| Duplicate headers | Corrupted values | Split and take first |
| 204 with body | Client parsing errors | Never send body on 204 |
| Chunked + Content-Length | Truncated responses | Use one, not both |
| HEAD ≠ GET headers | Broken caching | Match headers exactly |
| 301 method switch | Lost POST data | Use 307/308 instead |
Wrapping Up
HTTP seems simple until it isn't. These edge cases don't show up in tutorials, but they'll bite you in production — especially when proxies, CDNs, and diverse clients enter the picture.
Bookmark this as a quick reference. Your future self debugging a mysterious production issue will thank you.
Building APIs? Check out 1xAPI for production-ready API tools and services.
Top comments (0)