CLI Tool
@vafast/cli is the official Vafast command-line tool for syncing API type definitions from the server, enabling type safety across repositories.
Installation
npm install -D @vafast/cliCommands
vafast sync - Sync API Types
Fetches the API contract from the server and generates a TypeScript type definition file.
Basic Usage
# basic usage
npx vafast sync --url http://localhost:3000
# specify the output file
npx vafast sync --url http://localhost:3000 --out src/types/api.ts
# specify the contract endpoint
npx vafast sync --url http://localhost:3000 --endpoint /api-spec
# strip a path prefix
npx vafast sync --url http://localhost:3000 \
--endpoint /api/api-spec \
--out src/types/api/blog.generated.ts \
--strip-prefix /apiOptions
| Option | Description | Default |
|---|---|---|
--url <url> | Server URL (required) | - |
--out <path> | Output file path | src/api.generated.ts |
--endpoint <path> | Contract endpoint path | /__contract__ |
--strip-prefix <prefix> | Strip a path prefix | - |
Workflow
1. Server Setup
Expose the contract endpoint on your vafast server:
import { Server, defineRoute, defineRoutes, getApiSpec } from 'vafast'
const routes = defineRoutes([
defineRoute({
method: 'GET',
path: '/users',
handler: getUsersHandler
}),
defineRoute({
method: 'POST',
path: '/users',
handler: createUserHandler
}),
])
// add the contract endpoint
const allRoutes = [
...routes,
defineRoute({
method: 'GET',
path: '/api-spec',
handler: getApiSpec // use it directly as the handler
})
]
const server = new Server(allRoutes)
export default { fetch: server.fetch }2. Client Sync
npx vafast sync --url http://localhost:3000 --endpoint /api-spec3. Use the Generated Types
import { createClient } from '@vafast/api-client'
import { createApiClient } from './api.generated'
// create the underlying client
const client = createClient({
baseURL: 'http://localhost:3000',
timeout: 30000
})
// create the type-safe API client
const api = createApiClient(client)
// type-safe calls (wrong paths are caught by TypeScript)
const { data, error } = await api.users.get({ page: 1 })
// ❌ TypeScript reports an error
// api.nonExistent.get() // Error: Property 'nonExistent' does not existExample of Generated Types
The file generated by the CLI contains:
import type { ApiResponse, RequestConfig, Client, EdenClient } from '@vafast/api-client'
import { eden } from '@vafast/api-client'
/** API contract type */
export type Api = {
users: {
get: {
query: { page?: number }
return: any
}
post: {
body: { name?: string }
return: any
}
}
}
/** API client type alias */
export type ApiClientType = EdenClient<Api>
/**
* Create a type-safe API client
*/
export function createApiClient(client: Client): EdenClient<Api> {
return eden<Api>(client)
}Automation
Configure scripts in package.json:
{
"scripts": {
"sync:auth": "vafast sync --url http://localhost:9003 --endpoint /auth/api/api-spec --out src/types/api/auth.generated.ts --strip-prefix /auth/api",
"sync:blog": "vafast sync --url http://localhost:9002 --endpoint /blog/api/api-spec --out src/types/api/blog.generated.ts --strip-prefix /blog/api",
"sync:types": "npm run sync:auth && npm run sync:blog",
"dev": "vite",
"build": "npm run sync:types && vite build"
}
}Multi-Service Example
// src/utils/apiClients.ts
import { createClient } from '@vafast/api-client'
import { createApiClient as createAuthClient } from '~/types/api/auth.generated'
import { createApiClient as createBlogClient } from '~/types/api/blog.generated'
// shared config
const AUTH_API = { baseURL: '/auth/api', timeout: 30000 }
const BLOG_API = { baseURL: '/blog/api', timeout: 30000 }
// create the clients
const authClient = createClient(AUTH_API)
const blogClient = createClient(BLOG_API).use(appIdMiddleware)
// export the type-safe APIs
export const auth = createAuthClient(authClient)
export const blog = createBlogClient(blogClient)
// usage
const { data, error } = await blog.posts.find.post({ current: 1, pageSize: 10 })Notes
Return types: if the backend doesn't define a
responseschema, the generated return type isany(gradual type safety). Addingresponseschemas on the backend gives you full type checking.The server must be running: when running
sync, the server must be up and exposing the contract endpoint.Don't edit by hand: the generated file gets overwritten, so don't modify it manually.
Type safety: the generated
createApiClientreturnsEdenClient<Api>, and TypeScript catches wrong API paths.
Related Links
- API Client - learn how to use the generated types
- Routing Guide - learn how to define routes
- GitHub repository - source code and issue tracker