Building an HTTP Server
The problem
A client's HTTP request needs something on the other end that listens on a socket, parses the raw bytes into a structured request, decides what to do, and writes a correctly formatted response back — every backend framework exists to make that loop convenient, but the loop itself is the actual job of a server.
Why now
HTTP fundamentals defined the protocol's shape; sockets and ports defined the low-level endpoint a server binds to. This topic is where those two combine into a running program — the first time 'backend' stops being an abstract idea and becomes a process listening on a port, actually answering requests.
Mental model
An HTTP server is a loop: accept a connection on a bound socket, read and parse an HTTP request from the raw bytes, run some code to decide a response, write a correctly formatted HTTP response back, repeat. Every framework's routing, middleware, and controllers are convenience layered on top of that one loop — the loop itself never goes away, it's just hidden.
Requires
- HTTP FundamentalsNetworking
A server's entire job is producing valid HTTP responses to valid HTTP requests; you need the protocol's structure already defined before writing code that speaks it.
- Sockets & PortsNetworking
A server must bind to a socket and port to accept incoming connections at all; this is the literal, low-level starting point of 'a server that's running.'
Unlocks
Used in
- Every backend framework (Express, Fastify, Django, Rails) — a convenience layer over this exact loop
- Understanding what a framework's app.listen(port) call is actually doing underneath
- Debugging 'connection refused' errors by checking whether a server process is actually bound and listening
- Writing minimal servers for testing or for services that don't need a full framework
Projects
- Build a minimal HTTP server using only your language's raw socket/HTTP APIs (no framework) that responds to GET / with a 200 and a JSON body
- Add basic routing to your minimal server (different responses for different paths) without using a framework's router
Examples
- app.listen(3000) in Express is a thin wrapper around binding a socket and starting the accept-parse-respond loop
- A server returning no response at all (hanging) usually means the code path never reached the point of writing a response back to the socket
Resources
Mastery checklist
- I can build a minimal HTTP server without a framework
- I can explain the accept-parse-respond loop every HTTP server implements
- I can explain what a framework's routing layer adds on top of the raw loop
- I can diagnose whether a 'connection refused' error means nothing is listening on the target port