# Public API — `mgf-http`

> ⚠️ **This file documents `master` HEAD.** Names listed here may
> be unreleased. To learn what your installed wheel actually
> ships, run `pip show mgf-http` and compare against the git tag
> matching the published version.

This document is the **contract list** for `mgf-http`. Every name
listed below is a public name that consumers MAY depend on.

The contract terms are defined in
[`mgf-standard/docs/standards/API_DESIGN.md`](https://codeberg.org/magogi-admin/mgf-standard/src/branch/main/docs/standards/API_DESIGN.md). In
short:

- **Stability tiers:**
  - `experimental` — MAY change shape in any MINOR release
    (the 0.x window keeps everything experimental in practice).
  - `stable` — follows the deprecation cycle; removal only in MAJOR.
  - `deprecated` — slated for removal; emits `DeprecationWarning`.
- **Names not listed below are private.** Anything starting with
  `_` (underscore-prefixed module names like `_client.py`) is
  internal and MAY change without notice.
- **The 0.x window applies.** Per [SemVer](https://semver.org/) 0.x
  semantics, MINOR releases MAY break the public API. Pin tightly:
  `mgf-http = ">=0.X.0,<0.Y"`.

---

## `mgf.http`

Top-level typed async HTTP client. Closed-box: depends on
`mgf-common` + `httpx` only.

| Name | Tier | Description |
|---|---|---|
| `AsyncHttpClient` | experimental | Thin wrapper over `httpx.AsyncClient`. Bakes in: User-Agent identity (`<app>/<ver> mgf-http/<libver>`), retry on transient failures (via `RetryPolicy`), secret-header redaction in logs + OTel spans, typed error translation (`httpx.TimeoutException` → `HttpTransportError`), TLS-default-on with one-shot warning when disabled. Async context manager; `.client` escape hatch for httpx-specific features. |
| `RetryPolicy` | experimental | Frozen dataclass. `max_attempts` (default 0 = no retry), `base_backoff_seconds` (default 0.5), `max_backoff_seconds` (default 30), `retryable_methods` (default GET/HEAD/OPTIONS/PUT/DELETE — POST excluded), `retryable_statuses` (default {429, 503, 504}). `backoff_for_attempt(n)` computes the sleep before retry n with full jitter. |
| `HttpTransportError` | experimental | Re-exported from `mgf.http.exceptions`. Convenience top-level alias for the most-commonly-caught transport-layer exception. |

### Behaviours guaranteed at the public surface

- `AsyncHttpClient.request(method, url, **kw)` returns the
  `httpx.Response` for any non-error completion (incl. 4xx/5xx).
  4xx and 5xx are **not** raised — call `response.raise_for_status()`
  explicitly if you want a typed exception.
- Transport-level failures (timeout, connect error, network error)
  raise `HttpTransportError` AFTER retries exhaust. The original
  `httpx` exception is preserved as `__cause__`.
- `verify_tls=False` emits `UserWarning` exactly once per process.
- Secret-shaped request headers (case-insensitive match against
  `Authorization`, `Cookie`, `Set-Cookie`, `X-Api-Key`,
  `X-Auth-Token`, `X-Secret`, `Proxy-Authorization`) are redacted
  in the per-request log line. The response body is **never**
  logged.
- Per-request `cookies={...}` is repacked into a single `Cookie`
  header to sidestep httpx 0.28+'s deprecation of per-request
  cookies. If the caller already set a `Cookie` header explicitly,
  ours appends.
- `AsyncHttpClient(max_response_size=N)` caps `request()`-buffered
  responses at N bytes. When the cap is exceeded the wrapper
  raises `HttpTransportError(cause_summary="response-too-large")`
  rather than letting httpx buffer unbounded memory. Default
  `None` (no cap) preserves historical buffer-fully behaviour.
  PAPER-36.
- `AsyncHttpClient.stream(method, url, ...)` is an async context
  manager that yields a still-streaming `httpx.Response`. Retry,
  identity, redaction, and typed-error translation all apply —
  same posture as `request()`. The caller drives the body read
  via `response.aiter_bytes()` (or `aiter_text` / `aiter_raw`)
  and decides how much to consume. Once yielded, retries are
  off the table. PAPER-36.

---

## `mgf.http.exceptions`

Sibling-domain concrete exception leaves. Per the federation rule
(decision **D3** in the [federation roadmap](https://codeberg.org/magogi-admin/mgf-common/src/branch/main/docs/release/federation_roadmap.md)),
siblings own their domain concretes; mgf-common owns hierarchy
roots + generic status-code leaves.

| Name | Tier | Description |
|---|---|---|
| `HttpTransportError` | experimental | Inherits `mgf.common.exceptions.OperationError`. Raised by `AsyncHttpClient.request()` for transport-layer failures: timeout, connect-refused, network unreachable. Carries `url`, `cause_summary` (short categorization for log + OTel attribution), `attempts` (number of attempts before giving up). Original `httpx` exception preserved via `__cause__`. **Renamed from `HttpClientError` at the v0.29 federation cutover** to disambiguate from `mgf.common.exceptions.HttpClientError` (the HTTP-01 4xx-class hierarchy parent, which stays in mgf-common). |

---

## What stays in `mgf-common`, NOT here

- **HTTP-01 hierarchy** (`mgf.common.exceptions.HttpError`,
  `HttpClientError` *the 4xx-hierarchy parent*, `HttpServerError`,
  and the per-status leaves `HttpUnauthorized`, `HttpForbidden`,
  `HttpNotFound`, `HttpConflict`, `HttpBadRequest`,
  `HttpRateLimited`, `HttpInternalServerError`,
  `HttpServiceUnavailable`). These are the cross-cutting status-class
  hierarchy used by every web sibling (mgf-fastapi, future
  mgf-django, etc.). Do NOT confuse `mgf.common.exceptions.HttpClientError`
  (the 4xx-class parent) with `mgf.http.exceptions.HttpTransportError`
  (the transport-failure leaf, this sibling).
- **`AppError`, `OperationError`** and the rest of the typed
  exception hierarchy — `mgf.common.exceptions`.
- **`bootstrap`, `app_name`, `app_version`, `current_context`** —
  `mgf.common`.

`mgf-http` reaches into none of mgf-common's private modules. The
runtime dep is `mgf-common>=0.29,<0.30`.

## Additional public names

| Name | Tier | Description |
|---|---|---|
| `DownloadResult` | experimental | result of a streaming download (path, bytes, resumed flag) |
| `IntegrityError` | experimental | raised when a download's hash/length integrity check fails |

