{"id":45422087,"url":"https://github.com/urmzd/openapi-generator","last_synced_at":"2026-03-10T00:06:09.064Z","repository":{"id":337767628,"uuid":"1155036912","full_name":"urmzd/openapi-generator","owner":"urmzd","description":"OpenAPI 3.x → TypeScript \u0026 React code generator. Zero-dependency clients, SWR hooks, and SSE streaming.","archived":false,"fork":false,"pushed_at":"2026-02-25T07:06:03.000Z","size":2163,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-25T09:47:19.946Z","etag":null,"topics":["cli","codegen","openapi","openapi-generator","react","rust","server-sent-events","sse","swr","typescript"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/urmzd.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-11T03:43:04.000Z","updated_at":"2026-02-25T07:06:06.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/urmzd/openapi-generator","commit_stats":null,"previous_names":["urmzd/openapi-generator"],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/urmzd/openapi-generator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urmzd%2Fopenapi-generator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urmzd%2Fopenapi-generator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urmzd%2Fopenapi-generator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urmzd%2Fopenapi-generator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/urmzd","download_url":"https://codeload.github.com/urmzd/openapi-generator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/urmzd%2Fopenapi-generator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30317672,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-09T20:05:46.299Z","status":"ssl_error","status_checked_at":"2026-03-09T19:57:04.425Z","response_time":61,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","codegen","openapi","openapi-generator","react","rust","server-sent-events","sse","swr","typescript"],"created_at":"2026-02-22T01:40:49.960Z","updated_at":"2026-03-10T00:06:09.058Z","avatar_url":"https://github.com/urmzd.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# oag\n\nOpenAPI 3.x code generator with a plugin-style architecture supporting TypeScript, React, and Python FastAPI.\n\n![demo](doc/demo.gif)\n\n## Why oag?\n\nOpenAPI 3.2 shipped but most generators haven't caught up. When you need to glue a frontend to a backend during a POC, you don't want to fight a generator that produces bloated code requiring heavy post-processing.\n\n`oag` focuses on simplicity: one config file, one command, clean output.\n\n- Parses OpenAPI 3.x specs with full `$ref` resolution\n- Plugin-style architecture: enable only the generators you need\n- **TypeScript/Node client** with zero runtime dependencies\n- **React/SWR hooks** for queries, mutations, and SSE streaming\n- **Python FastAPI server** with Pydantic v2 models\n- First-class Server-Sent Events support via `AsyncGenerator` (TS) and `StreamingResponse` (Python)\n- **Test generation** — pytest tests for FastAPI, vitest tests for TypeScript/React (opt-out via `scaffold.test_runner: false`)\n- Scaffolds Biome + tsdown configuration for TypeScript projects, Ruff for Python\n- Configurable naming strategies and operation aliases\n- Three layout modes per generator: bundled, modular, or split\n\n## Quick start\n\nInstall with a single command (Linux/macOS):\n\n```sh\ncurl -fsSL https://raw.githubusercontent.com/urmzd/openapi-generator/main/install.sh | sh\n```\n\nOr install from crates.io (requires Rust):\n\n```sh\ncargo install oag-cli\n```\n\nWindows users can download binaries directly from the\n[latest release](https://github.com/urmzd/openapi-generator/releases/latest).\n\n\u003cdetails\u003e\n\u003csummary\u003eBuild from source\u003c/summary\u003e\n\n```sh\ngit clone https://github.com/urmzd/openapi-generator.git\ncd openapi-generator\ncargo install --path crates/oag-cli\n```\n\n\u003c/details\u003e\n\nInitialize a config file:\n\n```sh\noag init\n```\n\nThis creates `.urmzd.oag.yaml` in the current directory:\n\n\u003c!-- embed-src src=\"crates/oag-core/default-config.yaml\" fence=\"yaml\" --\u003e\n```yaml\n# oag configuration — https://github.com/urmzd/openapi-generator\n#\n# This file is loaded automatically from the current directory when running `oag generate`.\n# You can override the input spec with: oag generate -i other-spec.yaml\n#\n# Full reference: https://github.com/urmzd/openapi-generator#configuration\n\n# ---------------------------------------------------------------------------\n# Input\n# ---------------------------------------------------------------------------\n# Path to your OpenAPI 3.x spec (YAML or JSON), relative to this config file.\ninput: openapi.yaml\n\n# ---------------------------------------------------------------------------\n# Naming\n# ---------------------------------------------------------------------------\n# Controls how operation names (function/method names) are derived.\nnaming:\n  # Strategy for deriving operation names:\n  #   use_operation_id  — use the operationId field from the spec (default)\n  #   use_route_based   — derive from HTTP method + path (e.g., GET /pets → getPets)\n  strategy: use_operation_id\n\n  # Custom aliases to rename specific operations. Applied after the naming strategy.\n  # Keys are the resolved operation name, values are the desired alias.\n  aliases: {}\n    # createChatCompletion: chat     # operationId → custom name\n    # listModels: models\n\n# ---------------------------------------------------------------------------\n# Generators\n# ---------------------------------------------------------------------------\n# Each key is a generator ID. Only generators listed here will run.\n# Available generators:\n#   node-client       — TypeScript/Node API client (zero runtime dependencies)\n#   react-swr-client  — React/SWR hooks (extends node-client with hooks + context provider)\n#   fastapi-server    — Python FastAPI server stubs with Pydantic v2 models\ngenerators:\n  node-client:\n    # Directory where generated files are written. Created automatically.\n    output: src/generated/node\n\n    # How files are organized:\n    #   bundled  — single file (src/index.ts)\n    #   modular  — separate files per concern: types.ts, client.ts, sse.ts, index.ts (default)\n    #   split    — separate files per operation group (see split_by)\n    layout: modular\n\n    # Only used with layout: split. Controls how operations are grouped into files:\n    #   tag        — one file per OpenAPI tag (default)\n    #   operation  — one file per operation\n    #   route      — one file per route prefix\n    # split_by: tag\n\n    # Override the API base URL instead of reading from the spec's servers array.\n    # Useful when the spec omits a server or you need a different URL for development.\n    # base_url: https://api.example.com\n\n    # Set to true to disable JSDoc comments on generated types and methods.\n    # no_jsdoc: false\n\n    # Subdirectory within output for generated source files.\n    # Scaffold files (package.json, tsconfig, etc.) always stay at the output root.\n    # Set to \"\" to place source files directly at the output root.\n    # source_dir: src\n\n    # Set scaffold to false to disable all scaffolding (for existing projects).\n    # scaffold: false\n    #\n    # Scaffold controls which project configuration files are generated alongside\n    # the source code. Set individual tools to false to disable them.\n    scaffold:\n      # NPM package name. Defaults to a slugified version of the spec's info.title.\n      # package_name: my-api-client\n\n      # Repository URL included in package.json.\n      # repository: https://github.com/you/your-repo\n\n      # Set to true to skip scaffold files (package.json, tsconfig, biome, tsdown)\n      # but still emit a root index.ts re-export. Useful when adding generated code\n      # to an existing project with its own build configuration.\n      # existing_repo: false\n\n      # Code formatter. Generates biome.json and auto-formats after generation.\n      # Set to false to disable.\n      formatter: biome        # biome | false\n\n      # Test runner. Generates vitest test files and adds vitest to package.json.\n      # Set to false to disable test generation.\n      test_runner: vitest     # vitest | false\n\n      # Bundler. Generates tsdown.config.ts for building distributable packages.\n      # Set to false to disable.\n      bundler: tsdown         # tsdown | false\n\n  # react-swr-client:\n  #   output: src/generated/react\n  #   layout: modular           # only modular is supported for react-swr-client\n  #   # base_url: https://api.example.com\n  #   # no_jsdoc: false\n  #   # source_dir: src\n  #   scaffold:\n  #     # package_name: my-react-client\n  #     formatter: biome        # biome | false\n  #     test_runner: vitest     # vitest | false\n  #     bundler: tsdown         # tsdown | false\n\n  # fastapi-server:\n  #   output: src/generated/server\n  #   layout: modular           # only modular is supported for fastapi-server\n  #   scaffold:\n  #     # package_name: my_api_server\n  #     formatter: ruff         # ruff | false — auto-formats and lints after generation\n  #     test_runner: pytest     # pytest | false — generates pytest tests with async httpx client\n```\n\u003c!-- /embed-src --\u003e\n\nGenerate code:\n\n```sh\noag generate\n```\n\nThis will generate code for all configured generators. You can override the input spec:\n\n```sh\noag generate -i other-spec.yaml\n```\n\n**Note**: The old config format (with `target`, `output`, `output_options`, and `client` fields) is still supported for backward compatibility and automatically converted.\n\n## CLI reference\n\n| Command | Description | Key flags |\n|---------|-------------|-----------|\n| `oag generate` | Generate code from an OpenAPI spec | `-i, --input \u003cPATH\u003e` — override spec path |\n| `oag validate` | Validate an OpenAPI spec and report its contents | `-i, --input \u003cPATH\u003e` **(required)** |\n| `oag inspect` | Dump the parsed intermediate representation | `-i, --input \u003cPATH\u003e` **(required)**, `--format yaml\\|json` |\n| `oag init` | Create a `.urmzd.oag.yaml` config file | `--force` — overwrite existing |\n| `oag completions` | Generate shell completions | `\u003cSHELL\u003e` — bash, zsh, fish, powershell, elvish |\n\nRun `oag \u003ccommand\u003e --help` for detailed usage. Set `RUST_LOG=debug` for verbose output.\n\n## Configuration\n\nAll options are set in `.urmzd.oag.yaml`. The CLI supports `-i/--input` to override the input spec path.\n\n### Global options\n\n| Key | Type | Default | Description |\n|-----|------|---------|-------------|\n| `input` | `string` | `openapi.yaml` | Path to the OpenAPI spec (YAML or JSON) |\n| `naming.strategy` | `string` | `use_operation_id` | How to derive function names: `use_operation_id` or `use_route_based` |\n| `naming.aliases` | `map` | `{}` | Map of operationId to custom name overrides |\n\n### Generators\n\nThe `generators` map configures which generators to run and their options. Each generator has its own output directory and settings.\n\n**Available generators:**\n- `node-client` — TypeScript/Node API client (zero dependencies)\n- `react-swr-client` — React/SWR hooks (extends node-client)\n- `fastapi-server` — Python FastAPI server stubs with Pydantic v2 models\n\n### Generator options (node-client, react-swr-client, fastapi-server)\n\n| Key | Type | Default | Description |\n|-----|------|---------|-------------|\n| `output` | `string` | **required** | Output directory for this generator |\n| `layout` | `string` | `modular` | Layout mode: `bundled` (single file), `modular` (separate files per concern), or `split` (separate files per operation group) |\n| `split_by` | `string` | `tag` | Only for `split` layout: `operation`, `tag`, or `route` |\n| `base_url` | `string` | *(from spec servers)* | Override the API base URL (TypeScript generators only) |\n| `no_jsdoc` | `bool` | `false` | Disable JSDoc comments (TypeScript generators only) |\n| `source_dir` | `string` | `\"src\"` | Subdirectory for generated source files — set to `\"\"` to place files at the output root (TypeScript generators only) |\n| `scaffold.package_name` | `string` | *(from spec title)* | Custom package name (TypeScript: npm, Python: pyproject.toml) |\n| `scaffold.repository` | `string` | | Repository URL for package metadata |\n| `scaffold.formatter` | `string` or `false` | `biome` (TS) / `ruff` (Python) | Code formatter — set to `false` to disable |\n| `scaffold.test_runner` | `string` or `false` | `vitest` (TS) / `pytest` (Python) | Test runner — set to `false` to disable test generation |\n| `scaffold.bundler` | `string` or `false` | `tsdown` | Bundler config (TypeScript only) — set to `false` to disable |\n| `scaffold.existing_repo` | `bool` | `false` | Set to `true` to skip all scaffold files (package.json, tsconfig, biome, tsdown) and only emit a root `index.ts` re-export |\n\n### Layout modes\n\n- **bundled** — Everything in a single file (e.g., `src/index.ts` or `main.py`)\n- **modular** — Separate files per concern (e.g., `src/types.ts`, `src/client.ts`, `src/sse.ts`, `src/index.ts`)\n- **split** — Separate files per operation group (e.g., `src/pets.ts`, `src/users.ts`, `src/orders.ts`)\n\nFor TypeScript generators, source files are placed in a `src/` subdirectory by default (configurable via `source_dir`). This matches the scaffold's tsconfig.json (`rootDir`, `include`) and tsdown.config.ts (`entry`) — all of which adapt automatically to the configured `source_dir`. Set `source_dir: \"\"` to place files directly at the output root. Scaffold files (`package.json`, `tsconfig.json`, `biome.json`, `tsdown.config.ts`) always remain at the output root.\n\nWhen using `split` layout, specify `split_by`:\n- `operation` — One file per operation\n- `tag` — One file per OpenAPI tag (default)\n- `route` — One file per route prefix\n\n### Backward compatibility\n\nThe old config format (with `target`, `output`, `output_options`, and `client` fields) is still supported and automatically converted to the new format.\n\n## Architecture\n\n```\noag-cli  --\u003e  [oag-node-client, oag-react-swr-client, oag-fastapi-server]  --\u003e  oag-core\n```\n\nThe workspace uses a plugin-style architecture with five crates:\n\n| Crate | Role |\n|-------|------|\n| [`oag-core`](crates/oag-core/) | OpenAPI parser, intermediate representation, transform pipeline, and `CodeGenerator` trait |\n| [`oag-node-client`](crates/oag-node-client/) | TypeScript/Node API client generator (zero dependencies) |\n| [`oag-react-swr-client`](crates/oag-react-swr-client/) | React/SWR hooks generator (extends node-client) |\n| [`oag-fastapi-server`](crates/oag-fastapi-server/) | Python FastAPI server generator with Pydantic v2 models |\n| [`oag-cli`](crates/oag-cli/) | Command-line interface that orchestrates all generators |\n\n`oag-core` defines the `CodeGenerator` trait:\n\n```rust\npub trait CodeGenerator {\n    fn id(\u0026self) -\u003e config::GeneratorId;\n    fn generate(\n        \u0026self,\n        ir: \u0026ir::IrSpec,\n        config: \u0026config::GeneratorConfig,\n    ) -\u003e Result\u003cVec\u003cGeneratedFile\u003e, GeneratorError\u003e;\n}\n```\n\nEach generator implements this trait with a unique ID (`node-client`, `react-swr-client`, or `fastapi-server`). The CLI loops over the configured generators in `.urmzd.oag.yaml` and invokes each one.\n\n## Examples\n\nWorking examples with generated output are in the [`examples/`](examples/) directory:\n\n- **[`petstore`](examples/petstore/)** — Node client and React client generated from the Petstore 3.2 spec\n- **[`sse-chat`](examples/sse-chat/)** — Node client and React hooks with SSE streaming for a chat API\n\nEach example has its own `.urmzd.oag.yaml` configuring generators with separate output directories (e.g. `generated/node` and `generated/react`).\n\nRegenerate them with:\n\n```sh\njust examples\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Furmzd%2Fopenapi-generator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Furmzd%2Fopenapi-generator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Furmzd%2Fopenapi-generator/lists"}