Generate the client
Install the generator as a dev dependency and point it at your schema. The generated files are plain TypeScript with no runtime dependency, except axios for the axios client.
Or keep the options in a config file and run npx swagger-typescript-api-es (for example from a gen-api script). All options are described in the options reference.
The examples below use the generated names of the petstore schema: api.pets.listPets, api.pets.getPet, api.store.getInventory, … Method names come from operationId, and routes are grouped by the first path segment (/pets/… → api.pets).
Create a client
Create the client once, in its own module, and import it everywhere. Api extends HttpClient, so the constructor takes the HTTP client config.
fetch
Defaults are replaced, not merged.
baseApiParamsreplaces the built-in defaults (credentials: 'same-origin',redirect: 'follow',referrerPolicy: 'no-referrer'), so repeat the ones you still want. In the same way,baseUrl: undefined(an unset environment variable) removes the default server URL: writeprocess.env.API_URL ?? 'https://…'.
axios
The axios client passes the config to axios.create(), so every AxiosRequestConfig option works.
Your own axios instance
Pass instance to reuse an axios instance that already has interceptors, retries or a custom adapter. The client then uses it as is.
Client options
Call endpoints
Each operation is a method. Path parameters come first as positional arguments, then the query object, then the request body. The last argument is always an optional RequestParams. Everything is typed from the schema, so a wrong field or a missing required property is a compile error.
Per-request options
RequestParams is the per-call escape hatch. For the fetch client it accepts any RequestInit option plus secure, type, format, baseUrl and cancelToken. For axios it is an AxiosRequestConfig plus secure, type and format.
Headers and auth
Headers are merged in this order, the last one wins:
- client defaults:
baseApiParams.headers(fetch) orheaders(axios); - the
headersof the call'sRequestParams; - what the
securityWorkerreturns, for secure requests; - the
Content-Typeof the operation (not set formultipart/form-data, the browser adds the boundary); - finally
injectHeaderscan rewrite the result.
injectHeaders
Both clients accept injectHeaders: (headers) => headers | Promise<headers>. It runs before every request, after all the merging, which makes it the place for values that change over time: a CSRF token, the current locale, a tracing id.
Tokens with securityWorker
The type argument of Api is the type of your security data. Store it with api.setSecurityData() after login, and the securityWorker turns it into request params (usually an Authorization header) for every secure request.
The worker can be async, for example to refresh an expired token first:
Secure routes
- Operations with a
securityrequirement, their own or the schema's global one, are generated withsecure: trueand a@secureJSDoc tag. Only those call the worker. An operation withsecurity: []opts out (likeGET /in the petstore). - To send credentials with every request, set
baseApiParams: { secure: true }(fetch) orsecure: true(axios) in the client config. - To skip the worker for one call, pass
{ secure: false }asRequestParams.
Share one HttpClient
With singleHttpClient: true, Api no longer extends HttpClient: it receives one in its constructor and keeps it in api.http. The transport (base URL, auth, fetch or axios instance) is configured and replaced independently of the API surface, which helps with dependency injection and tests.
One output, one HttpClient.
HttpClienthas private fields, so TypeScript treats the class of each generated output as a different type. Share an instance between the modules of one output, not between two separately generated APIs.
Modular output
With modular: true the output is split into http-client.ts, data-contracts.ts and one class per module (Pets.ts, Store.ts, Users.ts, plus Common.ts for routes like GET /). By default each module class extends HttpClient, so give them the same config:
Add singleHttpClient: true to share one client instead: one config, one setSecurityData() call, and you can group the modules into a single object.
Responses and errors
fetch: HttpResponse
Methods resolve with an HttpResponse<Data, Error>: the native Response (status, headers, ok, …) with the parsed body in data. A non-2xx response rejects with the same object, the parsed error body in error, typed from the schema's error responses.
disableThrowOnError
Generate with disableThrowOnError: true to resolve every HTTP response and branch on ok instead of using try/catch. Network errors still reject.
axios: AxiosError
The axios client resolves with an AxiosResponse<Data> and rejects with an AxiosError. Pass the error type to axios.isAxiosError to type e.response.data.
unwrapResponseData
Generate with unwrapResponseData: true to get the body directly. This works for both clients; failed requests still reject (with the HttpResponse or the AxiosError).
Cancel requests
The fetch client can cancel by token: tag a request with cancelToken and call api.abortRequest(token). Both clients also accept a standard AbortSignal through signal. With the fetch client, cancelToken takes precedence over signal.
Upload and download files
Operations with a multipart/form-data body are generated with type: ContentType.FormData. Pass a plain object that matches the schema: File and Blob values are appended as they are, other objects are sent as JSON. Do not set the Content-Type header yourself.
For downloads, the format decides how the body is read. Responses declared as type: string, format: binary are generated with format: 'blob' and typed File (at runtime the value is a Blob). For other routes, pass format in RequestParams or call api.request():
With axios, format is the responseType: use 'blob' in the browser and 'arraybuffer' or 'stream' in Node.js.
Custom fetch
The fetch client calls customFetch instead of the global fetch when you pass one. Wrap any fetch-compatible function: retries, logging, a polyfill, a test double.
In tests, answer with real Response objects: no network and no mocking library.
For server-side rendering, create one client per incoming request so that headers such as cookies are never shared between users:
Pass a function, not window.fetch. The client calls
this.customFetch(…). Passingwindow.fetchitself can fail with Illegal invocation in browsers; use(...args) => fetch(...args).
React Query and SWR
Generated methods return promises, so they plug into any data-fetching library. Map the response to its data (or generate with unwrapResponseData and pass the method directly), and forward the library's AbortSignal so unused requests are canceled.
A rejected request surfaces as the query's error: the HttpResponse (fetch) or the AxiosError (axios).
Node.js
Node.js 18 and later have fetch, FormData, Blob and File built in, so the fetch client runs unchanged in scripts, CLIs and servers. The axios client works too, with axios installed.
Typing tips
Data contracts
Every schema of components/schemas is exported as a type (and enums as enums, or unions with generateUnionEnums). Import them from Api.ts, or from data-contracts.ts in modular mode. Inline parameter and response types can be derived from the methods.
Route types
With generateRouteTypes: true, each operation also gets a namespace with its RequestParams, RequestQuery, RequestBody, RequestHeaders and ResponseBody types, handy for forms, mocks and server handlers. In modular mode they are written to PetsRoute.ts, StoreRoute.ts, …
Need a different shape? Customize the output with hooks or custom templates, and preview the result in the playground.