Transport for Companies House: the settings resolver (per-call opts first, then context variables, then defaults), a typed HttpError, JSON GETs, and query-string building that drops unset values.

opts keyContext variableDefault
api-keycompanies-house.api-keynone: calls fail without it
base-urlcompanies-house.base-urlhttps://api.company-information.service.gov.uk
document-base-urlcompanies-house.document-base-urlhttps://document-api.company-information.service.gov.uk

Per-call credentials. api-key in opts is masked in call records and never written to context, so parallel flows and tenants in one run don't see each other's keys. Present but blank or null, it is an error, never a fallback to context. A per-call base-url or document-base-url needs an api-key in the same opts: the context key is never sent to a per-call URL.

Context Vars

Optional
  • companies-house.api-key
  • companies-house.base-url
  • companies-house.document-base-url

Values

BASE_URL

BASE_URL: Str "https://api.company-information.service.gov.uk"

DOCUMENT_BASE_URL

DOCUMENT_BASE_URL: Str "https://document-api.company-information.service.gov.uk"

KEYED_URL_KEYS

KEYED_URL_KEYS: Vec [
  "base-url",
  "document-base-url"
]

PACKAGE_AGENT

PACKAGE_AGENT: Str "hot-dev-companies-house-pkg/0.1 (+https://hot.dev)"

SOURCE

SOURCE: Str "companies-house"

Functions

body-detail

fn (body: Any): Str?

get-json

fn (url: Str, headers: Map): Any

GET a JSON resource and return the decoded body, or an Err carrying HttpError.

get-json-or-null

fn (url: Str, headers: Map): Any

get-json, but a 404 gives null (a missing company) instead of an Err.

given

fn (v: Any): Bool

True for a non-null value that is not a blank string.

http-error

fn (response: ::hot::http/HttpResponse, url: Str): HttpError

Build an HttpError from a non-2xx response. Exposed for testing; every request uses it.

is-not-found

fn (e: Any): Bool

True when e is an HttpError with status 404.

path-segment

fn (value: Any): Str

Percent-encode one path segment.

pick

fn (opts: Map, key: Str, ctx-key: Str, default: Any): Any

query-string

fn (params: Map): Str

Build a ?a=1&b=2 suffix from a Map, dropping null and blank values (pure); "" when nothing remains.

request

fn (method: Str, url: Str, headers: Map): ::hot::http/HttpResponse

GET (or another method) a Companies House URL with headers, returning the HttpResponse on 2xx or an Err carrying HttpError. A transport failure passes through as its own Err.

require-api-key

fn (cfg: Map): Str

The API key from resolved settings, or an Err naming where to set it.

resolve

fn (opts: Map): Map

Resolve settings for one call: {api-key, base-url, document-base-url}. Values in opts win over context; an api-key in opts is used for that call only and comes back unchanged. An Err when api-key is in opts but blank or null, or when opts has a URL without api-key.

Example

cfg ::companies-house::api/resolve({api-key: tenant.ch-key})

retry-after

fn (headers: Map): Int?

strip-slash

fn (url: Str): Str

Types

HttpError

HttpError type {
    source: Str,
    status: Int,
    url: Str,
    headers: Map,
    body: Any,
    retry-after: Int?,
    message: Str
}

A non-2xx Companies House response. source is "companies-house"; url the requested URL (Companies House takes no credentials in URLs); retry-after the parsed Retry-After seconds on 429s; message a one-line summary that never includes credentials.