
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.
Swaggie generates TypeScript client code from an OpenAPI 3 specification. Instead of writing API-fetching code by hand, you point Swaggie at your API spec and it outputs a fully typed, ready-to-use client — helping you catch errors at compile time rather than at runtime.
See the Example section for a quick demo, or visit the full documentation at yhnavein.github.io/swaggie for guides, configuration reference, and an interactive playground.
Inspired by OpenApi Client.
fetch, axios, xior, Angular 1, Angular 2+; with optional reactive layers (swr, tsq) that compose with any compatible HTTP clientmockSWR() and mockQuery()allOf, oneOf, anyOf, $ref, nullable types, and various enum definitionsvitest and jestInstall as a dev dependency in your project:
npm install swaggie --save-dev
Or install globally to use from anywhere:
npm install swaggie -g
Swaggie supports OpenAPI 3.0 and newer. OpenAPI 2.0 (Swagger) is not supported.
If your backend still produces a 2.0 spec, you have a few options:
Swaggie v0.x if upgrading is not currently possibleRun Swaggie from the command line:
swaggie -s https://petstore3.swagger.io/api/v3/openapi.json -o ./client/petstore.ts
Available options:
-V, --version Output the version number
-c, --config <path> Path to a JSON configuration file
-s, --src <url|path> URL or file path to the OpenAPI spec
-o, --out <filePath> Output file path (omit to print to stdout)
-b, --baseUrl <string> Base URL that will be used as a default value in the clients
-t, --template <string> Template to use. Single name: "axios", "fetch", "xior", "ng1", "ng2", "swr", "tsq". Reactive pair: "swr,axios" / "tsq,xior" / etc. (default: "axios")
-m, --mode <mode> Generation mode: "full" or "schemas" (default: "full")
-d, --schemaStyle <style> Schema object style: "interface" or "type" (default: "interface")
--enumStyle <style> Enum style for plain string enums: "union" or "enum" (default: "union")
--enumNamesStyle <s> Enum member name casing: "original" or "PascalCase" (default: "original")
--dateFormat <format> How date fields are emitted in generated types
--nullables <strategy> Nullable handling: "include", "nullableAsOptional", or "ignore"
--preferAny Use "any" instead of "unknown" for untyped values (default: false)
--skipDeprecated Exclude deprecated operations from the output (default: false)
--servicePrefix Prefix for service names — useful when generating multiple APIs
--allowDots Use dot notation to serialize nested object query params
--arrayFormat How arrays are serialized: "indices", "repeat", or "brackets"
-C, --useClient Prepend 'use client'; directive (Next.js App Router + SWR/TSQ)
--mocks <path> Output path for a generated mock/stub file (requires --testingFramework and --out)
-T, --testingFramework <name> Framework for generated mocks: "vitest" or "jest" (requires --mocks and --out)
-h, --help Show help
Swaggie produces functional TypeScript, but the formatting is not always perfect. It is recommended to pipe the output through a formatter. For example, using Prettier:
swaggie -s $URL -o ./client/petstore.ts && prettier ./client/petstore.ts --write
This can be added as an npm script in your project for easy re-generation.
For anything beyond a one-off run, a configuration file is the cleaner approach. Create a JSON file with your settings and pass it via -c:
swaggie -c swaggie.config.json
Example configuration:
{
"$schema": "https://raw.githubusercontent.com/yhnavein/swaggie/master/schema.json",
"src": "https://petstore3.swagger.io/api/v3/openapi.json",
"out": "./src/client/petstore.ts",
"template": "axios",
"baseUrl": "/api",
"preferAny": true,
"servicePrefix": "",
"dateFormat": "Date",
"nullableStrategy": "ignore",
"generationMode": "full",
"schemaDeclarationStyle": "interface",
"enumDeclarationStyle": "union",
"enumNamesStyle": "original",
"queryParamsSerialization": {
"arrayFormat": "repeat",
"allowDots": true
}
}
The $schema field enables autocompletion and inline documentation in most editors.
Swaggie's templates are split into two independent layers that you can combine freely.
These are standalone and cover the most common client libraries:
| Template | Description |
|---|---|
axios | Default. Recommended for React, Vue, and most Node.js projects |
fetch | Native browser/Node 18+ Fetch API — zero runtime dependencies |
xior | Lightweight Axios-compatible alternative (xior) |
ng1 | Angular 1 client |
ng2 | Angular 2+ client (uses HttpClient and InjectionToken) |
These add a reactive data-fetching layer (SWR or TanStack Query hooks) on top of any compatible http client. They cannot be used alone — pair them with a basic template using a 2-element array:
| Template | Description |
|---|---|
swr | SWR hooks for queries and mutations |
tsq | TanStack Query hooks for queries and mutations |
Compatible http client templates: axios, fetch, xior. Angular clients are not compatible with reactive layers.
Single http template (existing behaviour):
{ "template": "axios" }
swaggie -s ./openapi.json -o ./client.ts -t axios
Pair combination — in config:
{ "template": ["swr", "axios"] }
# CLI: comma-separated pair
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
Reactive template only — defaults to fetch as the http client:
{ "template": "swr" }
Pass the path to your own template directory as the template value:
swaggie -s https://petstore3.swagger.io/api/v3/openapi.json -o ./client/petstore.ts --template ./my-swaggie-template/
Custom paths also work as part of a composite pair: ["./my-l2", "axios"].
Let's say you're building a TypeScript client for the PetStore API. Instead of writing fetch calls by hand, run:
swaggie -s https://petstore3.swagger.io/api/v3/openapi.json -o ./api/petstore.ts && prettier ./api/petstore.ts --write
Swaggie will generate something like this:
// ./api/petstore.ts
import Axios, { AxiosPromise } from 'axios';
const axios = Axios.create({
baseURL: '/api',
paramsSerializer: (params: any) =>
encodeParams(params, null, {
allowDots: true,
arrayFormat: 'repeat',
}),
});
/** [...] **/
export const petClient = {
/**
* @param petId
*/
getPetById(petId: number): AxiosPromise<Pet> {
let url = `/pet/${encodeURIComponent(`${petId}`)}`;
return axios.request<Pet>({
url: url,
method: 'GET',
});
},
// ... and other methods ...
};
You can then use it directly in your application code:
// app.ts
import { petClient } from './api/petstore';
petClient.getPetById(123).then((pet) => console.log('Pet: ', pet));
If the API removes an endpoint you rely on, re-running Swaggie will cause a compile-time error — not a runtime surprise for your users.
Different backends expect query parameters in different formats. Swaggie lets you control this via the queryParamsSerialization config. The default values match what ASP.NET Core expects.
Here's how the object { "a": { "b": 1 }, "c": [2, 3] } is serialized under each combination:
| Result | allowDots | arrayFormat |
|---|---|---|
?a.b=1&c=2&c=3 | true | repeat |
?a.b=1&c[]=2&c[]=3 | true | brackets |
?a.b=1&c[0]=2&c[1]=3 | true | indices |
?a[b]=1&c=2&c=3 | false | repeat |
?a[b]=1&c[]=2&c[]=3 | false | brackets |
?a[b]=1&c[0]=2&c[1]=3 | false | indices |
Once you identify what your backend expects, update your config:
{
"queryParamsSerialization": {
"arrayFormat": "repeat",
"allowDots": true
}
}
OpenAPI 3.0 allows fields to be marked as nullable: true. Swaggie gives you three ways to handle this in the generated TypeScript, via the nullableStrategy option:
| Value | Behavior |
|---|---|
"ignore" (default) | nullable is ignored — the field is typed as if it were not nullable |
"include" | Appends | null to the type (e.g. string | null) |
"nullableAsOptional" | Makes the field optional (?) instead of adding | null |
Example — given tenant: { type: 'string', nullable: true } (required):
// nullableStrategy: "ignore" → tenant: string;
// nullableStrategy: "include" → tenant: string | null;
// nullableStrategy: "nullableAsOptional" → tenant?: string;
Use generationMode (or CLI --mode) to control what gets generated:
| Value | Behavior |
|---|---|
"full" | Generates full client code + used schemas (default, existing behavior) |
"schemas" | Generates only schemas and includes all component schemas by default |
"schemas" mode intentionally does not run the used-schema heuristic.
Use schemaDeclarationStyle (or CLI --schemaStyle) to control object schema output:
| Value | Behavior |
|---|---|
"interface" | export interface Tag { ... } (default) |
"type" | export type Tag = { ... }; |
Use enumDeclarationStyle (or CLI --enumStyle) for plain string enums:
"union" (default): export type Status = "active" | "disabled";"enum": export enum Status { active = "active", disabled = "disabled" }Note: this applies only to plain string enums. Non-string enums are still emitted as union types.
Use enumNamesStyle (or CLI --enumNamesStyle) to control the casing of enum member names when enumDeclarationStyle is "enum":
"original" (default): member names are used exactly as they appear in the spec"PascalCase": member names are converted to PascalCasex-ts-type ExtensionAdd x-ts-type to any schema in your spec to emit a verbatim TypeScript type string instead of deriving it from the schema definition. This is useful for intersection types, complex mapped types, or any TypeScript construct that cannot be expressed in OpenAPI's type system:
ResourceAccess:
x-ts-type: >-
{ items?: { [key: string]: Entry } } & { [key: string]: boolean | Entry | undefined }
type: object # kept for doc/validation purposes
Swaggie emits exactly:
export type ResourceAccess = { items?: { [key: string]: Entry } } & { [key: string]: boolean | Entry | undefined };
x-ts-type takes precedence over all other schema fields, including $ref. See the full documentation for more detail.
Sometimes an API spec marks a parameter as required, but your client handles it in an interceptor and you don't want it cluttering every method signature. Parameter modifiers let you override this globally without touching the spec.
Example:
{
"modifiers": {
"parameters": {
"clientId": "ignore",
"orgId": "optional",
"country": "required"
}
}
}
"ignore" — the parameter is removed from all generated method signatures"optional" — the parameter becomes optional regardless of what the spec says"required" — the parameter is always required (generally better to just fix the spec)Swaggie's output is functional but not always perfectly formatted, since it uses a templating engine internally. It is strongly recommended to run the output through a formatter to ensure consistent style across regenerations.
Prettier (most popular):
prettier ./FILE_PATH.ts --write
Biome (fast alternative):
biome check ./FILE_PATH.ts --apply-unsafe
Either tool needs to be installed separately and configured for your project.
Swaggie can generate a companion mock file alongside your client — a set of typed spy stubs for every method and hook, ready to drop into your tests.
swaggie -s ./spec.json -o ./src/api/client.ts -t swr,axios \
--mocks ./src/__mocks__/api.ts --testingFramework vitest
Or in a config file:
{
"src": "./openapi.json",
"out": "./src/api/client.ts",
"template": ["swr", "axios"],
"mocks": "./src/__mocks__/api.ts",
"testingFramework": "vitest"
}
The generated mock file exports the same names as the real client, so vi.mock('./api', () => import('./__mocks__/api')) is all you need in tests. For (SWR/TSQ) templates, hook stubs come with shorthand helpers:
pet.queries.usePetById.mockSWR({ data: { id: 1, name: 'Rex' } });
pet.mutations.useAddPet.mockSWRMutation({ isMutating: false });
// TanStack Query equivalents: mockQuery() / mockMutation()
See the Mocking guide for full details.
You can also call Swaggie directly from Node.js/bun/deno/etc:
import swaggie from 'swaggie';
swaggie
.genCode({
src: 'https://petstore3.swagger.io/api/v3/openapi.json',
out: './api/petstore.ts',
})
.then(complete, error);
function complete(spec) {
console.info('Service generation complete');
}
function error(e) {
console.error(e.toString());
}
| Supported | Not Supported |
|---|---|
| OpenAPI 3.0, 3.1, 3.2 | Swagger / OpenAPI 2.0 |
allOf, oneOf, anyOf, $ref, external $refs | not keyword |
| Spec formats: JSON, YAML | Very complex query parameter structures |
Extensions: x-position, x-name, x-enumNames, x-enum-varnames, x-ts-type | Multiple response types (only the first is used) |
| Content types: JSON, plain text, multipart/form-data | Multiple request body types (only the first is used) |
Content types: application/x-www-form-urlencoded, application/octet-stream | OpenAPI callbacks and webhooks |
| Various enum definition styles, support for additionalProperties | |
| Nullable types, path inheritance, JSDoc descriptions | |
| Remote URLs and local file paths as spec source | |
| Grouping by tags, graceful handling of duplicate operation IDs |
FAQs
Generate a fully typed TypeScript API client from your OpenAPI 3 spec
The npm package swaggie receives a total of 1,372 weekly downloads. As such, swaggie popularity was classified as popular.
We found that swaggie demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.