Adding an HTTP route
Source in the repository.
Checklist for adding (or changing) a /v1/* route in @kindgi/api and
exposing it through the TypeScript SDK (@kindgi/client). Every step has
an automated gate; the table at the end lists them.
Conventions for URL shape, auth, request / response bodies, pagination,
and errors are in API-ROUTE-CONVENTIONS.md.
Read it first.
1. Implement the handler
Section titled “1. Implement the handler”- Add the handler to the resource's router in
packages/api/src/routes/<resource>.ts(create the file for a new resource and mount it inpackages/api/src/app.ts). - If the route needs a capability the API doesn't have yet (storage, a
runtime service), add a binding interface to the relevant public
package and a field on
CreateAppInput. The host application supplies the implementation —@kindgi/apinever constructs one itself.
2. Register the operation
Section titled “2. Register the operation”Add one OperationSpec to OPERATIONS in
packages/api/src/openapi/operations.ts:
method,honoPath(:idstyle, exactly as mounted),openapiPath({id}style)operationIdas<resource>.<verb>,summary,tags,security('bearer'unless the route is deliberately public)parameters,requestBody,responses— schemas are$refs intocomponents.schemas; add new wire shapes topackages/api/src/openapi/schemas.ts
Gate: tests/openapi.test.ts fails when a mounted route has no
OPERATIONS entry or an entry has no mounted route. The pre-commit hook
runs it whenever staged files touch packages/api/src/{routes,openapi}/.
3. Regenerate the OpenAPI artifact
Section titled “3. Regenerate the OpenAPI artifact”pnpm --filter @kindgi/api gen:openapiThis rewrites packages/api/openapi.json (exported as
@kindgi/api/openapi.json — the SDK codegen input). Commit it with the
route change.
Gate: packages/api/tests/openapi-artifact.test.ts fails in CI when
the committed file differs from the generator output.
4. Test the route
Section titled “4. Test the route”Add or extend packages/api/tests/<resource>-routes.test.ts: success
path, auth / tenant scoping, validation errors, and not-found / conflict
cases per the conventions doc.
5. Wrap it in the SDK
Section titled “5. Wrap it in the SDK”pnpm --filter @kindgi/client genregenerates the wire types from the artifact (buildruns it automatically).- Add the resource-client method in
sdks/typescript/src/resources/<resource>.tsand its test. - Add an entry under
## Unreleasedinsdks/typescript/CHANGELOG.md. - Regenerate the Python client:
cd sdks/python && uv run python scripts/gen_client.py. Every operation becomes a method there (models and resources are generated); nothing to hand-write.
Gate: sdks/typescript/tests/coverage-drift.test.ts fails when a
generated endpoint has no resource-client method. An endpoint that is
deliberately not wrapped goes in that test's SKIP map with a reason.
The pre-commit hook runs it when the API or sdks/typescript/src/
changes.
Gates at a glance
Section titled “Gates at a glance”| Gate | Catches | Runs in |
|---|---|---|
packages/api/tests/openapi.test.ts |
route ↔ OPERATIONS drift |
pre-commit (API changes), CI |
packages/api/tests/openapi-artifact.test.ts |
stale openapi.json |
CI |
sdks/typescript/tests/coverage-drift.test.ts |
generated endpoint without SDK method | pre-commit (API / SDK changes), CI |
sdks/python/scripts/gen_client.py --check |
Python client out of step with openapi.json |
pre-commit (API / Python client changes, with uv), CI |