Templates
Swaggie's template system is split into two independent layers: HTTP client templates and reactive query layer templates. You can use an HTTP client template on its own, or combine a reactive layer template with any compatible HTTP client template to get a fully-typed reactive data-fetching layer on top.
HTTP client templates
These are self-contained and produce a plain typed client with one method per API operation. Pick whichever library fits your project:
| Template | HTTP Client | Best for |
|---|---|---|
axios | Axios | React, Vue, Node.js — the most widely used default |
fetch | Native fetch | Browser apps or Node 18+ with no extra dependencies |
xior | xior | Lightweight Axios-compatible alternative |
ky | ky | Modern fetch-based client with hooks API |
ng1 | Angular 1 $http | Legacy Angular 1.x applications |
ng2 | Angular HttpClient | Angular 2+ applications (uses InjectionToken) |
axios (default)
Generates client objects with methods that return AxiosPromise<T>. Includes a shared Axios instance configured with your baseUrl and query parameter serialization settings.
Dependencies:
npm install axiosGenerated output (excerpt):
import Axios, { AxiosPromise } from 'axios';
const axios = Axios.create({ baseURL: '/api' });
export const petClient = {
getPetById(petId: number): AxiosPromise<Pet> {
return axios.request<Pet>({ url: `/pet/${petId}`, method: 'GET' });
},
};fetch
Uses the native browser (or Node 18+) fetch API. No runtime dependencies required.
Generated output (excerpt):
export const petClient = {
async getPetById(petId: number): Promise<Pet> {
const response = await fetch(`/api/pet/${petId}`);
return response.json() as Promise<Pet>;
},
};xior
xior is a lightweight, modern alternative to Axios with a compatible API surface. Use this if you want Axios-style interceptors without the Axios bundle size.
Dependencies:
npm install xiorky
ky is a modern, fetch-based HTTP client with a hooks API. Methods return Promise<T> directly (no response wrapper), making the generated code simpler for straightforward use cases.
Dependencies:
npm install kyGenerated output (excerpt):
import ky, { type Options as KyOptions } from 'ky';
export const http = ky.create({
prefix: '/api',
});
export const petClient = {
getPetById(petId: number, $config?: KyOptions): Promise<Pet> {
const url = `pet/${encodeURIComponent(`${petId}`)}`;
return http.get(url, { ...$config }).json<Pet>();
},
};Using --clientSetup with ky
Because ky requires hooks (interceptors) to be provided at instance creation time — unlike axios or xior where interceptors can be attached after the fact — Swaggie provides a --clientSetup flag that generates a write-once setup file and switches the generated client to a lazy initialisation pattern.
swaggie -s ./openapi.json -o ./src/api.ts -t ky --clientSetup ./src/api.setup.tsOn the first run, this generates two files:
src/api.ts— the main generated client, now usinginitKyHttp()/getKyHttp()instead of a simple singletonsrc/api.setup.ts— a write-once scaffold you fill in once and own forever
On subsequent runs, api.ts is always regenerated, but api.setup.ts is never overwritten. Use --forceSetup to regenerate it intentionally.
src/api.setup.ts (generated scaffold):
// GENERATED ONCE — will not be overwritten on subsequent runs.
import type { Options as KyOptions } from 'ky';
export type KySetupConfig = Pick<KyOptions, 'hooks' | 'prefix' | 'retry' | 'timeout'>;
export function createKyConfig(): KySetupConfig {
return {
prefix: '/api',
hooks: {
beforeRequest: [
// TODO: attach Authorization header, agent headers, test cookies, etc.
],
afterResponse: [
// TODO: handle 401 redirect, error monitoring, etc.
],
beforeError: [],
},
};
}Usage in your app (e.g. a React provider):
import { initKyHttp } from './api';
initKyHttp(); // call once at startup, before any API requestsPassing runtime values into hooks (e.g. an auth ref from a React context):
Since createKyConfig() is called once with no arguments, pass runtime dependencies via module-level variables in the setup file:
// api.setup.ts
let _getToken: () => Promise<string> = () => Promise.resolve('');
export function configureKyClient(opts: { getToken: () => Promise<string> }) {
_getToken = opts.getToken;
}
export function createKyConfig(): KySetupConfig {
return {
prefix: '/api',
hooks: {
beforeRequest: [
async ({ request }) => {
const token = await _getToken();
if (token) request.headers.set('Authorization', `Bearer ${token}`);
},
],
},
};
}Then at startup:
import { configureKyClient } from './api.setup';
import { initKyHttp } from './api';
configureKyClient({ getToken: () => authRef.current.getAccessToken() });
initKyHttp();ng1 / ng2
Angular-specific clients. ng1 uses $http and Angular 1 dependency injection. ng2 generates injectable services using HttpClient and InjectionToken. Requires @angular/common/http.
Angular clients are not compatible with reactive query layer templates.
Reactive query layer templates
Reactive layer templates wrap an HTTP client template with a reactive data-fetching layer. They produce two exports per API group: the plain client object (identical to the standalone HTTP client template) and a hooks namespace with queries, mutations, and queryKeys.
| Template | Library | Best for |
|---|---|---|
swr | SWR | React apps using SWR for server state |
tsq | TanStack Query | React apps using TanStack Query |
Reactive layer templates must be composed with a compatible HTTP client template. The compatible HTTP client templates are: axios, fetch, xior, ky.
Combining templates
Pass the template as a 2-element array with [reactive-layer, http-client] in your config, or as a comma-separated pair on the CLI.
In a config file
{
"template": ["swr", "axios"]
}On the CLI
# reactive-layer,http-client — comma-separated
swaggie -s ./openapi.json -o ./client.ts -t swr,axios
swaggie -s ./openapi.json -o ./client.ts -t tsq,xior
swaggie -s ./openapi.json -o ./client.ts -t swr,fetch
swaggie -s ./openapi.json -o ./client.ts -t tsq,axiosReactive layer alone — defaults to fetch
If you pass only a reactive layer template name without a companion HTTP client template, Swaggie defaults to fetch:
{ "template": "swr" }This is equivalent to ["swr", "fetch"].
Valid combinations
| Reactive layer | Compatible HTTP client templates |
|---|---|
swr | axios, fetch, xior, ky |
tsq | axios, fetch, xior, ky |
Generated output (excerpt for ["swr", "axios"])
import useSWR, { type SWRConfiguration, type Key } from 'swr';
import useSWRMutation, { type SWRMutationConfiguration } from 'swr/mutation';
import Axios, { type AxiosPromise, type AxiosRequestConfig } from 'axios';
const axios = Axios.create({ baseURL: '/api' });
// Plain HTTP client — identical to the plain axios template
export const petClient = {
getPetById(petId: number): AxiosPromise<Pet> {
return axios.request<Pet>({ url: `/pet/${petId}`, method: 'GET' });
},
};
// SWR hook namespace
export const pet = {
queries: {
useGetPetById(petId: number, $config?: SwrConfig) {
return useSWR<Pet>(pet.queryKeys.getPetById(petId), () =>
petClient.getPetById(petId).then((r) => r.data)
);
},
},
mutations: {
useAddPet($config?: SWRMutationConfiguration<Pet, Error, string, { body: Pet }>) {
return useSWRMutation('/pet', (_key, { arg }) =>
petClient.addPet(arg.body).then((r) => r.data)
);
},
},
queryKeys: {
getPetById: (petId: number) => `/pet/${petId}`,
},
};Dependencies for ["swr", "axios"]:
npm install axios swrDependencies for ["tsq", "xior"]:
npm install xior @tanstack/react-queryClient setup file (--clientSetup)
The --clientSetup <path> flag generates a write-once setup scaffold alongside the main generated client. This is especially important for the ky template, where hooks must be provided at instance creation time.
# ky: generates both api.ts (imports setup) and api.setup.ts (scaffold)
swaggie -s ./openapi.json -o ./src/api.ts -t ky --clientSetup ./src/api.setup.ts
# axios/xior: generates api.setup.ts as a standalone interceptor scaffold
swaggie -s ./openapi.json -o ./src/api.ts -t xior --clientSetup ./src/api.setup.ts| Template | api.ts imports setup file? | Setup file purpose |
|---|---|---|
ky | Yes — api.ts calls createKyConfig() from the setup file | Provide ky hooks (beforeRequest, afterResponse, etc.) |
axios / xior | No | Scaffold showing how to attach interceptors to http |
fetch | No | Scaffold showing how to wrap the default fetch |
The setup file is never overwritten on subsequent runs. Use --forceSetup to regenerate it intentionally (e.g. after upgrading Swaggie).
# Regenerate the setup scaffold (overwrites existing file)
swaggie -s ./openapi.json -o ./src/api.ts -t ky --clientSetup ./src/api.setup.ts --forceSetupSee the ky template section above for a detailed walkthrough and usage examples.
Choosing the right template
| Scenario | Template |
|---|---|
| No framework / Node.js backend | fetch (zero deps) or axios |
| React — prefer minimal bundle size | xior or fetch |
| React — modern fetch-based client | ky |
| React with SWR — backed by axios | ["swr", "axios"] |
| React with SWR — minimal bundle | ["swr", "xior"] or ["swr", "fetch"] |
| React with SWR — ky hooks API | ["swr", "ky"] |
| React with TanStack Query | ["tsq", "xior"] or ["tsq", "axios"] |
| Angular 2+ | ng2 |
| Angular 1 (legacy) | ng1 |
Custom templates
If none of the built-in templates fit your existing HTTP client setup, provide a path to your own template directory:
swaggie -s ./openapi.json -o ./client.ts --template ./my-template/Or in your config file:
{
"template": "./my-template/"
}Custom paths also work in composite pairs. For example, to use your own reactive layer on top of the built-in axios HTTP client template:
{
"template": ["./my-reactive-template/", "axios"]
}Template directory structure
A custom template directory should contain .ejs files. Swaggie renders these files at generation time:
| File | Purpose |
|---|---|
baseClient.ejs | Top of the output file — imports and shared HTTP client setup |
client.ejs | One client object per tag group |
operation.ejs | One method per API operation |
barrel.ejs | Shared helpers appended once at the bottom |
The best way to get started is to copy one of the built-in templates and modify it for your needs.
