Notifications

No notifications

/Phase 2

HTTP Fundamentals

HTTP β€” The Protocol of the Web

HTTP (HyperText Transfer Protocol) is how clients (browsers, apps) communicate with servers.

Request/Response Cycle

Client ──── Request ────> Server
  (GET /api/users)
  
Client <─── Response ──── Server
  (200 OK + JSON data)

HTTP Methods (Verbs)

MethodPurposeBody?Idempotent?
GETRead dataβŒβœ…
POSTCreate dataβœ…βŒ
PUTReplace dataβœ…βœ…
PATCHPartial updateβœ…βŒ
DELETERemove dataβŒβœ…

Status Codes

RangeMeaningCommon Codes
1xxInformational101 Switching Protocols
2xxSuccess200 OK, 201 Created, 204 No Content
3xxRedirect301 Moved, 304 Not Modified
4xxClient Error400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found
5xxServer Error500 Internal Server Error, 503 Service Unavailable

On this page

Detailed Theory

What HTTP Actually Is

Every time you load a webpage, hit "refresh", or tap a button in an app, your computer sends an HTTP request to a server, and the server sends back an HTTP response. That conversation β€” plain text over a network socket β€” is the entire web.

HTTP is stateless: each request stands alone. The server doesn't remember you between requests. That's why we invented cookies, sessions, and tokens.

A Request, in Plain Text

GET /api/users?page=1 HTTP/1.1   ← method, path, version
Host: api.example.com             ← headers (key: value)
Authorization: Bearer eyJhbG...
Accept: application/json
                                  ← blank line ends headers

A POST/PUT also has a body below that blank line:

POST /api/users HTTP/1.1
Content-Type: application/json
Content-Length: 45

{ "name": "Asha", "email": "a@b.com" }

A Response, in Plain Text

HTTP/1.1 200 OK                   ← status
Content-Type: application/json
Content-Length: 32

{ "users": [{ "id": 1 }] }

The status code tells you what happened. The body carries the data.

The Methods (Verbs)

MethodUse it forHas body?Idempotent?
GETRead a resourcenoyes
POSTCreate something / submityesno
PUTReplace a resource fullyyesyes
PATCHUpdate part of a resourceyesusually yes
DELETERemove a resourceusually noyes

*Idempotent* = doing it 5 times has the same effect as doing it once. POST creates a new row each call β€” not idempotent.

Status Codes You'll See Daily

RangeMeaningCommon ones
1xxInformational101 Switching Protocols (WebSocket)
2xxSuccess200 OK, 201 Created, 204 No Content
3xxRedirect301 Moved Permanently, 304 Not Modified
4xxClient error400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 409 Conflict, 422 Unprocessable, 429 Too Many Requests
5xxServer error500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable

Memory hook: 4xx = *you* messed up. 5xx = *server* messed up.

URL Anatomy

https://api.example.com:443/users/42?include=posts#section
\___/  \_____________/ \_/ \_____/ \___________/ \_____/
  
scheme     host        port  path     query string  hash

  • path: which resource (/users/42)
  • query: filters/options (?include=posts&page=1) β€” you read these on the server
  • hash: client-only, never sent to the server

Beginner Mistakes to Skip

1. Putting a body on a GET request. Most servers and proxies will silently drop it. Use the query string. 2. 200 OK for everything, including failures. Pick a real status code so clients can react properly. 3. POST for reads because "GET feels weird". Breaks caching, breaks tooling. 4. Missing or wrong Content-Type. The server tries to parse {...} as a form and you get undefined everywhere. 5. Trusting headers like X-User-Id from the client. Anyone can set those. Authenticate with cryptographically-signed tokens.

Intermediate: Headers Worth Knowing

HeaderPurpose
Content-TypeWhat the body actually is (application/json, text/html, multipart/form-data)
AcceptWhat the *client* would like back
AuthorizationCredentials (Bearer , Basic )
Cookie / Set-CookieBrowser-managed key-value store
Cache-ControlHow long this response can be cached
ETag / If-None-MatchConditional requests for cheap revalidation
LocationWhere a 201 / 3xx is pointing
Access-Control-Allow-OriginCORS β€” who can call you from a browser

Intermediate: Body Formats

# JSON β€” default for APIs
Content-Type: application/json
{ "name": "Asha" }

# URL-encoded form β€” classic <form> submit Content-Type: application/x-www-form-urlencoded name=Asha&email=a%40b.com

# Multipart β€” file uploads Content-Type: multipart/form-data; boundary=----XYZ ------XYZ Content-Disposition: form-data; name="avatar"; filename="me.png" Content-Type: image/png <binary bytes> ------XYZ--

Your server has to parse the right format β€” in Express that's express.json(), express.urlencoded(), or multer for files.

Intermediate: HTTPS, in One Paragraph

HTTPS is HTTP wrapped in TLS. The server presents a certificate, the client verifies it against trusted Certificate Authorities, and an encrypted tunnel is established. Inside the tunnel, it's regular HTTP β€” same methods, same headers. Modern browsers refuse most features over plain HTTP. In production, always HTTPS (free certs from Let's Encrypt or your platform).

Intermediate: CORS Crash Course

Browsers block JavaScript on yourapp.com from calling api.other.com *unless* the API responds with the right CORS headers:

Access-Control-Allow-Origin: https://yourapp.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true

For non-simple requests, the browser first sends a preflight OPTIONS request. Servers must answer it. The cors npm package handles all of this for you.

Intermediate: Cookies, Sessions, Tokens

  • Cookie: a small string the server tells the browser to remember and re-send on every request to that domain.
  • Session: server-side state keyed by a cookie's session ID.
  • JWT (JSON Web Token): a self-contained, signed token. Server doesn't need to remember it β€” it just verifies the signature.
Mix and match: Set-Cookie: token=; HttpOnly; Secure; SameSite=Lax is a popular modern combo.

Intermediate: Caching

Cache-Control: public, max-age=3600     ← cache anywhere for 1 h
Cache-Control: private, no-store        ← never cache (login pages)
ETag: "v3"                              ← fingerprint of the response
If-None-Match: "v3"                     ← client says "I have v3"
β†’ server replies 304 Not Modified, no body

Good caching is the cheapest performance upgrade you'll ever ship.

Advanced: HTTP/1.1 vs HTTP/2 vs HTTP/3

  • HTTP/1.1 β€” one request at a time per TCP connection (browsers open ~6 in parallel).
  • HTTP/2 β€” multiplexes many requests over one TCP connection, header compression. Big speedup, no app changes.
  • HTTP/3 β€” same model but built on QUIC (UDP-based). Survives network changes (Wi-Fi β†’ 4G) without reconnecting.
You rarely configure these directly β€” your reverse proxy (NGINX, Caddy, Cloudflare) handles them.

Advanced: Idempotency Keys

A payment POST that retries due to a network blip must not charge twice. Solution: client sends a unique Idempotency-Key header. The server stores the result against that key and replays it for any retries with the same key. Used by Stripe, Square, etc.

Advanced: Streaming & Server-Sent Events

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

data: {"msg":"hi"}\n\n data: {"msg":"again"}\n\n

An open HTTP response that the server keeps writing to. Perfect for live token streaming (LLM chat), notifications, dashboards — simpler than WebSockets when you only need server→client.

Advanced: WebSockets vs HTTP

WebSockets start as an HTTP request with Upgrade: websocket, then drop into a full-duplex binary protocol. Use them when you need two-way real-time (chat, multiplayer, collaborative editing). Otherwise prefer plain HTTP β€” easier to cache, log, and debug.

Practice Path

1. Open Chrome DevTools β†’ Network tab on any site. Click a request and identify the method, status code, and 3 headers you recognise. 2. Use curl -v https://httpbin.org/get and read the raw request/response. 3. With curl, send a JSON POST to https://httpbin.org/post with -H 'Content-Type: application/json' -d '{"a":1}' and inspect what the server saw. 4. Force a 304 by hitting any cacheable URL twice with curl --etag-save / --etag-compare.