At the boundary between an HTTP server and a web framework, what does the server hand over, and what does the framework hand back?
answer
- transport below, application above
- one entry point registered at startup
- request in, response description out
- invoked once per request, not per connection
- completion signals the server to serialize
basics
~20 sThe server hands over one parsed request - method, target, headers, body stream and connection facts - plus a way to answer. The framework returns a status, headers and body, or writes them into the response handle.
solid answer
~40 sThe seam is a **callable contract**. At startup the framework registers a single entry point; for every request the server parses off the wire, it builds a request object and invokes that entry point once. Inbound the framework gets the method, the request target, the negotiated protocol version, the header fields, a body that is usually still an unread stream, and connection facts such as the peer address and whether the connection is secure. Outbound there are two common shapes: the entry point *returns* a response value (status, headers, body - or a future of one), or the server passes a *response writer* the framework sets status and headers on and writes bytes into. The framework never owns the socket: it produces a description of a response and the server encodes it.
go deeper
Remember the split: the server handles the network and parsing, the framework handles what the request means. Your code receives an already-parsed request and produces a response.
Be able to list what the request object carries at hand-off and to describe both answer shapes - returning a response value versus writing into a response handle - and say when the server considers the exchange complete.
Show that you can reason about the seam under load and under async: a future that never settles hangs a request silently, and anything the server rejects before hand-off will never reach your error handling or your request logs.
The value of this boundary is optionality - swapping the server, the protocol version or the execution model without touching application code. Weigh that against the leaks that do cross it: streaming semantics, timeouts and limits still have to be designed end to end.
## The seam in one sentence A web framework does not read the network. A **server** owns the listening socket, accepts connections, terminates transport security when the connection is encrypted, and parses each HTTP message off the wire. When it has a complete, well-formed request it builds a **request object** and calls one entry point that the framework registered at startup. That call is the **server adapter boundary**: below it everything is transport, above it everything is application. ## What crosses inbound The server passes a single value describing exactly one request: - the **method** and the **request target** - the path plus the raw query string, taken from the start line; - the **protocol version** that was actually negotiated for this exchange; - the **header fields**, as a collection looked up by name without regard to case; - the **body**, usually as a stream that has not been read yet; small bodies are sometimes already buffered; - **connection facts** that are not part of the HTTP message at all: the peer address, whether the connection is secure, which protocol was negotiated. ## What crosses back Frameworks differ here, and both shapes are common in production: | shape | how the framework answers | when the server serializes | |---|---|---| | return a response | the entry point returns status, headers and body, or a future of them | after the call returns, or after the future settles | | write into a handle | the server passes a response writer; the framework sets status and headers, then writes body bytes | as the framework writes | Many frameworks offer both: a return value for the ordinary case and access to the writer when a handler wants to stream a long response. Either way the framework produces a *description* of a response; the server encodes it onto the connection. ## Completion - when is the exchange over? The server must know when it may finish the response and decide what to do with the connection, so the contract has to define completion: 1. In a **blocking, thread-per-request** model, completion is simply the return of the call. 2. In an **asynchronous** model, the call returns almost immediately with a future, promise or continuation, and completion is that value settling. 3. For a **streamed** response, completion is the framework closing the response writer. This is why an asynchronous handler that forgets to complete its future produces a request that hangs with no thread blocked anywhere and nothing in the error log: the server is still waiting for the signal the seam defines as done, and will only give up when a timeout fires. ## What never crosses - **The socket and the connection lifecycle.** Whether the connection is reused for a further request or closed after the response is decided below the seam. - **Transport security.** Certificates, handshakes and cipher selection belong to the server or to a component in front of it; the framework at most receives a flag and a few attributes. - **Wire framing.** How the body was delimited on the connection is resolved below the seam; above it the body is just a stream of bytes. - **Requests the server already refused.** A message that violates a server limit, or that is malformed, is answered by the server itself - the entry point is never invoked, so no framework-level error handling shapes that response. ## Why the boundary is drawn exactly here Three payoffs justify the indirection: - **Portability.** A framework can run on several server implementations by writing one small adapter per server, with application code unchanged. The adapter's whole job is translating that server's parsed-request representation into the framework's, and the framework's response representation back. - **Testability.** Because the entry point is an ordinary callable, tests can synthesize a request object and invoke it directly - no port to bind, no connection to open, no timing. - **Protocol evolution.** Newer HTTP versions change how a message is carried, and much of that difference is normalized below the seam, so application code written against the request object mostly survives the change. Not everything normalizes: trailers, server-initiated streams and flow-control-sensitive streaming still show through. ## The one thing to keep straight One call, one request. The entry point is invoked once per **request**, not once per **connection**, even though several requests may travel over the same connection one after another. A framework that believed otherwise would have to do the server's job of deciding where one message ends and the next begins - which is exactly the work the seam exists to keep below it.
- Why is connection handling kept on the server side of the seam rather than given to the framework?Connection handling is protocol and platform work that every application would otherwise reimplement: accepting sockets, deciding on reuse, managing timeouts and concurrency. Keeping it below the seam lets one framework run on several servers and lets a server serve several frameworks, and it keeps application code free of socket lifetimes it has no useful opinion about.
- What does the seam look like when the handler is asynchronous?The entry point returns a future, promise or continuation instead of a finished response, and the server treats the settling of that value as completion. The request object and response handle must therefore stay valid after the initial call returns, which is why touching them once the exchange has completed is an error in asynchronous models.
- How does this contract make framework code testable without a network?Because the entry point is an ordinary callable over a request object, a test can build a request in memory, call it, and assert on the returned response. No port is bound and no connection is opened, so the tests are fast and deterministic - what they do not cover is everything the server does below the seam, such as limit enforcement and framing.
A hotel front desk takes the phone call and passes the guest a written message; the guest writes a reply and hands it back. The guest answers the content but never touches the phone line.
saying these in an interview costs you the question
- Thinks the framework opens and reads the network socket itself
- Says the entry point is called once per connection, not once per request
- Believes the framework parses raw request bytes into a start line and headers
- Assumes the full body is always in memory when the framework is invoked
- Treats transport security and connection reuse as framework responsibilities