2025-07-17 · 3 min read
API Design for Adapter Catalogs
A good adapter catalog API should mirror how users think about the product. They want to list adapters, inspect a single adapter, compare versions, start jobs, and download artifacts. If the API is too clever, it becomes hard to use. If it is too vague, it becomes hard to automate. ModelForgeLab should aim for small, stable endpoints with predictable JSON.
The core endpoints are straightforward. A list endpoint returns adapters with filters and pagination. A detail endpoint returns one adapter and its versions. A job endpoint starts training or inference work. A status endpoint returns progress. A download endpoint returns the selected artifact. That set is enough for most clients.
curl -s "http://127.0.0.1:8080/api/adapters?task=image&public=true" | jq .
Filtering should be easy to understand. Let clients filter by task, base_model, public, license, and version. Avoid forcing consumers to download a whole catalog when they only need a subset. Pagination should return stable cursors or page numbers with a consistent sort order.
The response should include enough metadata to render a card without extra fetches. That usually means slug, name, version, base model, size, format, precision, and checksum at minimum. If the client needs more detail, it can request the adapter detail endpoint.
Error responses should be structured. A simple JSON error object with a code, message, and optional details is enough for almost every case. The important part is consistency. Clients should not have to parse different error shapes depending on which endpoint failed.
{"error":{"code":"not_found","message":"adapter not found"}}
Versioning should be part of the path or the schema from the beginning. Even a small registry benefits from a stable API version so new fields can be added later without breaking clients. The version can be in the URL, in a header, or both, but the decision should be deliberate rather than accidental.
The download endpoint should be aligned with the catalog metadata. If the catalog says an adapter is gated, the API should not quietly expose the file. If the file is public, the download should be direct and verifiable. The API and the UI need to agree on visibility.
For job creation, the API should return a job ID immediately and let clients poll or subscribe for progress. That keeps the initial request short and gives the user a durable handle for the run. A job object should include the selected adapter or dataset, the current state, and a few progress fields. It does not need to expose internal implementation details.
It is also smart to keep the API flat where possible. Nested endpoints can be hard to remember, especially for small scripts. A path like /api/adapters/{slug} and /api/jobs/{job_id} is easy to scan and easy to document. The fewer surprises the API has, the more likely users are to automate against it.
The same applies to payload shape. Keep the response fields stable and avoid changing their meaning across versions. If a field is optional, say so. If a value can be null, keep it explicit. That sort of boring clarity is what makes a registry API pleasant to use.
ModelForgeLab can support a clean ecosystem with a relatively small API if the endpoints are predictable and the schemas are honest. That is the sort of design that is easy to document, easy to cache, and easy to use from scripts.