Arch Tutor

Lesson 2

Clients, Servers & Requests

Learn how clients and servers communicate through HTTP requests and responses — the foundation of the web.

25 min read · Beginner

The conversation that powers the web

Every time you load a webpage, check your email, or post a message, two programs are having a structured conversation. One program — the client — asks for something. Another program — the server — listens, processes the request, and sends back a response. This pattern is so fundamental that most of the internet runs on it.

As a developer, understanding this request-response cycle is your entry point to system architecture. Before you worry about databases, caches, or load balancers, you need a clear mental model of how a single client talks to a single server. Everything else is an extension of this basic idea.

Client-server separation

The client and server are separate programs, often on separate machines, connected by a network:

Client-server separation

request

forward

read/write

response

deliver

Client

Internet

Server

Database

The client never touches the database directly. All data flows through the server.

This separation is the foundation of web security and scalability. You can update the server without forcing users to reinstall an app. You can add more servers without changing the client at all.

Clients: the askers

A client is any program that initiates requests. When you type a URL into Chrome, the browser is the client. When your phone app fetches your feed, the app is the client. Even a server can act as a client when it calls another service — but the role is always the same: send a request and wait for a response.

Clients are responsible for presenting information to users and capturing their input. They should stay “thin” when possible — meaning they handle display and interaction, while the server handles business logic and data access.

Here is what a simple client request looks like in JavaScript:

Browser fetch examplejavascript
const response = await fetch("https://archtutor.dev/api/lessons");
const lessons = await response.json();
console.log(lessons);
The browser is the client — it sends a request and waits for the server to respond.

Servers: the responders

A server is a program that waits for incoming requests, processes them, and returns responses. It runs continuously on a machine (physical or virtual) that has a known address on the network. Web servers like NGINX or application servers like Node.js, Python’s Gunicorn, or Java’s Tomcat all play this role.

Servers enforce rules: Is this user allowed to do this? Is the data valid? What should happen if something goes wrong? Keeping these rules on the server — rather than trusting the client — is a core security principle.

HTTP methods at a glance

HTTP methods tell the server what kind of action the client wants:

MethodPurposeSafe?Idempotent?Example
GETRead dataYesYesFetch a user profile
POSTCreate new resourceNoNoSubmit a form, create order
PUTReplace entire resourceNoYesUpdate all fields of a profile
PATCHPartial updateNoNoChange just the email field
DELETERemove resourceNoYesDelete a todo item
HEADLike GET but no bodyYesYesCheck if resource exists

Safe means the request does not change server state. Idempotent means calling it multiple times has the same effect as calling it once. These properties matter for retries — if a network blip causes a duplicate PUT, you will not accidentally create two resources.

Request anatomy

Every HTTP request has three parts:

POST /api/todos HTTP/1.1          ← Request line (method, path, version)
Host: archtutor.dev               ← Headers (metadata)
Content-Type: application/json
Authorization: Bearer eyJhbG...   ← Auth token

{"title": "Learn architecture"}   ← Body (optional payload)

Here is the same request and its response as raw text — exactly what travels over the wire:

HTTP requesthttp
POST /api/todos HTTP/1.1
Host: archtutor.dev
Content-Type: application/json
Authorization: Bearer eyJhbG...

{"title": "Learn architecture"}
HTTP responsehttp
HTTP/1.1 201 Created
Content-Type: application/json
Location: /api/todos/42

{"id": 42, "title": "Learn architecture", "done": false}

Key headers to know:

HeaderPurpose
HostWhich server to route to (required)
Content-TypeFormat of the body (application/json, text/html)
AuthorizationCredentials (Bearer token, API key)
AcceptWhat response formats the client can handle
CookieSession identifier stored by the browser

Response anatomy

The server replies with a similar structure:

HTTP/1.1 201 Created              ← Status line
Content-Type: application/json
Location: /api/todos/42

{"id": 42, "title": "Learn architecture", "done": false}

Status codes are grouped by meaning:

RangeMeaningExamples
2xxSuccess200 OK, 201 Created, 204 No Content
3xxRedirect301 Moved, 304 Not Modified
4xxClient error400 Bad Request, 401 Unauthorized, 404 Not Found
5xxServer error500 Internal Error, 503 Service Unavailable

HTTPS and why it matters

HTTP sends everything in plain text. Anyone on the same Wi-Fi network can read passwords, tokens, and personal data. HTTPS wraps HTTP in TLS encryption — the “S” stands for Secure.

HTTP:  Client ----[readable text]----> Server
HTTPS: Client ----[encrypted blob]----> Server

In practice:

  • Always use HTTPS in production — browsers mark HTTP sites as “Not Secure”
  • TLS also verifies server identity via certificates, preventing impersonation
  • The TLS handshake adds a small latency cost (~1 round trip), but CDNs and HTTP/2 minimize this

Never send passwords or API keys over plain HTTP. Treat HTTP as acceptable only for local development.

Stateless vs stateful

Stateless servers do not remember previous requests. Each request carries all the context needed (usually via tokens or cookies). This is the default for REST APIs and makes horizontal scaling easy — any server can handle any request.

Stateful servers keep session data in memory. If Server A handled your login, only Server A knows you are authenticated. This requires sticky sessions or shared session storage when you scale to multiple servers.

ApproachProsCons
Stateless (JWT tokens)Easy to scale, no server memoryTokens harder to revoke instantly
Stateful (server sessions)Easy to invalidate sessionsNeeds sticky sessions or Redis

Most modern apps use stateless APIs with JWT or session tokens stored in Redis for the best of both worlds.

The HTTP request lifecycle

HTTP (Hypertext Transfer Protocol) is the language clients and servers use to communicate on the web. Let’s walk through what happens when you visit a website:

HTTP Request Flow

DNS Lookup

The client resolves the domain name to an IP address.

archtutor.dev  →  DNS Server  →  192.0.2.42

When you type archtutor.dev into your browser, it first asks a DNS (Domain Name System) server: what IP address belongs to this name? DNS is like a phone book for the internet. The answer might be something like 192.0.2.42 — the actual location of the server. DNS results are cached at multiple levels (browser, OS, ISP) to speed up repeat visits.

Step 1 of 6

In practice

When debugging a slow page load, work through the lifecycle above. Is DNS slow? Is TLS taking too long? Is the server returning a 500? Tools like browser DevTools (Network tab) and curl -v show you exactly where time is spent.

Key takeaways

  • Clients initiate requests; servers respond — this is the fundamental pattern of the web
  • HTTP is the protocol that structures these conversations with methods, headers, and status codes
  • Keep business logic on the server — clients can be modified by users and should not be trusted
  • HTTPS encrypts traffic — always use it in production
  • Stateless servers scale better — carry context in tokens, not server memory
  • Every web interaction follows a request-response cycle, even when it feels instant

Common mistakes

  • Assuming the client and server are always separate machines — during local development, both often run on your laptop, but the roles remain distinct
  • Ignoring HTTP methods — using GET for actions that change data can cause bugs and security issues
  • Not handling error status codes — a 500 error from the server means something broke; show a helpful message
  • Sending sensitive data over HTTP — use HTTPS everywhere outside localhost

Go deeper