Code-First APIs
Code-first API development with OpenAPI and hey-api ensures end-to-end type safety from Fastify routes to generated clients.
Code-first API development with OpenAPI and hey-api ensures end-to-end type safety. Fastify routes are the source of truth, the OpenAPI spec is generated from routes, and hey-api generates type-safe TypeScript clients for multi-language SDKs and AI/MCP integration.
What is Code-First Development?
Code-first development means implementing your API routes first, then generating the OpenAPI specification from those route definitions. Fastify routes serve as the single source of truth, and the OpenAPI spec is automatically generated via generate-openapi.ts:
- Request/response shapes defined in route schemas
- Type definitions extracted from route implementations
- Validation schemas from Zod schemas in routes
- API documentation generated from route metadata
Benefits
- ✅ End-to-end type safety - Types flow from routes → OpenAPI spec → generated clients automatically
- ✅ No duplication - Define routes once, generate OpenAPI spec and clients automatically
- ✅ Automatic OpenAPI generation - OpenAPI spec generated from Fastify routes via
generate-openapi.ts - ✅ Automatic client generation - hey-api generates fully typed TypeScript clients from the generated spec
- ✅ OpenAPI standard - Industry-standard format for API contracts
- ✅ Framework portability - Works with Fastify, Express, or any framework
- ✅ Multi-language support - Generate clients for TypeScript, Python, Go, Rust, etc.
Simple Example
1. Implement Routes (apps/api/src/routes/)
Fastify routes are implemented with schemas and metadata:
fastify.get('/health', {
schema: {
response: {
200: {
type: 'object',
properties: {
status: { type: 'string' }
}
}
}
}
}, async (request, reply) => {
return { status: 'ok' }
})2. Generate OpenAPI Spec (apps/api/openapi/openapi.json)
The OpenAPI spec is automatically generated from Fastify routes:
pnpm generate:openapiThis runs generate-openapi.ts which scans route definitions and generates the OpenAPI specification.
3. Generate TypeScript Client (packages/core)
hey-api generates type-safe clients from the generated OpenAPI spec:
// Generated by @hey-api/openapi-ts
import { createClient } from './gen/client'
const client = createClient({
baseUrl: 'https://api.example.com',
})4. Client Usage (apps/web)
import { createApi } from '@basilic/core'
import { useHealthCheck } from '@basilic/react'
const api = createApi({
baseUrl: process.env.NEXT_PUBLIC_API_URL!,
getAuthToken: async () => session?.token,
})
// Fully typed API call
const health = await api.healthCheck()
// Or use React Query hooks
const { data } = useHealthCheck()
// data is fully typed from OpenAPI specWorkflow
- Implement routes - Define Fastify routes with schemas in
apps/api/src/routes/ - Generate OpenAPI spec - Run
pnpm generate:openapito generate OpenAPI 3.0 spec inapps/api/openapi/ - Generate clients - hey-api generates TypeScript clients in
packages/coreandpackages/reactfrom the spec - Use in client - Import and use generated typed clients
Client Consumption
Clients consume the API through generated TypeScript clients:
import { createApi } from '@basilic/core'
import { useHealthCheck } from '@basilic/react'
// Runtime-agnostic client
const api = createApi({
baseUrl: process.env.NEXT_PUBLIC_API_URL!,
getAuthToken: async () => session?.token,
})
// Fully typed API call
const health = await api.healthCheck()
// Or use React Query hooks (generated from OpenAPI spec)
const { data, isLoading, error } = useHealthCheck()The generated clients:
- Provide full type safety from routes → OpenAPI spec → components
- Handle authentication and headers automatically
- Work with TanStack Query for caching and state management
- Are generated by hey-api from the OpenAPI spec (which is generated from routes)
OpenAPI Integration
OpenAPI 3.0 specs are automatically generated from Fastify routes:
- Generated at
apps/api/openapi/openapi.jsonviagenerate-openapi.ts - Served at
/reference/openapi.json(programmatic access) - Scalar UI at
/reference(interactive docs) - MCP integration for AI agents
- Multi-language SDK generation using hey-api and standard OpenAPI tools
SDK Generation
TypeScript: Generated by @hey-api/openapi-ts from the generated OpenAPI spec. Other languages: Use standard OpenAPI generators (openapi-generator, oapi-codegen, progenitor). All clients are generated from the same OpenAPI spec (which is generated from routes), ensuring consistency.
Related Documentation
- Package Conventions - Detailed package architecture
- API Contracts - Deep dive into OpenAPI and hey-api