Warming up the neural circuits...
By the end of this chapter you will:
HTTP is the only language the web speaks. If you know it cold, you read docs once and write code that works. If you don't, you'll spend your career chasing mystery bugs that turn out to be a missing header.
An HTTP request is a politely formatted text message. It has a method (what you want), a path (where), some headers (metadata), and an optional body (the payload).
POST /orders HTTP/1.1
Host: api.example.com
Content-Type: application/json
Authorization: Bearer eyJhbGc...
{"itemId": "sku_42", "quantity": 2}You can type that by hand into telnet on port 80 and a webserver will respond. The whole web is built on this format.
Every HTTP request starts with a method. Each method has a precise meaning. Pick the wrong one and you violate rules, rules, and a hundred years of tradition.
| Method | Use for | Safe? | ? |
|---|---|---|---|
GET | Read a resource | ✅ | ✅ |
POST | Create a new resource (or non-idempotent action) | ❌ | ❌ |
PUT | Replace a resource entirely | ❌ | ✅ |
PATCH | Modify part of a resource | ❌ | ✅ (should be) |
DELETE | Delete a resource | ❌ | ✅ |
HEAD | GET, but only headers (no body) | ✅ | ✅ |
OPTIONS | Ask "what can I do here?" — used by CORS | ✅ | ✅ |
Using GET to delete or create resources. Browsers, crawlers, link-previewers, and CDNs all happily call GET URLs unsolicited. If a GET /api/users/42/delete exists, Google Bot will delete user 42.
There are 60+ HTTP status codes. You need 15.
401 means "we don't know who you are." 403 means "we know who you are, and you can't." Mixing them up causes auth bugs no one can debug.
Headers are key-value pairs that say how to interpret the request or response. There are dozens. Here are the ones you'll meet daily:
Host — which virtual host on the serverAuthorization — credentials (Bearer <token> or Basic <base64>)Content-Type — the body's format (application/json, multipart/form-data)Accept — what formats the client can read backUser-Agent — what client is calling (browser, curl, your service)Cookie — session/auth cookiesX-Forwarded-For — added by proxies; the original client IPContent-Type — format of the bodyContent-Length — size in bytesSet-Cookie — server tells the browser to remember a valueCache-Control — caching rules (no-store, max-age=3600, public)Location — where to redirect (used with 3xx)Strict-Transport-Security — "always use HTTPS for this domain"Content-Security-Policy — frontend XSS defenseAnything you invent — convention is to prefix with X- (legacy) or just your-name-. Examples: X-Request-Id, Stripe-Signature.
Two ways to send credentials with every request:
Cookies. Set by the server with Set-Cookie. Browser auto-attaches them to every request to that domain. Good: invisible to JS if HttpOnly. Bad: subject to CSRF unless you set SameSite.
Authorization header. Client must read the token from somewhere and add Authorization: Bearer ... to each request. Good: no CSRF (the browser doesn't auto-send it). Bad: easier to leak if the client stores it in localStorage.
For browser-based apps, HttpOnly cookies are usually the safer choice. For mobile apps and server-to-server, tokens are simpler.
HTTPS = HTTP wrapped in TLS. TLS does three things:
What TLS does not do:
$ curl -v https://example.com 2>&1 | grep -E "TLS|subject:"
* TLSv1.3 (IN), TLS handshake, Server hello
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions
* TLSv1.3 (IN), TLS handshake, Certificate
* subject: CN=example.com
* TLSv1.3 (IN), TLS handshake, CERT verifyYou should know what each is and when to care.
Practical impact for backend devs: usually you write code the same way for all three. Your reverse proxy (nginx, Cloudflare) handles the wire format and translates.
| Mistake | Why it's wrong | What to do |
|---|---|---|
Returning 200 with {"error": "..."} | Frontends, monitoring, and retries all key off the status code | Return the actual HTTP error code (4xx/5xx) |
| Using POST for everything | No caching, no idempotency guarantees | Use GET for reads, the right verb for writes |
Authorization: <token> without Bearer prefix | Many servers strip the scheme; yours might not | Always include Bearer |
| Putting JWTs in URL query strings | Logged everywhere, leaks in referrers | Use Authorization header |
| Caching POST responses | They're never cached, even by you | Use GET for cacheable reads |
Production. Use 429 correctly with Retry-After headers. Use 503 with Retry-After during deploys. Clients that respect these will not retry-storm you.
Performance. Enable HTTP/2 at your reverse proxy. Set Cache-Control headers thoughtfully — public, max-age=31536000, immutable for fingerprinted assets, no-store for personalized data.
Security. Always set Strict-Transport-Security. Never accept HTTP for anything that matters. Don't log Authorization headers (a depressing number of services do).
curl -v to make a GET to https://httpbin.org/get. Read every line of the verbose output.curl to send a POST with a JSON body to https://httpbin.org/post. Check the echoed headers and json fields.curl -I (HEAD). Compare to a full GET.openssl s_client -connect example.com:443 to see the raw TLS handshake.curl --http1.1 and curl --http2 and compare the protocol negotiation.Beginner. What's the difference between 401 and 403? 401 = not authenticated. 403 = authenticated but not allowed.
Senior. When would you choose cookies over Authorization headers? When the client is a browser and you want HttpOnly, SameSite protection. Tokens make more sense for mobile or service-to-service.
Senior. Walk me through what happens when you hit a 502. The reverse proxy got an error from your origin. Could be: origin down, origin returned malformed HTTP, origin timed out, TLS handshake to origin failed. Knowing which one matters.
HTTP is a text protocol with methods, headers, status codes, and a body. Each piece has a precise meaning. HTTPS adds encryption, server authentication, and tamper detection — but does not make your app secure. Pick the right method, return the right status code, and respect the verbs and you'll write APIs that play well with every tool in existence.
Content-Type and Accept?HttpOnly important on cookies?