Hono Client
Zelt generates type-safe client types (AppType) for Hono's hc client — enabling fully type-safe API calls with IDE autocomplete.
Overview
The @zeltjs/openapi package generates AppType from your controller signatures. This type integrates with Hono's hc client to provide:
- Full TypeScript inference for request parameters and response bodies
- IDE autocomplete for API endpoints
- Compile-time type checking for API calls
Installation
pnpm add @zeltjs/openapi
Configuration
Create a zelt.config.ts file in your project root:
import { defineConfig } from '@zeltjs/openapi';
export default defineConfig({
controllers: ['./src/**/*.controller.ts'],
dist: './generated',
tsconfig: './tsconfig.json',
});
Generating AppType
pnpm zelt-openapi build
This generates <dist>/app.gen.ts containing the AppType.
Generated app.gen.ts
// THIS FILE IS GENERATED BY @zeltjs/openapi. DO NOT EDIT.
import type { Route, BuildAppType } from '@zeltjs/openapi';
import type { HelloController } from '../src/controllers/hello.controller';
export type AppType = BuildAppType<[
Route<'GET', '/hello/:name', typeof HelloController.prototype.greet>,
Route<'POST', '/hello', typeof HelloController.prototype.create>,
]>;
Using AppType
Type-Safe API Client
import { hc } from 'hono/client';
import type { AppType } from './generated/app.gen';
const client = hc<AppType>('https://api.example.com');
// Fully typed - IDE autocomplete and type checking
const response = await client.hello[':name'].$get({
param: { name: 'world' },
});
if (response.ok) {
const data = await response.json();
// data is typed as { message: string }
console.log(data.message);
}
Testing with Type-Safe Client
import { hc } from 'hono/client';
import { describe, it, expect } from 'vitest';
import { app } from './app';
import type { AppType } from './generated/app.gen';
describe('Hello API', () => {
const client = hc<AppType>('http://localhost', {
fetch: (input, init) => app.fetch(new Request(input, init)),
});
it('should return greeting', async () => {
const res = await client.hello[':name'].$get({
param: { name: 'world' },
});
expect(res.status).toBe(200);
const body = await res.json();
expect(body.message).toBe('Hello, world!');
});
});
How It Works
- Static Analysis — Analyzes controller method signatures at build time
- Type Extraction — Extracts request/response types from TypeScript types
- Code Generation — Generates
AppTypeusing type-level computation
The generated AppType maps your controller methods to Hono's route types, enabling the hc client to infer parameter and response types automatically.