DEV Community

Cover image for Part 3 — Networking: From `fetch()` to Packets
Alok Kumar
Alok Kumar

Posted on

Part 3 — Networking: From `fetch()` to Packets

Most web developers use HTTP every day.

We write fetch(), call APIs, send requests, and handle responses. But lets understand what happens underneath those familiar abstractions.

When we write:

const response = await fetch("https://api.example.com/users");
Enter fullscreen mode Exit fullscreen mode

how does that request reach another computer? What happens before the server receives it? And why can a request be slow even when the application code is fast?

Here's what I've been learning.


The layers underneath HTTP

A simplified view of networking looks like this:

Application
    ↓
HTTP
    ↓
TCP
    ↓
IP
    ↓
Ethernet / Wi-Fi
    ↓
Network
Enter fullscreen mode Exit fullscreen mode

Each layer solves a different problem.

  • HTTP defines how applications structure requests and responses.
  • TCP provides a reliable, ordered byte stream.
  • IP helps packets travel between networks.
  • Ethernet/Wi-Fi handles communication over a local network link.

The important realization is that HTTP doesn't handle everything. It's one layer in a much larger system.

HTTPS adds TLS to protect HTTP traffic, typically over TCP. HTTP/3 is different: it runs over QUIC, which uses UDP.

IP addresses and ports

An IP address helps identify the network destination. A port identifies the transport endpoint associated with an application.

For example:

Server: 203.0.113.10

Port 22   → SSH
Port 443  → HTTPS
Port 5432 → PostgreSQL
Enter fullscreen mode Exit fullscreen mode

A few addresses worth understanding:

  • 127.0.0.1 — IPv4 loopback, referring to the local machine.
  • 192.168.x.x and 10.x.x.x — private IPv4 address ranges.
  • 0.0.0.0 — when used as a listening address, commonly means listening on all local IPv4 interfaces.

This last one is particularly useful in backend development. A server bound to 127.0.0.1 generally won't accept connections from other machines through its LAN interface, whereas binding to 0.0.0.0 allows it to listen on all local IPv4 interfaces, subject to firewall and network rules.

Routers forward packets between networks, while NAT often allows multiple devices with private addresses to share a public IPv4 address.

TCP: Reliable communication

IP alone doesn't guarantee that packets arrive or arrive in order. TCP provides reliability on top of IP.

A TCP connection typically begins with a three-way handshake:

Client                 Server

  SYN  ────────────────>

       <────────── SYN + ACK

  ACK  ────────────────>
Enter fullscreen mode Exit fullscreen mode

After establishing the connection, TCP uses sequence numbers, acknowledgements, and retransmissions to deliver an ordered stream of bytes.

It also uses:

  • Flow control to avoid overwhelming the receiver.
  • Congestion control to respond to network congestion.
  • Connection termination to close connections safely.

One important concept:

TCP gives you a reliable byte stream, not messages.

If an application sends HELLO and WORLD, the receiver isn't guaranteed to receive them as two separate chunks. It might read HELLOWORLD, or several smaller pieces.

TCP preserves byte order, not application-level message boundaries. Protocols such as HTTP define their own message structure.

DNS: From domain name to IP address

Humans use names like google.com, but network connections need an IP address.

DNS resolves domain names into records, including IP addresses.

google.com
     ↓
DNS resolver
     ↓
IP address
     ↓
Connection
Enter fullscreen mode Exit fullscreen mode

A recursive resolver may answer from its cache or query the DNS hierarchy to obtain the relevant record.

DNS records have a TTL (Time to Live), which controls how long a record may be cached. This reduces repeated lookup work, but it also explains why DNS changes may not be visible everywhere immediately.

Useful commands to explore this:

dig google.com
dig google.com A
dig google.com AAAA
Enter fullscreen mode Exit fullscreen mode

DNS helps discover the destination; it doesn't establish the connection itself.

HTTPS and TLS

Resolving a domain and establishing a TCP connection aren't enough if we want secure communication.

TLS adds encryption, integrity protection, and server authentication when certificate validation succeeds.

For a typical HTTPS connection over TCP:

DNS resolution
      ↓
TCP handshake
      ↓
TLS handshake
      ↓
HTTP request
      ↓
HTTP response
Enter fullscreen mode Exit fullscreen mode

This setup has a cost. But connection reuse, caching, and TLS session resumption can reduce repeated work.

HTTP/2 also introduced multiplexing, allowing multiple streams to share a TCP connection. HTTP/3 uses QUIC over UDP, providing independent streams that reduce the cross-stream blocking caused by TCP packet loss.

The HTTP methods and status codes remain familiar; the underlying transport has evolved.

What actually happens when we call fetch()?

Putting everything together, a simplified request lifecycle looks like this:

fetch("https://api.example.com/users")
                    ↓
             DNS resolution
                    ↓
           TCP connection
                    ↓
             TLS handshake
                    ↓
              HTTP request
                    ↓
          Network → Server
                    ↓
          Application processing
                    ↓
             HTTP response
                    ↓
              Client receives it
Enter fullscreen mode Exit fullscreen mode

This is a conceptual sequence. Existing DNS entries and reusable connections can skip some setup steps, and HTTP/3 follows a different connection-establishment path.

The server might also query a database or call other services before returning the response.

Latency isn't just server execution time

Suppose an API request takes 800 ms, but the server spends only 30 ms executing application code.

Where did the rest go?

Potentially:

  • DNS lookup
  • Connection establishment
  • TLS handshake
  • Network round trips
  • Packet loss and retransmissions
  • Queueing
  • Downstream service calls
  • Response transfer

This is why total request latency and application execution time are different things.

Understanding the networking layers gives us a better starting point for investigating slow requests instead of immediately blaming the application.

A few things to try

I found it more useful to inspect actual network behavior than to memorize protocol definitions.

curl -v https://example.com
dig example.com
ping example.com
traceroute example.com
ss -tan
Enter fullscreen mode Exit fullscreen mode
  • curl -v reveals useful connection, TLS, and HTTP details.
  • dig helps inspect DNS records and TTLs.
  • ping tests ICMP reachability, not HTTP availability.
  • traceroute attempts to reveal the path through network hops.
  • ss shows socket information and connection states.

Not every network responds to these diagnostic tools, so a failed ping or missing traceroute hop doesn't necessarily mean a service is down.

The goal is to connect what the tools show with what's happening underneath the request.


The mental model

Application
    ↓
HTTP
    ↓
TLS
    ↓
TCP / QUIC
    ↓
IP
    ↓
Network
    ↓
Remote server
Enter fullscreen mode Exit fullscreen mode

Each layer has its own responsibilities, failure modes, and performance characteristics.

A network request isn't a single operation. It's a chain of operations across multiple layers, often involving more than one machine.

And that leads to the next question.

When the request reaches the backend and the application asks a database for some data, how does the database actually find it? Why are some queries fast while others are slow?

That's where Part 4 — Databases + Storage begins.

Top comments (0)