Skip to content

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:

TemplateHTTP ClientBest for
axiosAxiosReact, Vue, Node.js — the most widely used default
fetchNative fetchBrowser apps or Node 18+ with no extra dependencies
xiorxiorLightweight Axios-compatible alternative
kykyModern fetch-based client with hooks API
ng1Angular 1 $httpLegacy Angular 1.x applications
ng2Angular HttpClientAngular 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:

bash
npm install axios

Generated output (excerpt):

typescript
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):

typescript
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:

bash
npm install xior

ky

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:

bash
npm install ky

Generated output (excerpt):

typescript
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.

bash
swaggie -s ./openapi.json -o ./src/api.ts -t ky --clientSetup ./src/api.setup.ts

On the first run, this generates two files:

  • src/api.ts — the main generated client, now using initKyHttp() / getKyHttp() instead of a simple singleton
  • src/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):

typescript
// 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):

typescript
import { initKyHttp } from './api';
initKyHttp(); // call once at startup, before any API requests

Passing 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:

typescript
// 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:

typescript
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.

TemplateLibraryBest for
swrSWRReact apps using SWR for server state
tsqTanStack QueryReact 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

json
{
  "template": ["swr", "axios"]
}

On the CLI

bash
# 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,axios

Reactive layer alone — defaults to fetch

If you pass only a reactive layer template name without a companion HTTP client template, Swaggie defaults to fetch:

json
{ "template": "swr" }

This is equivalent to ["swr", "fetch"].

Valid combinations

Reactive layerCompatible HTTP client templates
swraxios, fetch, xior, ky
tsqaxios, fetch, xior, ky

Generated output (excerpt for ["swr", "axios"])

typescript
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"]:

bash
npm install axios swr

Dependencies for ["tsq", "xior"]:

bash
npm install xior @tanstack/react-query

Client 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.

bash
# 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
Templateapi.ts imports setup file?Setup file purpose
kyYesapi.ts calls createKyConfig() from the setup fileProvide ky hooks (beforeRequest, afterResponse, etc.)
axios / xiorNoScaffold showing how to attach interceptors to http
fetchNoScaffold 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).

bash
# Regenerate the setup scaffold (overwrites existing file)
swaggie -s ./openapi.json -o ./src/api.ts -t ky --clientSetup ./src/api.setup.ts --forceSetup

See the ky template section above for a detailed walkthrough and usage examples.


Choosing the right template

ScenarioTemplate
No framework / Node.js backendfetch (zero deps) or axios
React — prefer minimal bundle sizexior or fetch
React — modern fetch-based clientky
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:

bash
swaggie -s ./openapi.json -o ./client.ts --template ./my-template/

Or in your config file:

json
{
  "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:

json
{
  "template": ["./my-reactive-template/", "axios"]
}

Template directory structure

A custom template directory should contain .ejs files. Swaggie renders these files at generation time:

FilePurpose
baseClient.ejsTop of the output file — imports and shared HTTP client setup
client.ejsOne client object per tag group
operation.ejsOne method per API operation
barrel.ejsShared 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.

Released under the MIT License.