HTTP, deeply.
Every backend you'll ever build speaks HTTP. Every interview question about REST is really an HTTP question wearing a costume. Today we make this protocol obvious — methods, statuses, headers, idempotency — until reading any HTTP exchange feels native.
What HTTP actually is
HTTP (HyperText Transfer Protocol) is a text-based request/response protocol that runs on top of TCP. The client opens a connection, sends a request as plain text, the server sends a response as plain text, done. There is nothing magical about it.
# What gets sent over the wire (HTTP/1.1) — literally:
GET /users/42 HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer eyJhbGc...
# (blank line ends headers, then optional body)# And the response:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 84
{"id":42,"name":"Abhishek","email":"a@b.com","createdAt":"2026-05-04T..."}That's it. Text. You could type it by hand into a TCP socket. Tomcat parses these bytes into HttpServletRequest; Spring exposes them as method parameters. Everything you'll see in a controller is some abstraction over this raw text.
The anatomy of a request
- Request line — method + path + version
- Headers — key: value pairs, one per line
- Blank line — separates headers from body
- Body — JSON, form data, file bytes — whatever the
Content-Typesays
HTTP methods — the verbs
The method tells the server what kind of operation you want. Tutorials list them. Few explain the rules they obey.
| Method | Purpose | Idempotent? | Has body? |
|---|---|---|---|
| GET | Retrieve a resource | Yes | No |
| POST | Create a resource (or "do something") | No | Yes |
| PUT | Replace a resource entirely | Yes | Yes |
| PATCH | Partially update a resource | Often, not required | Yes |
| DELETE | Remove a resource | Yes | Usually no |
| HEAD | Like GET but no body in response | Yes | No |
| OPTIONS | What methods does this URL allow? (CORS uses this) | Yes | No |
Idempotency — the concept that decides everything
An operation is idempotent if calling it 10 times has the same effect as calling it once. DELETE /users/42 — once or ten times, user 42 ends up gone. POST /payments — every call charges again.
Networks fail. Your client sends a request, doesn't get a response — was it processed? If the operation is idempotent, retry is safe. If not (POST /payment), retry might double-charge.
This is why every payment API gives you an "idempotency key" header. It is also why your Webhook Relay project (Week 5) needs idempotency keys baked in.
Safe methods
A "safe" method does not modify server state. GET, HEAD, OPTIONS are safe. The others aren't. Crawlers and prefetchers rely on this — Google's bot will GET your URLs but never POST.
Status codes — the response language
2xx · Success
- 200 OK — generic success (GET, PUT, PATCH)
- 201 Created — POST that made a resource (include
Locationheader) - 204 No Content — success, no body (DELETE, sometimes PUT)
- 202 Accepted — request accepted, work happens later (async jobs)
3xx · Redirection
- 301 Moved Permanently — old URL, browsers/SEO will update
- 302 Found — temporary redirect
- 304 Not Modified — your cached version is still good (caching)
4xx · Client error (your fault, caller)
- 400 Bad Request — malformed request, validation failed
- 401 Unauthorized — actually means "Not Authenticated" (no/bad credentials)
- 403 Forbidden — authenticated but not allowed
- 404 Not Found — resource doesn't exist
- 409 Conflict — state conflict (duplicate email, version mismatch)
- 422 Unprocessable Entity — request well-formed but semantically invalid
- 429 Too Many Requests — rate limited
5xx · Server error (your fault, server)
- 500 Internal Server Error — uncaught exception
- 502 Bad Gateway — your reverse proxy got a bad response from upstream
- 503 Service Unavailable — overloaded or down
- 504 Gateway Timeout — upstream didn't respond in time
Despite the name, 401 means "you didn't authenticate" (no/bad token). 403 means "you authenticated, but you can't do this." Mixing them up is the most common API design mistake. Memorize: 401 = login problem, 403 = permission problem.
The headers you must know
| Header | What it does |
|---|---|
Content-Type | What format is the body? application/json, multipart/form-data, text/html |
Accept | What format will the client accept back? |
Authorization | Credentials. Usually Bearer <jwt> or Basic <base64> |
Cache-Control | How long can intermediaries cache this? no-cache, max-age=3600 |
ETag / If-None-Match | Conditional GET. Server responds 304 if unchanged. |
Location | On 201 Created or 3xx redirects — the new/target URL |
Set-Cookie / Cookie | Server-set cookies / client-sent cookies |
Origin / Access-Control-Allow-* | CORS — cross-origin browser security |
X-Forwarded-For | Real client IP when behind a load balancer |
HTTP is stateless — what that means
Each request is independent. The server does not "remember" you between requests. So how does your app know "this is Abhishek's 5th request and he's logged in"?
Two patterns:
- Sessions (cookies) — server stores state, hands the client a session ID via
Set-Cookie. Client sends it on every subsequent request. Server-side state, doesn't scale to many servers without a shared store. - Tokens (JWT) — server signs a token containing user info. Client sends it via
Authorization: Bearer .... Stateless — any server with the signing key can verify. Modern preference.
HTTP/1.1 → HTTP/2 → HTTP/3 — what changed
HTTP/1.1 (1997)
- Text-based wire format
- One request at a time per connection (head-of-line blocking)
- Browsers open 6 parallel connections to compensate
- Still the protocol you'll see in tutorials
HTTP/2 (2015) & HTTP/3 (2022)
- Binary framing — more efficient
- Multiplexed: many requests on one connection
- Server push (HTTP/2)
- HTTP/3 runs on QUIC (UDP) instead of TCP — better mobile networks
- Same semantics — methods, statuses, headers unchanged
For our purposes: application code doesn't change across versions. Your Spring controller looks identical. The transport gets faster.
HTTPS — the one-paragraph version
HTTPS is HTTP wrapped in TLS encryption. The TLS handshake exchanges keys; thereafter the HTTP messages are encrypted bytes on the wire. From your application's perspective, nothing changes — Spring sees the same requests. The TLS work happens at the load balancer or web server, often before your code runs.
CORS — the bug you'll hit on day one
Browsers block JavaScript from one origin (foo.com) reading responses from another (api.bar.com) — unless the server explicitly says it's OK. That permission is communicated via the Access-Control-Allow-Origin header.
If you ever see "blocked by CORS policy" in the browser console, your backend is not setting that header for the calling origin. In Spring Boot you fix it with @CrossOrigin or a global CorsConfigurationSource bean.
Every @RestController method is annotated with HTTP semantics: @GetMapping, @PostMapping, @RequestHeader, @RequestBody, @PathVariable. These annotations map directly to the parts of an HTTP request you saw above. Once you see HTTP clearly, every controller annotation has an obvious meaning.
Lock in today's learning
If anything is fuzzy, that section is a re-read.
- What's the difference between 401 and 403?
- What does idempotent mean, and which HTTP methods are idempotent?
- What's the difference between safe and idempotent?
- What goes in the
Content-TypevsAcceptheader? - How can a backend "remember" a user when HTTP is stateless?
- What is CORS and which header tells the browser cross-origin is allowed?
End of Day 8. Tomorrow: SQL essentials — joins, indexes, the relational mental model.