The Registry stores API providers, their endpoints, and stable service.verb aliases in the database. Your module calls an alias; the endpoint is a row, not a hardcoded URL. Change a provider without touching a line of application code.
An API key is a secret — it never goes in a YAML or in code. Store it by name in the vault; the registry references the name, never the value.
Input is masked. fabbro vault list shows which providers have a credential; fabbro vault rm removes one. The value is Fernet-encrypted with your FERNET_KEY and resolved at call time.
Three ways in, from most to least automatic. Discovery from an OpenAPI spec:
No spec URL? Drop --spec and the registry probes common spec locations from the base URL. When discovery can't reach anything, --manual is the always-works path: it registers the provider interactively, one endpoint at a time.
The declarative path — a YAML describing providers, endpoints, and bindings — is the one to commit to your repo so the registry is reproducible:
--dry-run prints the plan and writes nothing. Drop it (or add --yes to skip the prompt) to apply; --replace overwrites providers that already exist by name.
A binding is the stable name your code calls. It points a service.verb alias at one provider's endpoint — the code names the service, never the provider, so swapping providers is a re-bind, not a code change.
fabbro registry unbind pets.fetch removes it. fabbro registry list is the human summary of everything registered.
From modules/<name>.py, reach the binding through service("..."). Path params and query values are passed as keyword arguments; the shape (rename, unwrap) is applied for you. You never build a URL or set an auth header by hand.
from core import registry_api as registry
def load_pet(pet_id: int) -> dict:
# pets.fetch resolves to the bound provider+endpoint;
# the stored secret is injected as the endpoint's auth requires.
return registry.service("pets").fetch(id=pet_id)An undeclared parameter fails locally with a Fix (the classic city→ciyt typo) instead of being sent silently and returning a cryptic 400. Optional params an endpoint doesn't declare go through the explicit query={...} channel.
describe generates a usage guide of every registered service and verb — feed it to your coding agent so it calls the bindings correctly instead of inventing raw requests.
fabbro registry export dumps the whole registry as seedable YAML — the round-trip back into seed on another environment.