Tutorials Ultimate Web Development Series › Chapter 7

What's a Backend? — HTTP, REST, and JSON in Plain English

WebChapter 7 of the Ultimate Web Development Series25 minApril 20, 2026Beginner

Welcome to Part 2 of the series. For six chapters you've lived inside the browser — HTML, CSS, JavaScript, the DOM, fetch(). Every time you called fetch('/api/users'), something on the other end answered. This is where we go meet that something.

This chapter is zero code. It's the vocabulary and mental model you need before Chapter 8 where you write your first Cloudflare Worker. By the end you'll know what "REST" actually means, why JSON beat every other data format, how HTTP status codes map to real situations, and how to design an API that's pleasant to use — before you touch a keyboard.

What a Backend Actually Is

A backend is just a program that listens for HTTP requests and sends HTTP responses. That's the whole definition. It doesn't have to be big, fancy, or in a data centre — it's any code that plays the "server" role in the browser-asks-server-answers loop you met in Chapter 1.

Loading diagram…

Figure 1 — A backend sits between clients (browsers, mobile apps) and the stuff they can't touch directly: your database, your secrets, third-party APIs like Stripe. It's the only place where "trusted code" runs.

Why have a backend at all? Three reasons a browser can't do the work:

  1. Shared data. Two users of your site need to see the same list of articles. That list has to live somewhere neither user owns — on a server.
  2. Secrets. Your Stripe API key, your database password, your OpenAI key. Put any of these in browser JS and anyone can steal them with View Source. The backend is the only place they're safe.
  3. Trust. The user can do anything with the page in front of them — edit the HTML, change JavaScript values, replay requests. The backend is where you enforce "is this user allowed to do this?"

Any time you need one of those three things, you need a backend.

Where Backends Run

Historically, a backend lived in a server room. Today "backend" can mean any of these:

| Where | What it looks like | When to use | |---|---|---| | Your laptop | node server.js on localhost:3000 | Development | | A VPS / VM | DigitalOcean droplet, AWS EC2 | Full control, ops overhead | | A container | Docker on Fly.io, Render, Railway | Modern "just deploy" | | Serverless function | AWS Lambda, Google Functions | Sporadic workloads | | Edge worker | Cloudflare Workers, Deno Deploy, Vercel Edge | Global latency, pay-per-ms |

We'll use Cloudflare Workers from Ch 8 onward. Same JavaScript language you learned in Ch 5, no server to rent, 100K free requests a day, runs in 200+ cities by default. A Worker is a backend — it's just a tiny one that deploys in two seconds and runs wherever the user is.

HTTP — A Refresher, Now That You Write It

You met HTTP in Chapter 1 from the browser's side. Now flip it: as a backend author, you read a request and produce a response.

A request your Worker will see:

POST /api/notes HTTP/1.1
Host: simpleappshipper.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOi…
Content-Length: 58

{ "title": "Groceries", "body": "milk, eggs" }

A response you'll produce:

HTTP/1.1 201 Created
Content-Type: application/json
Location: /api/notes/42

{ "id": 42, "title": "Groceries", "body": "milk, eggs" }

Four things from the request you'll read constantly as a backend author:

| Piece | What it tells you | |---|---| | Method (GET / POST / PUT / DELETE) | What the client wants to do | | Path (/api/notes, /api/notes/42) | Which resource | | Headers (Authorization, Content-Type) | Auth, content format, caching hints | | Body (JSON, form data, file bytes) | The payload for POST / PUT / PATCH |

Three things you'll set on every response:

| Piece | What it tells the client | |---|---| | Status code (200 / 201 / 400 / 401 / 404 / 500) | What happened | | Headers (Content-Type, Cache-Control, Set-Cookie) | How to interpret the body, how long to cache, how to auth next time | | Body (JSON, HTML, bytes) | The actual data |

Good API design is mostly about picking the right methods, paths, and status codes — and being consistent across every endpoint.

REST — A Convention, Not a Technology

"REST" (Representational State Transfer) is a naming convention for organising your API around resources. It's not a library, not a framework, not a protocol — it's a set of rules about what your URLs and methods should look like. Following them makes your API predictable without a manual.

The core idea: your URLs name things (nouns), and HTTP methods express what you want to do with them (verbs).

Loading diagram…

Figure 2 — REST at a glance: path names the resource, method says what to do with it. Four methods cover 95% of real APIs.

The canonical CRUD API

If you're building a "notes" feature, the REST template is:

| Method + path | What it does | Success status | |---|---|---| | GET /api/notes | List all notes (often paginated) | 200 OK | | POST /api/notes | Create a new note from the request body | 201 Created | | GET /api/notes/:id | Read one note | 200 OK | | PATCH /api/notes/:id | Update some fields of one note | 200 OK | | PUT /api/notes/:id | Replace one note entirely | 200 OK | | DELETE /api/notes/:id | Remove one note | 204 No Content |

That's it. Same pattern for /api/users, /api/posts, /api/orders — any resource in your app. Once your users learn the shape of one endpoint, they've learned all of them.

Path params vs query params

Two places to put data in a URL. They have different meanings:

GET /api/notes/42?include=tags&fields=title,body
         ↑                 ↑
    path param        query params

Rule of thumb: if it uniquely identifies a thing, make it a path param. If it shapes the response, make it a query param.

JSON — The Format That Won

Backends and browsers don't send each other HTML. For programmatic data, they use JSON — JavaScript Object Notation. A note in JSON:

{
  "id": 42,
  "title": "Groceries",
  "body": "milk, eggs",
  "tags": ["home", "shopping"],
  "createdAt": "2026-04-20T10:30:00Z"
}

Six types and that's all it has:

| Type | Example | |---|---| | String | "hello" | | Number | 42, 3.14, -1e10 | | Boolean | true, false | | Null | null | | Array | [1, 2, 3] | | Object | { "key": "value" } |

Why JSON won over alternatives like XML or binary formats:

The one footgun: JSON has no comments and no trailing commas. { "a": 1, } is invalid. Parsers will reject it. Learn to spot missing quotes and misplaced commas — they're 80% of your JSON debugging for the first month.

Status Codes — How You Tell the Client What Happened

The three-digit status on your response is a contract. Use the right ones and every client library works automatically. Use wrong ones and chaos follows.

Loading diagram…

Figure 3 — The status-code families. 2xx = done, 3xx = go somewhere else, 4xx = client's fault, 5xx = server's fault. The second and third digits refine the story.

Stateless — The Backend's Superpower

HTTP is stateless: every request arrives independently, and the server doesn't remember what happened in the last one. If a client wants "remember me," it has to send that memory on every request (via a cookie or a token).

This feels like a limitation but is actually the whole reason the web scales. Because no request depends on where the previous one was handled, any of your Worker instances — in Tokyo, Sydney, Dublin — can handle any request. There's no "session" stuck to a specific machine.

Practical consequences for you as a backend author:

Idempotency — The Word You'll Say Weekly

A method is idempotent if calling it N times has the same effect as calling it once. Why you care: when a client's network hiccups mid-request, it often retries. Idempotent methods can be retried safely; non-idempotent ones can't.

| Method | Idempotent? | |---|---| | GET | Yes (reading never changes state) | | PUT | Yes (replacing with the same value repeatedly = same result) | | DELETE | Yes (deleting an already-deleted thing is a no-op) | | PATCH | Depends (usually yes if you use "set to X"; no if you use "increment by 1") | | POST | No (creates a new thing each time) |

This is why POST /api/notes creates a note and PUT /api/notes/42 replaces one: PUT is retryable, POST isn't.

For POST endpoints where you need idempotency (like a payment), the pattern is an idempotency key — the client generates a unique ID and sends it in a header. If the server sees the same key twice, it returns the result of the first call instead of creating a duplicate. Stripe does this; you will too.

Designing a Clean API — A Worked Example

Let's design a tiny API from scratch. Say you're building a note-taking app. Requirements:

Draft the endpoints on paper first. Don't write code yet.

GET    /api/notes                 list my notes
GET    /api/notes?tag=home        list my notes tagged "home"
GET    /api/notes?q=milk          search my notes for "milk"
GET    /api/notes?page=2&per=20   paginate

POST   /api/notes                 create a new note
GET    /api/notes/:id             read one
PATCH  /api/notes/:id             update some fields
DELETE /api/notes/:id             delete one

# And since tags are a sub-concept:
GET    /api/notes/:id/tags        list tags on a note
POST   /api/notes/:id/tags        add a tag
DELETE /api/notes/:id/tags/:tag   remove a tag

A JSON shape for a note:

{
  "id": "nt_abc123",
  "title": "Groceries",
  "body": "milk, eggs, apples",
  "tags": ["home", "shopping"],
  "createdAt": "2026-04-20T10:30:00Z",
  "updatedAt": "2026-04-20T10:35:00Z"
}

A few design choices worth calling out:

That's the entire API design process. Write it out, criticise it, imagine clients using it, refine. When you're happy, then write the code. An hour on paper saves a week of refactoring.

Errors — The Shape Every Client Expects

When something goes wrong, a JSON error body helps the client handle it:

{
  "error": "validation_failed",
  "message": "title must be between 1 and 200 characters",
  "field": "title"
}

Three fields, same across every endpoint:

Combined with the right status code (400 for validation, 401 for auth, 404 for missing, 409 for conflicts, 500 for bugs), your client now knows both what went wrong and who should fix it.

Before You Touch a Keyboard — Checklist

Before writing any Worker in Ch 8, you should be able to answer these about your imagined API:

  1. What resources does it have? (nouns)
  2. What can you do with each? (verbs)
  3. What's the JSON shape of each resource?
  4. Which endpoints require auth?
  5. What's your pagination scheme?
  6. What error shape do you return?
  7. Where will the data live — a database, a third-party API, a file?

You can design a complete REST API on a napkin in 20 minutes. Everyone who later uses it will thank you for not designing it as you go.

Next Steps

You now have the vocabulary: client, backend, HTTP method, path, headers, body, status code, REST, JSON, stateless, idempotent. These are the words every backend tutorial assumes you know. You now know them.

Next:

  1. Take a rest. This chapter was theory; Ch 8 is all hands-on.
  2. Pick an app idea that needs a backend. A note-taking app, a tiny bookmark manager, a link-shortener, anything. Sketch its REST API on paper — resources, methods, error shapes.
  3. Read the next chapter — Ch 8: Your First Cloudflare Worker, where you deploy a real "hello world" API to the edge in 5 minutes, then grow it into a proper RESTful notes service over Chs 9 (database), 10 (storage), 11 (auth).
Ch 6: Project Study — Dissecting simpleappshipper.comCh 8: Your First Cloudflare Worker

Ship your apps faster

When you're ready to publish your Swift app to the App Store, Simple App Shipper handles metadata, screenshots, TestFlight, and submissions — all in one place.

Try Simple App Shipper
5 free articles remainingSubscribe for unlimited access