api
Build JSON API routes with validation, and call them from the browser fully typed.
What it is
@kitr/api is the HTTP API of a kitr app: routes in a table, controllers, schema validation and plain objects as responses. The typed client reads the same table, and kitr api:sync writes an OpenAPI document from it.
Routes run on the server; the client runs anywhere. For functions only your own components call, actions are shorter.
Install
kitr add apiFirst time? Run npm i -g @kitr/kitr once. Inside a project, the global kitr runs your project's own version.
Adds @kitr/api, config/api.ts, server/routes.ts with a health route, and the typed client in app/api/client.ts. Adds server first if missing. Every change.
Quick start
Write a controller. Each method receives the request context and returns the response body:
// server/controllers/orders_controller.ts
import type { HttpContext } from '@kitr/api'
import { KitrError } from '@kitr/kitr/app'
const orders = new Map([['ord_1042', { id: 'ord_1042', customer: 'Ada', total: 129, status: 'open' }]])
export default class OrdersController {
async index() {
return [...orders.values()]
}
async show({ params }: HttpContext<{ id: string }>) {
const order = orders.get(params.id)
if (!order) throw KitrError.notFound('Order')
return order
}
}
Register it as a resource:
// server/routes.ts
import { defineRoutes } from '@kitr/kitr/app'
import api from '@kitr/api/routes'
import OrdersController from '#server/controllers/orders_controller'
export const routes = defineRoutes([api], (router) =>
router.group({ prefix: '/api' }, (r) => r.resource('orders', OrdersController)),
)
export type ServerRoutes = typeof routes.$types
Start it with kitr dev api and ask for an order:
curl http://localhost:3001/api/orders/ord_1042
# => { "id": "ord_1042", "customer": "Ada", "total": 129, "status": "open" }
resource registered GET /api/orders and GET /api/orders/:id from the controller's methods. An unknown id answers 404 with { "code": "NOT_FOUND" }. Next in the guide: Build your first endpoint.
Built on
| Layer | Built on | What kitr adds |
|---|---|---|
| HTTP | h3, through server. | Route groups, resources, lazy controllers, named routes and the middleware order. |
| Validation | Any Standard Schema library: zod, valibot, arktype. | Validated params, query and body on the request, and errors in kitr's one shape. |
| Client | fetch |
A client typed from the route table, with KitrError on failure and TanStack Query helpers. |
| Documentation | OpenAPI 3.1 | kitr api:sync, which writes the document from the routes and their schemas. |
kitr adds the route table, controllers, validation, the error shape, the typed client and the OpenAPI export.
Problems it solves
- Routes, handlers and types kept in three places. Define routes.
- Untrusted input in controllers. Validate input.
- Errors that look different on every endpoint. Return errors.
- A client that drifts from the server. Call the API from the browser.
- Cross-origin front ends, abusive clients and non-JSON bodies. Write middleware.
- Documentation nobody updates. Generate an OpenAPI document.
- Testing through a real port. Call routes in-process.