API Design

Foundations · Lesson 03

Layers & the narrow waist

Your API call rides on a stack of layers, each solving one problem and trusting the layer below. Understanding the stack — and the single skinny point everything funnels through — explains why the internet can be so diverse on top and bottom yet still interoperate everywhere.

⏱ 10 minDifficulty: corePrereq: Lesson 01

By the end you'll be able to

Why layers at all?

Sending bytes across the world is too big a problem to solve in one piece. So it's split into layers, like a postal system: you write a letter (content), put it in an envelope with an address (delivery), the post office routes it (logistics), and a truck carries it (physical transport). Each layer does one job and depends only on the agreed interface of the layer beneath — it doesn't care how that layer works. Swap the truck for a plane and the letter is unaffected. That's the same interface/implementation idea from Lesson 01, applied to the network itself.

The TCP/IP model (the one that runs the internet)

Application HTTP · gRPC · DNS — what your API speaks Transport TCP · UDP — reliability & ports Internet IP — addressing & routing (the narrow waist) Link Ethernet · Wi-Fi — the physical hop ▲ closer to your app ▼ closer to the wire
Four layers. Your data starts at the top, gets wrapped by each layer going down, travels, then is unwrapped on the way up at the other end.

OSI: the textbook seven-layer version

Interviews and textbooks often reference the OSI model, which splits the same idea into seven layers. You don't need to memorise all seven — just know it's a more granular map of the same territory, and how it lines up:

TCP/IP (practical)OSI (textbook)
ApplicationApplication · Presentation · Session
TransportTransport
InternetNetwork
LinkData Link · Physical
🎯 Interview angle

If asked "which layer does TLS / a load balancer / HTTP operate at?", reason from the stack: HTTP and TLS are application-ish (TLS sits just under HTTP), TCP/UDP and port-based load balancing are transport, IP routing is the internet layer. People say "Layer 4 vs Layer 7 load balancer" — that's just OSI transport (4) vs application (7). Knowing the stack lets you place any technology instantly.

The narrow waist: everything funnels through IP

Here's the elegant part. There are many things at the top (HTTP, gRPC, email, video, games) and many things at the bottom (Ethernet, Wi-Fi, fibre, 5G). But in the middle, almost everything funnels through one protocol: IP. Drawn out, the diversity-at-the-ends and singularity-in-the-middle forms an hourglass:

HTTP · gRPC · DNS · SMTP · RTP · QUIC · … IP Ethernet · Wi-Fi · fibre · 5G · … ← the narrow waist
Many protocols above and below, one in the middle. Anything that speaks IP can talk to anything else that speaks IP.

Why does this matter so much? Because the narrow waist decouples innovation at the two ends. Inventors of a new application protocol (say, QUIC) only have to run on top of IP — they don't need to care whether the user is on fibre or 5G. Builders of a new physical network only have to carry IP — they don't need to know whether it's a video call or an API request. One stable contract in the middle let the top and bottom evolve independently for decades. It's the interface/implementation principle operating at planetary scale.

✅ The lesson for your own designs

A stable, minimal "waist" in your own system — a small core API that many things depend on — gives you the same superpower: the layers above and below can change freely as long as the waist holds. This is why a clean, slow-changing contract is worth more than a clever, churning one.

⚠️ Common trap

Thinking layers are just academic trivia. They're a debugging map: "is the problem at the application layer (a 500 from my code), transport (connection refused / wrong port), or internet (can't route to the host)?" Naming the layer narrows the cause in seconds. Engineers who skip this guess randomly.

Under the hood: encapsulation — tracing a packet down and up the stack

When your application sends an HTTP request, each layer wraps the data from the layer above with its own header (and sometimes trailer). This is called encapsulation. On the receiving end, each layer strips its wrapper and hands the payload up. Here is the exact sequence for GET /v1/users/42 HTTP/1.1:

  1. Application (HTTP). Your code produces the request: a UTF-8 string starting with the request line, headers, blank line, and optional body. This is the HTTP message — pure text.
  2. Transport (TCP). The OS TCP stack breaks the HTTP message into segments. Each segment gets a TCP header (source port, destination port, sequence number, ACK number, flags, window size). The segment is now: [ TCP header | HTTP data ].
  3. Internet (IP). The TCP segment is handed to the IP layer, which prepends an IP header (source IP, destination IP, TTL, protocol=6 for TCP). The packet is now: [ IP header | TCP header | HTTP data ].
  4. Link (Ethernet). The IP packet is placed inside an Ethernet frame with a MAC-address header and a CRC trailer for error detection. The frame is now: [ Ethernet header | IP header | TCP header | HTTP data | CRC ].
  5. Physical. The frame is serialised to electrical signals / radio waves / photons and sent to the next hop (router or switch).

Traced example — the byte layout on the wire:

━━━ Ethernet frame ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Ethernet header  (14 bytes)
  dst_mac: aa:bb:cc:dd:ee:ff   ← MAC of the next router hop
  src_mac: 11:22:33:44:55:66   ← MAC of this machine's NIC
  ethertype: 0x0800              ← "payload is IPv4"

  ━━━ IPv4 packet ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  IP header  (20 bytes minimum)
    version: 4, IHL: 5 (20 bytes), TTL: 64
    protocol: 6                   ← TCP
    src_ip: 203.0.113.5           ← client
    dst_ip: 93.184.216.34         ← server

    ━━━ TCP segment ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    TCP header  (20 bytes minimum)
      src_port: 51000              ← ephemeral client port
      dst_port: 443                ← HTTPS
      seq: 1001, ack: 0, flags: PSH|ACK

      ━━━ HTTP message (application payload) ━━━━━━━━━━━━━━━━━━━━━━━━
      GET /v1/users/42 HTTP/1.1
      Host: api.example.com
      ...

Ethernet CRC  (4 bytes)          ← receiver checks for bit errors; discards frame if bad

On the receiving end the layers unwind in reverse: the NIC checks the Ethernet CRC and strips the Ethernet header; the IP layer checks the destination IP (drops if not for us) and strips the IP header; TCP reassembles segments in order, strips the TCP header, and delivers the HTTP bytes; the HTTP server parses the request line and headers. The application sees only: GET /v1/users/42 HTTP/1.1\r\nHost: api.example.com\r\n….

SENDER (down the stack) HTTP: GET /v1/users/42… TCP hdr | HTTP data IP hdr | TCP hdr | HTTP data Eth hdr | IP | TCP | HTTP | CRC wire RECEIVER (up the stack) Eth hdr stripped → IP packet IP hdr stripped → TCP segment TCP hdr stripped → HTTP message App reads: GET /v1/users/42…
Each layer at the sender wraps the payload from the layer above. At the receiver the process reverses: each layer checks its header, acts on it, and strips it before passing the remainder up.

How to debug & inspect it — which tool sees which layer

Each debugging tool speaks to exactly one layer. Choosing the right tool instantly narrows the search space. If ping fails, the problem is below the application layer — there is no point inspecting HTTP headers yet.

LayerToolWhat it checksClassic symptom it reveals
Physical / Linkping, ip link, ifconfigIs the network interface up? Can we reach the adjacent router? (ICMP echo)ping: unknown host or 100% packet loss → cable/NIC/driver problem
Internet (IP)ping host, traceroute host, ip routeCan packets reach the destination IP? Where do they stop?no route to host → routing/firewall; traceroute shows the hop where packets die
Internet (DNS)dig hostname, nslookup hostnameDoes the hostname resolve to the correct IP?NXDOMAIN → hostname wrong or DNS record missing; wrong IP → stale cache or wrong zone
Transport (TCP)nc -zv host port, telnet host port, ss -lntpIs something listening on that port? Can a connection be established?Connection refused → nothing listening on that port; timed out → firewall silently drops SYN
Application (HTTP)curl -v URL, httpie, browser DevToolsDoes the server return the right status, headers, and body?404 → wrong path; 401 → auth missing; CORS error → missing response headers
All layers (raw)tcpdump -i eth0 host X, WiresharkEvery packet, every byte — reads Ethernet frames and decodes each layerUnexpected RST → server reset; SYN with no SYN-ACK → firewall; retransmits → packet loss

A diagnostic walkthrough — "my API call fails; where is the problem?"

$ ping api.example.com PING api.example.com (93.184.216.34): 56 bytes → IP layer reachable $ dig api.example.com +short 93.184.216.34 → DNS resolves correctly $ traceroute api.example.com 1 192.168.1.1 1 ms → local gateway fine 2 10.0.0.1 8 ms … 93.184.216.34 → route complete $ nc -zv api.example.com 443 Connection to api.example.com 443 port [tcp/https] succeeded! → TCP + TLS port open $ curl -v https://api.example.com/v1/users/42 < HTTP/1.1 401 Unauthorized → problem is at the application layer # All layers below HTTP are fine; the issue is a missing Authorization header

Debug checklist — layer by layer:

  1. ping hostname — if this fails, the problem is at the IP or link layer; fix routing/DNS before anything else.
  2. dig hostname — confirm the name resolves to the expected IP; a cached stale record is a common gotcha after a server move.
  3. traceroute hostname — find the hop where packets stop; that is the firewall or dead router.
  4. nc -zv host port — confirm something is listening; if refused, the service is down or the port is wrong.
  5. curl -v URL — inspect HTTP-level behaviour; the status code tells you which layer owns the error (4xx = your request, 5xx = the server).
  6. If packets arrive but responses look wrong: tcpdump -i any -A host <ip> and port <port> to see the raw bytes at every layer.

🧠 Quick check

1. The main benefit of layering the network is:

Layering isolates concerns: each layer depends only on the interface below, so you can swap Wi-Fi for fibre, or HTTP/2 for HTTP/3, without rewriting the rest.

2. In TCP/IP, ports and the choice of TCP vs UDP belong to which layer?

The transport layer handles end-to-end delivery: TCP/UDP and port numbers that direct data to the right program. IP (internet layer) handles addressing/routing between machines.

3. The "narrow waist" of the internet refers to:

Many protocols sit above and below, but IP is the common waist. That one stable point in the middle decoupled innovation at both ends.

✍️ Drill: locate the failure by layer

Three separate incidents: (a) "connection refused on port 5432", (b) "no route to host", (c) "HTTP 500 with a stack trace". Name the layer each points to and what it suggests. Decide first.

Model answer: (a) Transport — the host is reachable but nothing is listening on that port (DB down or wrong port). (b) Internet — IP routing can't reach the machine at all (bad address, network/firewall, host down). (c) Application — the connection and routing worked fine; your code threw. Reading the layer tells you whether to check your code, your ports, or your network — without guessing.

Rubric: ✓ maps each symptom to the right layer ✓ explains what that layer being the culprit implies ✓ shows layering as a diagnostic tool, not trivia.

Key takeaways

Sources & further reading