From unihttp
Generates a typed, packaged unihttp API client SDK from an OpenAPI 3.x spec or plain API description. Produces typed DTOs, method definitions, client class, ruff + mypy config, and contract tests.
How this skill is triggered — by the user, by Claude, or both
Slash command
/unihttp:unihttp-clientThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Generate a **runnable, packaged API client** on top of `unihttp` from either an
Generate a runnable, packaged API client on top of unihttp from either an
OpenAPI 3.x specification or a written API description. The output is an
installable Python package with typed models, declarative methods, a client
class, ruff + mypy (strict) config, and a small set of common-sense tests.
Always write idiomatic unihttp code — load the companion unihttp skill (or
../unihttp/SKILL.md) for the Wrong/Correct rules. The most
important one: import from submodules (unihttp.method, unihttp.markers,
unihttp.bind_method), never from the empty top-level unihttp package.
Defaults (override only when the user or spec asks):
aiohttp async (AiohttpAsyncClient); use requests
(RequestsSyncClient) when the user wants a synchronous client.build_http_request /
make_response) — only pytest needed, no HTTP-mock library.Map OpenAPI constructs with references/openapi-to-unihttp.md.
openapi is
3.0.x or 3.1.x. If it is older, ambiguous, or incomplete, say so before
generating. Extract: tags / path groups, operationIds, parameters
(path/query/header), request bodies, response schemas + status codes, reusable
components.schemas, and security schemes. Flag hard constructs early:
oneOf, anyOf, allOf, discriminators, multiple media types, file uploads.Keep this short — infer sensible defaults and state them rather than interrogating.
Mirror unihttp's own conventions: src/<import_name>/ layout, hatchling
build, ruff.toml + mypy.ini, py.typed. Use one file per symbol:
models/<model>.py, enums/<enum>.py, methods/<operation>.py, and a single
client.py. Re-export the public surface from __init__.py. For a very small
API (a handful of endpoints), it is fine to collapse models into one
models.py — use judgement, do not over-fragment a 3-endpoint client.
The full tree and file templates are in references/package-layout.md.
@dataclass per schema; one enum.StrEnum/IntEnum per enumerated type.name_mapping in the client's Retort, not by renaming attributes.nullable / oneOf null to T | None; oneOf/anyOf to Union;
allOf to composition or a merged dataclass.One BaseMethod[ResponseType] per operation, in methods/<operation>.py:
operationId (PascalCase); else <Verb><Resource>
(GetUser, CreateUser, ListUsers).__url__ = the path template, __method__ = the HTTP verb (uppercase).Path/Query/Header), request body to Body,
form to Form, file uploads to File + UploadFile. See the mapping table.list) or expose page/offset as optional Query fields — see "Pagination" in
the mapping reference. datetime/date/UUID/Decimal/Enum fields need no
special handling (adaptix loads them from their standard string forms).None ONLY for a genuinely
empty body (a real 204 with no content); if the endpoint returns an empty
object {} (common for DELETE), use BaseMethod[dict[str, Any]] — None
raises TypeLoadError because make_response always deserializes the body.A single *Client subclass in client.py:
AiohttpAsyncClient (async, default) or RequestsSyncClient (sync).bind_method.Retort (extend DEFAULT_RETORT) carrying any name_mapping, and
pass AdaptixDumper(retort) / AdaptixLoader(retort). The mapping must cover
the method classes (Body/Query fields), not only response models — for
an all-camelCase API use one global name_mapping(map={...}) with no class
predicate, which renames bodies, query filters, and models at once.base_url and auth inputs in __init__; default base_url from the
spec's servers[0].url so callers can construct the client with no args.
Inject auth via a Header field on methods or an auth middleware
(AsyncMiddleware for async clients; type next_handler as AsyncHandler).call_method instead of bind_method.Header). Leave a TODO for OAuth/refresh flows rather than inventing them.AsyncErrorMapperMiddleware / SyncErrorMapperMiddleware, or override
handle_error. Keep a small exceptions module if the API has a real error
taxonomy.Produce pyproject.toml (hatchling, src layout), ruff.toml, mypy.ini,
py.typed, .gitignore, and a README.md with install + quickstart. Runtime
dependency is unihttp with the chosen extras, e.g.
unihttp[aiohttp,adaptix]>=0.2.9. Dev dependencies for the default tests are just
ruff, mypy, pytest. In ruff.toml use extend-exclude (not exclude) so
ruff keeps ignoring .venv. Templates in
references/package-layout.md.
Default to contract tests at the unihttp seam — they cover exactly what generated code introduces and avoid flaky HTTP-mock dependencies:
Method(...).build_http_request(dumper) produces the
right url / method / query / body (markers wired correctly).Method(...).make_response(HTTPResponse(...), response_loader=loader) parses
into the right DTO. Call it by keyword (response_loader=) — that is how
call_method invokes it, so a method overriding make_response with a wrong
parameter name is caught instead of silently passing a positional test.pytest is needed, the same
for async (aiohttp) and sync (requests) clients. See
references/package-layout.md.Optionally add one full-pipeline test through a mocked transport, but treat it
as an extra. Note that aioresponses lags new aiohttp releases (it breaks on
aiohttp 3.14), so pin a compatible pair, prefer respx for httpx clients, or use
a local pytest-aiohttp server. Skip property-based / contract fuzzing unless the
user asks.
Run, from the generated package, and report real output:
ruff check .
ruff format --check .
mypy
pytest
Freshly generated code routinely needs one ruff check --fix + ruff format
pass before it is clean (import grouping, long __all__ lines). Run those first,
then the gate. Fix what remains. Do not claim the package is correct until these
pass (or explicitly report what does not and why).
pyproject.toml (+ ruff.toml, mypy.ini, py.typed) when scaffolding a package.BaseMethod per operation; a single client binding them.Retort carrying wire-name mappings when the API is not snake_case.README.md with install and a runnable quickstart (using async with for
async clients).ruff / mypy / pytest results.npx claudepluginhub goduni/unihttp --plugin unihttpGenerates type-safe client SDKs in TypeScript, Python, Go, Java from OpenAPI specs with auth, retries, pagination, and tests.
Generates client SDK code, API wrapper libraries, and request/response models for any REST API. Supports multiple languages with patterns for auth, retry, and pagination.
Generates API client code, SDKs, and integrations from API specs. Activates on phrases like 'api client generator' for building API integrations.