# Code examples

These server-side examples use standard HTTP clients. Configure `ATM_API_BASE_URL` and `ATM_API_KEY` as shown in the [quickstart](/quickstart). No API-specific SDK is required.

## JavaScript: find a movie and read its ending

Run this as a Node.js script with built-in `fetch` support. It checks HTTP failures, handles an empty search, and verifies content availability before requesting the explanation.

```js
const baseUrl = process.env.ATM_API_BASE_URL;
const apiKey = process.env.ATM_API_KEY;

if (!baseUrl || !apiKey) {
  throw new Error("Set ATM_API_BASE_URL and ATM_API_KEY.");
}

async function get(path, params = {}) {
  const url = new URL(`${baseUrl.replace(/\/$/, "")}${path}`);
  url.search = new URLSearchParams(params).toString();

  const response = await fetch(url, {
    headers: { Authorization: `Bearer ${apiKey}` },
    signal: AbortSignal.timeout(15000),
  });
  const body = await response.json();

  if (!response.ok) {
    const error = new Error(body.error?.message ?? `HTTP ${response.status}`);
    error.status = response.status;
    error.code = body.error?.code;
    error.requestId = body.error?.request_id;
    error.retryAfter = response.headers.get("Retry-After");
    throw error;
  }

  return body;
}

const results = await get("/movies", { imdb_id: "tt1375666", limit: "1" });
const match = results.data[0];

if (!match) {
  console.log("No matching movie in the catalog.");
} else {
  const { data: movie } = await get(`/movies/${match.id}`);

  if (movie.available_content.includes("ending")) {
    const { data: ending } = await get(`/movies/${movie.id}/content/ending`);
    console.log(ending.text);
  } else {
    console.log("No ending explanation is available for this movie.");
  }
}
```

Availability can change between calls, so handle `content_not_available` in your application's error boundary too. These examples make a single attempt per request; add bounded retries according to [Errors and limits](/errors-and-limits).

## JavaScript: fetch one more page

Using the same `get` function:

```js
const filters = { genre: "Drama", sort: "-year", limit: "20" };
const firstPage = await get("/movies", filters);

if (firstPage.pagination.next_cursor) {
  const nextPage = await get("/movies", {
    ...filters,
    cursor: firstPage.pagination.next_cursor,
  });
  console.log(nextPage.data);
}
```

For an interactive list, request the next page when the reader asks for more. Keep the filters alongside the cursor so subsequent requests use the same search.

## Python: search the catalog

This example uses Python's standard library:

```python
import json
import os
from urllib.error import HTTPError
from urllib.parse import urlencode
from urllib.request import Request, urlopen

base_url = os.environ["ATM_API_BASE_URL"].rstrip("/")
api_key = os.environ["ATM_API_KEY"]
query = urlencode({"q": "Inception", "limit": 5})
request = Request(
    f"{base_url}/movies?{query}",
    headers={"Authorization": f"Bearer {api_key}"},
)

try:
    with urlopen(request, timeout=15) as response:
        page = json.load(response)
except HTTPError as exc:
    try:
        error = json.loads(exc.read()).get("error", {})
    except (ValueError, UnicodeDecodeError):
        error = {}
    raise RuntimeError(
        f"HTTP {exc.code}: {error.get('code', 'request_failed')} "
        f"(request ID: {error.get('request_id', 'unavailable')})"
    ) from None

for movie in page["data"]:
    print(movie["id"], movie["title"], movie["year"])
```

Use the returned `id` for detail requests. Keep the key in the request header and out of error messages.

**Reference:** [Browse every endpoint →](/api)
