Generate TypeScript models and Angular services from OpenAPI 3.x specs — fast, deterministic, Rust-powered.
Try it without installing anything: playground (paste a spec, see the output) · StackBlitz demo (generated client used in an Angular app).
Documentation → · Getting started · Angular guide · Node API · Diagnostics
- Rust-powered codegen. The engine is a native binary loaded via NAPI-RS. The same input always produces identical output.
- Angular-first output. Each operation ships with three flavors —
.observable(),.resource(),.request()— matching Angular's current HTTP primitives. - Two layouts. Per-tag
@Injectableservices by default, or--layout operationsfor one tree-shakeable constant per operation, callable from any injection context or bound once withwithInjector(). - Strict OpenAPI subset. A focused 3.x slice with clear diagnostics. No silent misgeneration; see Assumptions & limitations for the accepted shape.
- Configurable naming. Tune method names and service grouping with template + regex rules, via YAML, JSON, or TypeScript config.
- Thin, pass-through helpers. Generated methods just build the request (method, URL, query, body) and forward every
HttpClient.request/httpResourceoption through unchanged —withCredentials,transferCache,reportProgress,equal,injector, and the rest. The response reaches you untouched.
bun add -d @avsystem/openapi-ngRequires Node.js >= 22.12. Pre-built binaries for macOS, Linux (glibc and musl), and Windows (x64 / ARM64). See Runtime & platforms.
openapi-ng generate --input petstore.openapi.yaml --output ./generated✓ Generated 5 files from Petstore (3.0.3)
1 path · 1 operation · 1 schema
model.ts
rest.model.ts
rest.util.ts
rest.validate.ts
rest/pet.rest.ts
Wire a generated service into a component:
import { Component, inject } from '@angular/core';
import { PetRest } from './generated/rest/pet.rest';
@Component({/* ... */})
export class PetList {
readonly #pets = inject(PetRest);
// Signal-based, reactive, with a default value while loading.
readonly list = this.#pets.listPets.resource({ defaultValue: [] });
}Or skip the classes. --layout operations emits one file per operation (rest/pet/list-pets.ts, rest/pet/get-pet.ts, …) plus a barrel rest/pet/index.ts, so the endpoints you never import tree-shake away:
import { Component } from '@angular/core';
import { listPets } from './generated/rest/pet';
@Component({/* ... */})
export class PetList {
// Same three flavors; HttpClient comes from the surrounding injection context.
readonly list = listPets.resource({ defaultValue: [] });
}Both layouts expose the same .observable() / .resource() / .request() surface, and --layout services,operations emits the classes on top of the operation files. Details in the Angular guide.
A validateRest(path, restMethod, opts) helper wraps Angular signal-forms validateAsync and delegates to the generated RequestFn.resource(), preserving request/response typing:
import { validateRest } from './generated/rest.validate';
validateRest(emailPath, accountRest.checkEmail, {
request: ctx => ({ email: ctx.value() }),
onError: () => ({ kind: 'email-taken' }),
});@angular/forms is an optional peer — install it only if you import from rest.validate.ts; the file tree-shakes away when unused.
Full walkthrough on docs.openapi-ng.dev/getting-started.
bun install
bun run build # release build (Rust + NAPI)
bun run build:debug # debug build (faster compile)
bun run test # Node integration tests (AVA)
cargo test # Rust unit tests
bun run lint # oxlint
bun run format # oxfmt + rustfmt + taploRust changes require a rebuild (bun run build or bun run build:debug) before tests reflect them.
Bug reports and PRs welcome at github.com/AVSystem/openapi-ng.
MIT © 2026