# HTTP & JSON: the API Building Blocks

> Every web API is made of two things: HTTP carries the message, JSON carries the data. Learn both well enough to read any API call with confidence.


---

# HTTP & JSON: the API Building Blocks

You keep hearing that an app "calls an API" - a request goes out, some data comes back, a screen fills
with results. It can feel like magic behind a curtain. It isn't. Almost every web API you'll ever touch
is built from exactly two things: **HTTP**, the way the message travels, and **JSON**, the way the data
is written down. Learn those two, and the curtain disappears - you'll be able to read an API call and
actually understand what's going on.

This guide is the calm walkthrough of those two building blocks. No framework, no SDK, no special tools - 
just `curl` in a terminal so you can see the raw request and the raw response with nothing in the way.

> ⏭️ Brand new to the whole idea of an API? Read [What an API Is](/guides/what-an-api-is) first, then
> come back here.

## How to read this

- **Want it to finally make sense?** Read in order. Phase 1 recaps the transport (HTTP), Phase 2 teaches
  the data format (JSON), and Phase 3 puts them together in real calls. Each phase builds on the last.
- **Already comfortable with HTTP?** You can skim [Phase 1](01-http-the-transport.md) and start at
  [Phase 2: JSON, the Data Format](02-json-the-data-format.md).

## The phases

1. **[HTTP, the Transport](01-http-the-transport.md)** - how a web API rides on HTTP: request and
   response, the methods (GET/POST/...), status codes, and headers - focused on the API angle. An
   annotated `GET` request, start to finish.
2. **[JSON, the Data Format](02-json-the-data-format.md)** - what JSON actually is (objects, arrays,
   strings, numbers, booleans, null), why it won, and how to read and write it. With the mental map from
   JSON to objects in your code, and the punctuation gotchas that bite everyone.
3. **[A Real API Call](03-a-real-api-call.md)** - the two halves together: `curl` a JSON API and read
   what comes back, then send a `POST` with a JSON body and the right headers. Annotated transcripts of
   both.

> This guide deliberately stays at "the two building blocks." The deeper mechanics of HTTP (caching,
> connections, cookies, HTTPS) live in [HTTP Explained](/guides/http-explained). How APIs are *organized*
> into resources and conventions is the job of [REST APIs Explained](/guides/rest-apis-explained), which
> this guide sets you up for.


---

# HTTP, the Transport

When an app "calls an API," what actually leaves your computer is an **HTTP request** - the same kind of
message your browser sends when you open a web page. The reply that comes back is an **HTTP response**.
That's the whole transport layer of a web API: one request out, one response back.

You can get the full story of HTTP - caching, connections, HTTPS, the lot - in
[HTTP Explained](/guides/http-explained). This phase is the *API-shaped* recap: just the parts you need to
read and reason about an API call. Hold these four ideas and you're set.

## The shape of every call: request → response

HTTP is a strict question-and-answer protocol. Your program asks one question (the request) and the server
gives one answer (the response). Nothing is "always on"; each call is a fresh, self-contained exchange.

A request has four parts, and so does a response:

```text
  REQUEST  (what you send)              RESPONSE  (what comes back)
  ──────────────────────────           ──────────────────────────
  GET /users/42  HTTP/1.1     ◄── line │ HTTP/1.1  200 OK          ◄── status line
  Host: api.example.com                │ Content-Type: application/json
  Accept: application/json    ◄ headers │ Content-Length: 57       ◄ headers
                                        │
  (usually empty for GET)     ◄── body  │ {"id":42,"name":"Ada"}   ◄── body (the data)
```

The request says **what you want** - a method (`GET`), a path (`/users/42`), some headers (extra notes),
and sometimes a body. The response says **what you got** - a status code (`200 OK`), its own headers, and
a body holding the actual data. Once you can spot those parts, you can read any HTTP exchange.

## Methods: the verb of the request

The **method** (also called the *verb*) is the first word of the request. It tells the server what kind of
action you intend. There are several, but a handful cover almost everything you'll do with an API:

| Method   | What you're asking for                          | Has a body? |
|----------|-------------------------------------------------|-------------|
| `GET`    | "Give me this thing." (read, never changes data)| No          |
| `POST`   | "Here's some data - create something with it."  | Yes         |
| `PUT`    | "Replace this thing with what I'm sending."     | Yes         |
| `PATCH`  | "Change part of this thing."                    | Yes         |
| `DELETE` | "Remove this thing."                            | Usually no  |

📝 **Terminology.** "Read-only" methods like `GET` are called **safe** - running one is not supposed to
change anything on the server. That's why your browser fetches a page (`GET`) freely but warns you before
re-sending a form (`POST`).

The method is half of *what a call does.* `GET /users/42` reads user 42; `DELETE /users/42` deletes them.
Same URL, completely different outcome - the verb is what changed.

## Status codes: the server's one-word verdict

Every response opens with a three-digit **status code** that summarizes how it went. You don't need to
memorize all of them - you need the ranges, because the first digit tells you the category:

```text
  2xx  ✓ It worked.            200 OK · 201 Created
  3xx  ↪ Go look elsewhere.    301 Moved Permanently · 304 Not Modified
  4xx  ✗ You messed up.        400 Bad Request · 401 Unauthorized · 404 Not Found
  5xx  ✗ The server messed up. 500 Internal Server Error · 503 Service Unavailable
```

When a call fails, the status code is the first thing you read, and the digit already tells you
**whose fault it is.** A `4xx` means your request was wrong (bad data, missing credentials, wrong URL) - 
*you* fix it. A `5xx` means the request was fine but the server broke - usually *not* something you can
fix from your side.

⚠️ **Gotcha.** A `200 OK` means HTTP delivered the response successfully - it does **not** guarantee the
data inside is what you wanted. Some APIs return `200` with a body like `{"error": "not found"}`. Always
read the body, not just the status. And the famous `404 Not Found` is about *this specific URL* - often a
typo in the path, not a dead server.

## Headers: the notes attached to the message

**Headers** are `Name: value` lines that carry metadata - information *about* the request or response,
separate from the actual data in the body. Think of them as the label on a parcel versus what's inside.

A few you'll meet constantly with APIs:

- `Content-Type: application/json` - "the body is JSON." Sent on a request to describe what you're
  uploading, and on a response to describe what's coming back.
- `Accept: application/json` - on a request, "please reply in JSON if you can."
- `Authorization: Bearer <token>` - "here's my key, proving I'm allowed to do this."

📝 **Terminology.** `application/json` is a **media type** (you'll also hear the old name *MIME type*) - a
standard label for a format. It's how both sides agree that the bytes in the body are JSON and not, say,
HTML or an image.

## Putting it together: an annotated GET

Here's a complete `GET` with `curl`. The `-i` flag tells `curl` to print the response headers and status
line, not only the body - so you can see all the pieces from the diagram above for real:

```console
$ curl -i https://api.example.com/users/42
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 57

{"id":42,"name":"Ada Lovelace","role":"admin"}
```
You sent a `GET` request for the path `/users/42`. The server answered `200 OK` - it worked. The
`Content-Type: application/json` header promises the body is JSON, and sure enough, the last line is the
data: a small JSON object describing user 42. The blank line is HTTP's way of saying "headers are done;
everything after this is the body."

Notice what you *didn't* have to do: no library, no setup. A request really is just a method, a URL, some
headers, and (sometimes) a body - and a response is a status code, headers, and a body. That's the entire
transport.

💡 **Key point.** HTTP is the envelope and the verb: it gets your message to the server and back, and the
method + status code tell you what was asked and how it went. But the envelope is almost empty without
something to *put in the body* - and for web APIs, that something is almost always JSON. That's next.

## Recap

1. Every API call is a **request** (method + URL + headers + optional body) and a **response** (status
   code + headers + body).
2. The **method** is the verb: `GET` reads, `POST` creates, `PUT`/`PATCH` change, `DELETE` removes.
3. The **status code** is the verdict: `2xx` worked, `4xx` you erred, `5xx` the server erred.
4. **Headers** are metadata notes; `Content-Type: application/json` is the one you'll see most.
5. A `200 OK` means *delivered*, not *correct* - always read the body too.


---

# JSON, the Data Format

In Phase 1, the response body held a line like `{"id":42,"name":"Ada Lovelace"}`. That's **JSON** - the
format almost every web API uses to write down the data it sends and receives. If HTTP is the envelope,
JSON is the letter written inside it.

The good news: JSON is small. There are only a handful of building blocks, and once you've seen them you
can read any JSON document, however large. By the end of this phase you'll look at a blob of JSON and see
structure, not soup.

## What JSON actually is

JSON (it stands for **JavaScript Object Notation**) is a way to write structured data as plain text.
"Structured" means it has shape - values nested inside other values - and "text" means it's just
characters you can read, type, and email. A program turns that text into data it can work with, and turns
its data back into that text to send. Nothing about it is secret or binary.

Here is a complete JSON document with every building block in it. Read it top to bottom - it's meant to be
readable:

```json
{
  "id": 42,
  "name": "Ada Lovelace",
  "active": true,
  "nickname": null,
  "roles": ["admin", "author"],
  "profile": {
    "city": "London",
    "followers": 1024
  }
}
```

You just read a full record about a user, and probably understood it without being told how - that
readability is the entire point of JSON. Now let's name the pieces.

## The building blocks

JSON is made of exactly these value types - that's the whole language:

| In the example above        | What it is | Looks like                          |
|-----------------------------|------------|-------------------------------------|
| `{ ... }`                   | **object** | a set of `"key": value` pairs in `{}` |
| `["admin", "author"]`       | **array**  | an ordered list in `[]`             |
| `"Ada Lovelace"`            | **string** | text in double quotes               |
| `42`, `1024`                | **number** | a plain number (no quotes)          |
| `true`                      | **boolean**| `true` or `false`                   |
| `null`                      | **null**   | "no value here on purpose"          |

📝 **Terminology.** An **object** is a collection of named fields - `"name": "Ada"` is a field whose
**key** is `"name"` and whose **value** is `"Ada"`. An **array** is an ordered list where position
matters, not names. Objects answer "what are this thing's properties?"; arrays answer "how many, and in
what order?"

The power comes from nesting: a value can itself be an object or array, so structures grow as deep as the
data needs. In the example, `profile` is a value that happens to be a whole object, and `roles` is a value
that happens to be an array. That's how JSON describes anything from a single number to an entire catalog.

## The mental map: JSON ↔ objects in your code

When your program receives JSON, it doesn't keep it as text - it **parses** it into the data structures
your language already has. The mapping is direct and predictable, which is exactly why JSON is comfortable
to work with:

```text
        JSON                       In your code (typical names)
   ┌──────────────┐
   │  object {}   │  ──────►   dict / map / object / hash
   │  array  []   │  ──────►   list / array
   │  string ""   │  ──────►   string
   │  number      │  ──────►   number / int / float
   │  true/false  │  ──────►   boolean
   │  null        │  ──────►   null / None / nil
   └──────────────┘
```

That table is the whole reason JSON feels natural in every language. A JSON object becomes a dictionary
(Python), an object (JavaScript), a map (Go) - whatever your language calls "named fields." Once the data
is parsed, you reach into it the normal way: ask the object for its `"name"` field, ask the array for its
first item. JSON is the *text on the wire*; in your code it's just ordinary data again.

📝 **Terminology.** Turning JSON text into in-memory data is **parsing** (or *deserializing*). Going the
other way - turning your data into JSON text to send - is **serializing**. Every language has a built-in
tool for both; you rarely do it by hand.

## Why JSON won

Before JSON, data on the web was often sent as **XML** - a tag-based format (`<name>Ada</name>`) that's
powerful but heavy and noisy to read and write. JSON made a different trade:

- **Human-readable.** You can open a JSON response and understand it with no tools - which makes debugging
  an API far less painful.
- **Language-neutral.** Despite the "JavaScript" in the name, JSON has no ties to any one language. Every
  major language reads and writes it, so two systems written in different languages can exchange data
  cleanly.
- **Small and simple.** Only six value types and a tiny grammar. Less to type, less to send, less to get
  wrong.

The trade-off it accepts: JSON has no built-in comments, no date type (dates travel as strings), and no
schema of its own. For most web APIs that's a price worth paying for how easy it is to read - which is why
it became the default.

## The punctuation gotchas

JSON's rules are strict and unforgiving, and two mistakes account for most "why won't this parse?"
moments. Name them now so they never cost you an hour later.

⚠️ **Gotcha - keys and strings must use double quotes.** Single quotes are not valid JSON, and keys are
*never* unquoted. This trips up everyone coming from JavaScript, where both are fine:

```text
   ✗ { name: 'Ada' }      ← single quotes, unquoted key - NOT valid JSON
   ✓ { "name": "Ada" }    ← double quotes on both the key and the string - valid
```

⚠️ **Gotcha - no trailing comma.** A comma *separates* items, so there must be nothing after the last one.
A leftover comma before a closing `}` or `]` is the single most common JSON error:

```text
   ✗ { "a": 1, "b": 2, }  ← trailing comma after the last pair - NOT valid JSON
   ✓ { "a": 1, "b": 2 }   ← no comma after the last pair - valid
```

If a parser ever rejects your JSON, check these two first - it's usually a stray comma or the wrong kind of
quote, not anything deep.

💡 **Key point.** JSON is structured text built from six value types, it maps cleanly onto the data
structures in any language, and it's strict about quotes and commas. That's everything you need to read the
data half of an API call. Now let's combine it with the HTTP half and make real calls.

## Recap

1. **JSON** is structured data written as plain, readable text.
2. The building blocks are **object** `{}`, **array** `[]`, **string**, **number**, **boolean**, and
   **null** - that's the whole language.
3. Values **nest**: an object or array can hold other objects and arrays, so JSON describes anything.
4. Your code **parses** JSON into normal data (objects → dicts/maps, arrays → lists) and **serializes**
   data back into JSON to send.
5. It won for being **human-readable, language-neutral, and simple.**
6. Two rules bite everyone: **double quotes only** (keys included) and **no trailing comma.**

## Try it yourself

Paste or edit JSON - it validates live, and you can format or minify it:

```playground-json
```

## Practice

```exercise
[
  {
    "type": "json",
    "task": "Type a JSON object with a \"name\" key of \"Ada\" and a \"roles\" array containing \"admin\" and \"author\", in that order.",
    "expected": { "name": "Ada", "roles": ["admin", "author"] },
    "hint": "Double quotes on every key and string value - JSON doesn't allow single quotes."
  }
]
```


---

# A Real API Call

You've met both halves: HTTP carries the message, JSON carries the data. Now you'll put them together the
way every real API call does - first reading data with a `GET`, then sending data with a `POST`. We'll use
`curl` so nothing hides the request or the response from you.

The examples use a public-style JSON API at `https://api.example.com` - a stand-in for the kind of endpoint
you'll meet in the wild. The *shapes* of the requests and responses are exactly what real APIs produce.

## Reading data: GET that returns JSON

The most common thing you'll ever do with an API is ask it for some data. That's a `GET`: name the thing
you want in the URL, and read the JSON that comes back.

```console
$ curl -i https://api.example.com/products/15
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 96

{"id":15,"name":"Mechanical Keyboard","price":129.99,"in_stock":true,"tags":["peripherals","input"]}
```
You sent a `GET` for `/products/15`. The server replied `200 OK` (it worked), and the
`Content-Type: application/json` header told you the body is JSON. The body is one JSON object describing
product 15 - and you can already read every field: a number `id`, a string `name`, a number `price`, a
boolean `in_stock`, and an array of `tags`. Everything from Phase 2, on the wire, for real.

That single line of JSON is compact because the server didn't add spaces. If you want it laid out for human
eyes, pipe it through a formatter. Many systems have `jq` installed for exactly this:

```console
$ curl -s https://api.example.com/products/15 | jq
{
  "id": 15,
  "name": "Mechanical Keyboard",
  "price": 129.99,
  "in_stock": true,
  "tags": [
    "peripherals",
    "input"
  ]
}
```
The `-s` flag silences `curl`'s progress meter so only the body is passed along, and `jq` pretty-prints the
JSON with indentation - same data, same bytes from the server, just spaced out so the structure is obvious.
(`jq` is a separate tool, not part of `curl`; if you don't have it, the compact line above is still
perfectly valid JSON.)

⚠️ **Gotcha.** `-i` (show response headers) and `-s` (silent) do different jobs - don't confuse them.
Reach for `-i` when you want to *see the status code and headers*; reach for `-s` when you want *only the
body*, usually to pipe it somewhere like `jq`.

## Sending data: POST with a JSON body

When you want the API to *create* something - a new user, an order, a comment - you send the data in the
request body, as JSON, with a `POST`. Two things have to be right for the server to accept it: the body
must be valid JSON, and you must tell the server it *is* JSON with a `Content-Type` header.

```console
$ curl -i -X POST https://api.example.com/products \
    -H "Content-Type: application/json" \
    -d '{"name": "Wireless Mouse", "price": 49.99, "in_stock": true}'
HTTP/1.1 201 Created
Content-Type: application/json
Location: /products/16

{"id":16,"name":"Wireless Mouse","price":49.99,"in_stock":true,"tags":[]}
```
You sent a `POST` to `/products` - the collection of products - asking it to create a new one. Read each
flag, because this is the pattern you'll reuse constantly:

- `-X POST` sets the **method** to `POST` (the default is `GET`).
- `-H "Content-Type: application/json"` adds the **header** that announces "my body is JSON." Without it,
  many servers won't know how to read what you sent and will reject it.
- `-d '{...}'` is the **request body** - the JSON data you're sending. (Using `-d` also makes `curl` send a
  `POST` automatically, but writing `-X POST` keeps the intent obvious.)

The response is `201 Created` - a more specific `2xx` than `200`, meaning "I made the new thing." The
server filled in an `id` (16) and an empty `tags` array, and the `Location` header points at the URL of the
resource you just created. You sent JSON; you got JSON back. That round trip is the heart of working with
any web API:

```mermaid
sequenceDiagram
  participant Client
  participant Server
  Client->>Server: POST /products + Content-Type: application/json + JSON body
  Server-->>Client: 201 Created + Location: /products/16 + JSON body
```

📝 **Terminology.** The single quotes around the `-d '...'` value are your **shell's** way of passing the
JSON to `curl` as one piece without mangling it - they are not part of the JSON. Inside, the JSON itself
still uses **double quotes**, exactly as Phase 2 requires.

⚠️ **Gotcha.** If you forget the `Content-Type: application/json` header, a server will often reply
`400 Bad Request` or `415 Unsupported Media Type` even though your JSON is perfect - because it didn't know
to read the body as JSON. When a `POST` is rejected, check that header first. (And recheck your JSON for a
stray trailing comma - the other usual suspect.)

## You can now read any API call

Look back at what you did. You sent a method to a URL, attached the right headers, put JSON in the body when
you had data to send, and read the status code and JSON that came back. There was no magic - only the two
building blocks, used together:

```text
   ┌─────────────────────── one API call ───────────────────────┐
   │                                                             │
   │   YOU send:   METHOD  +  URL  +  headers  +  JSON body      │   ← HTTP carries it,
   │                                                             │     JSON is the data
   │   YOU get:    status code  +  headers  +  JSON body         │
   │                                                             │
   └─────────────────────────────────────────────────────────────┘
```

That diagram is every web API request you'll ever make, in one frame. The specifics change - different
URLs, different fields, an `Authorization` header once you need to log in - but the shape is always this.
You now have the vocabulary to read it.

💡 **Key point.** HTTP and JSON are the two building blocks, and you've now used both together. What you
*haven't* learned yet is how APIs are *organized* - why it's `GET /products/15` and `POST /products`, how
URLs map to "resources," and the conventions that make different APIs feel familiar. That organizing layer
is **REST**, and it's the natural next step.

## Recap

1. A **`GET`** asks for data; read the JSON in the response body (use `jq` to pretty-print it).
2. A **`POST`** sends data; put valid JSON in the body with `-d` and announce it with
   `-H "Content-Type: application/json"`.
3. `curl` flags to know: `-X` sets the method, `-H` adds a header, `-d` sends a body, `-i` shows response
   headers, `-s` shows only the body.
4. `201 Created` is the typical success for a `POST`; a missing `Content-Type` header is the usual reason a
   good JSON body gets rejected.
5. Every web API call is the same shape: **method + URL + headers + JSON body** out, **status + headers +
   JSON body** back.

---

[← Phase 2: JSON, the Data Format](02-json-the-data-format.md) · [Guide overview](_guide.md) · Next up: [REST APIs Explained →](/guides/rest-apis-explained)
