@bazo/openapi-client-generator
v3.0.18
Published
Generate type-safe API clients from an OpenAPI / Swagger JSON spec. One CLI, five output targets:
Readme
@bazo/openapi-client-generator
Generate type-safe API clients from an OpenAPI / Swagger JSON spec. One CLI, five output targets:
| Mode | Output | Stack |
|------|--------|-------|
| full (default) | .ts | React Query hooks + Wretch HTTP client + Zod validation |
| playwright | .ts | Class wrapping Playwright's APIRequestContext for E2E tests + Zod validation |
| swift | .swift | Codable structs + async/await client (Foundation only) |
| kotlin | .kt | @Serializable data classes + Ktor-based suspend client |
| php | directory of .php | PSR-4 classes + backed enums + Symfony HttpClient/Serializer client |
Schemas are normalized, sorted by dependency, and emitted with full types; unused declarations are stripped from TypeScript output automatically.
Installation
npm install -D @bazo/openapi-client-generator
# or: bun add -d @bazo/openapi-client-generatorYou can also run it without installing:
npx @bazo/openapi-client-generator api.json src/api -n MyClientUsage
openapi-client-generator <spec.json> <output-dir> -n <ClientName> [-m <mode>]| Option | Description |
|--------|-------------|
| <spec.json> | Path to the OpenAPI/Swagger JSON spec (positional, required) |
| <output-dir> | Directory to write the generated file into (positional, required) |
| -n, --name | Client/class name — must be a valid identifier (required) |
| -m, --mode | full | playwright | swift | kotlin | php (default: full) |
| --namespace | Root PHP namespace, php mode only (default: --name) |
| --php-version | Target PHP version, php mode only: 8.0–8.5 (default: 8.1) |
| -v, --version | Print version |
| -h, --help | Print help |
The output file is named after --name with the extension chosen by the mode (MyClient.ts, ApiClient.swift, ApiClient.kt). The php mode instead writes a directory named after --name containing one PSR-4 file per class.
# React Query client
openapi-client-generator api.json src/api -n MyClient
# Playwright E2E client
openapi-client-generator api.json tests/api -n TestApi -m playwright
# Swift client
openapi-client-generator api.json Sources/Api -n ApiClient -m swift
# Kotlin client
openapi-client-generator api.json src/main/kotlin -n ApiClient -m kotlin
# PHP client
openapi-client-generator api.json src/Api -n ApiClient -m php --namespace "App\\Api" --php-version 8.2A handy package.json script:
{
"scripts": {
"gen:api": "openapi-client-generator ./openapi.json ./src/api -n MyClient"
}
}Generated client examples
full — React Query
Peer dependencies: zod, wretch, @tanstack/react-query.
import { QueryClient } from "@tanstack/react-query";
import { MyClient } from "./api/MyClient";
const queryClient = new QueryClient();
const api = new MyClient("https://api.example.com", queryClient);
function TaskList() {
const { data, isLoading } = api.listTasks.useQuery({ page: 1, limit: 10 });
const create = api.createTask.useMutation();
// ...
}Constructor: new MyClient(baseUrl, queryClient, options?, onHttpConfigure?). Each operation exposes query/mutation (raw) and useQuery/useMutation (hooks); responses are typed as ApiResponse<T> and validated with Zod.
playwright — E2E testing
Peer dependencies: zod, @playwright/test.
import { test, expect } from "@playwright/test";
import { TestApi } from "./api/TestApi";
test("list tasks returns 200", async ({ request }) => {
const api = new TestApi(request);
const result = await api.listTasks({ page: 1, limit: 10 });
expect(result.status).toBe(200);
expect(result.data.items.length).toBeGreaterThan(0);
});Constructor takes Playwright's APIRequestContext (the { request } fixture). Operations are async methods returning a Zod-validated ApiResponse<T>.
swift — iOS / macOS
No external dependencies (Foundation only). Add the .swift file to your Xcode project.
let api = ApiClient(baseURL: URL(string: "https://api.example.com")!)
let response = try await api.listTasks(page: 1, limit: 10)Constructor: init(baseURL: URL, session: URLSession = .shared). Schemas are Codable structs; failures throw an APIError enum.
kotlin — Android / JVM
Uses Ktor + kotlinx.serialization.
val httpClient = HttpClient(CIO) {
install(ContentNegotiation) { json() }
}
val api = ApiClient(client = httpClient, baseUrl = "https://api.example.com")
val response = api.listTasks(page = 1, limit = 10)Constructor: ApiClient(client: HttpClient, baseUrl: String). Schemas are @Serializable data classes; operations are suspend functions returning ApiResponse<T> and throw ApiException on error.
// build.gradle.kts
plugins { kotlin("plugin.serialization") version "2.1.0" }
dependencies {
implementation("io.ktor:ktor-client-core:3.1.0")
implementation("io.ktor:ktor-client-cio:3.1.0")
implementation("io.ktor:ktor-client-content-negotiation:3.1.0")
implementation("io.ktor:ktor-serialization-kotlinx-json:3.1.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0")
}php — Symfony HttpClient
Composer dependencies: symfony/http-client, symfony/serializer, symfony/property-info, symfony/property-access, phpdocumentor/reflection-docblock.
use App\Api\ApiClient;
use Symfony\Component\HttpClient\HttpClient;
$api = new ApiClient(HttpClient::create(), 'https://api.example.com');
$response = $api->listTasks(page: 1, limit: 10);
$response->data; // typed model, hydrated via Symfony Serializer
$response->status; // 200Constructor: new ApiClient(HttpClientInterface $client, string $baseUrl, ?SerializerInterface $serializer = null) (a sensible serializer is built by the generated SerializerFactory when omitted). Output is a PSR-4 directory — models under Model/, plus ApiResponse, ApiException (thrown on every non-2xx), and the client class. --php-version gates emitted features: backed enums + readonly need 8.1+, readonly class 8.2+, typed constants 8.3+, #[\Deprecated] 8.4+, #[\NoDiscard] + Uri\Rfc3986 URL building 8.5. Code generated for 8.0 uses serializer ^5.4|^6.x (AnnotationLoader); 8.1+ requires serializer >= 6.4.
Agent skills
The package ships agent skills — Markdown playbooks for AI coding agents covering CLI usage (generate-client) and per-mode integration (integrate-{full,playwright,swift,kotlin,php}-client). Compatible tools discover them automatically once the package is installed.
Development
bun install
task test # run the vitest suite
task lint # oxlint
task build # bundle src/bin.ts -> dist/bin.js
task run # generate a sample client from fixtures/api.json into out/Run a single test file: bun vitest run src/__tests__/converter/primitives.test.ts
See CLAUDE.md for architecture details and the full task list. task run-pw, task run-swift, task run-kotlin, and task run-php generate sample clients for the other modes. Runtime integration tests (task test-runtime) require a Java/Gradle toolchain (Kotlin), a Swift toolchain (Swift), or PHP >= 8.1 + Composer (PHP) and are skipped otherwise.
License
No license has been declared for this package yet. Add a LICENSE file and a license field to package.json / package.json.dist before publishing publicly.
