# 11 · Call HTTP APIs

English narration · HHY 1.7.0

Fetch and filter JSON from a local API with explicit request policies.

## 00:00:00.000 — An API becomes useful data

In this lesson, we will turn an HTTP response into a small, useful list of names. Our local API contains three users, but only Ada and Linus are active. We will request the data, decode JSON, filter the records, and print the result. Everything runs on your own computer, so you can repeat the demonstration without creating an account, obtaining a token, or depending on someone else's public API.

```
["Ada", "Linus"]
```

## 00:00:31.830 — Start the local fixture

Open a terminal in the downloaded examples directory and start the Python fixture. It listens on loopback port ninety three eleven. Leave this terminal running and open a second one for HHY. The fixture has a users route and a missing route for testing failure. Python is just the small test server here; the client that requests and processes its data is written entirely in HHY. Stop the fixture with Control C when you finish.

```
python3 mock-api.py
```

## 00:01:04.380 — Build a request plan

Start by importing HTTP and constructing a GET request. The request builder describes the operation; send is the point where the network operation happens. Between those steps, add a two second timeout and a small retry policy. This order keeps the address, policy, and effect visible together. Notice that the returned value is an HTTP response, not the users collection yet. We still need to decode its body and select the field we want.

```
import http
let response = http.get("http://127.0.0.1:9311/users")
    |> timeout(2s)
    |> retry({ count: 2, backoff: 100ms })
    |> send
```

## 00:01:38.470 — Decode one layer at a time

Response body reads the response as text. Parse JSON converts that text into HHY values, and get selects the users field from the outer object. These are separate operations because HTTP and JSON are separate formats. A successful connection does not guarantee valid JSON, and valid JSON does not guarantee the field exists. When debugging an unfamiliar API, inspect one stage at a time. This makes a schema mismatch much easier to locate than one long unexplained pipeline.

```
response |> response_body |> parse_json |> get("users")
```

## 00:02:17.720 — Filter and project

The users field contains a List. Convert it explicitly to a Stream before applying stream operators. Where keeps only records whose active field is the Boolean true. Map then projects each record to its name, so inactive users and unrelated fields never reach the final collection. Collect consumes the finite stream, and JSON encoding gives us a machine readable result. Run the full client now and compare the two names with the fixture's three input records.

```
    |> stream
    |> where { user -> user.active == true }
    |> map { user -> user.name }
    |> collect |> encode_json |> print
```

## 00:02:52.110 — Observe an HTTP failure

Now run the missing example. The fixture returns a four oh four status, and HHY reports an HTTP status error that our catch block prints. This is different from a JSON parser error or an unreachable server. Keep those distinctions in your troubleshooting. Do not assume every failure means the service is offline. A wrong route can be fixed in the client, while an unavailable service may require waiting, retrying, or presenting a clear failure to the caller.

```
hhy run missing.hhy
# HttpStatusError
```

## 00:03:27.350 — Choose retry boundaries

A retry policy is useful for temporary failures, but it cannot repair an invalid route or an incompatible response. Our example uses GET, a read operation. Before applying retries to an operation that creates or changes data, understand the API's rules for duplicate requests. The HHY documentation describes selective retry behavior and does not automatically retry POST by default. Keep a timeout on every request, and retain the final error when the configured attempts still cannot complete successfully.

```
GET /users
Timeout: 2 seconds
Retry policy: count 2, backoff 100 ms
```

## 00:04:08.520 — Practice with the same fixture

For practice, change the projection so the output contains small objects with both name and active fields. Then change one fixture record from inactive to active, restart the fixture, and predict the new result before running the client. Keep the filtering and the projection as separate stages so their responsibilities remain clear. You now have the foundation for calling real APIs: an explicit request, bounded policy, response decoding, and an intentional data transformation. Next we will process several requests concurrently.

```
hhy run api-client.hhy
hhy run missing.hhy
```

