# koi_swagger_parser [English](README.md) | [Chinese (Simplified)](README.zh-CN.md) `koi_swagger_parser` is an OpenAPI 3.0/3.1 Dart and Flutter client generator for projects that use Dio, Retrofit, Freezed, and json_serializable. It separates document loading, `$ref` resolution, validation, an intermediate representation (IR), rendering, and safe incremental writes. Generated code follows a Koi-oriented layout: ```text lib/src/ api/ api_client.dart index.dart v1/ index.dart stores_api.dart api_models/ api_models.dart request/ result/ shared/ enums/ ``` ## Features - Local JSON/YAML files, HTTP(S) documents, multiple root documents, and local, relative, file, and remote `$ref` values. - Component reference resolution, caching, cycle detection, deterministic conflict handling, and dependency tracking. - Retrofit APIs and Freezed/json_serializable request, response, shared, enum, and union models. - `enum_mappings`, legacy `enum_key_mappings`, `x-enumNames`, `x-enum-varnames`, `x-enum-values`, descriptions, and optional unknown enum fallback. - Model, property, parameter, operation, schema, type, and import mappings with collision diagnostics. - OpenAPI path, query, header, and cookie parameters, including supported style, explode, and `allowReserved` combinations. - JSON, text, multipart, form-urlencoded, and binary requests; byte and stream downloads. - Multiple successful responses, 204, `2XX`, `default` and error responses, response headers, and optional `HttpResponse` results. - Required, nullable, and absent-value semantics; read-only/write-only projections; `additionalProperties`; `allOf`; and supported `oneOf`/`anyOf` forms. - Server variables and security metadata. Credentials remain the responsibility of the host application's Dio interceptor or provider. - Exact, glob, and regular-expression filters. - A locked manifest, SHA-256 change detection, safe stale-file cleanup, atomic writes, dry runs, and optional build_runner integration. See the [compatibility matrix](doc/COMPATIBILITY.md) for precise boundaries. ## Requirements - Dart SDK `^3.11.0`. - An OpenAPI 3.0.x or 3.1.x document in JSON or YAML. - A host Dart or Flutter project configured for Retrofit, Freezed, and json_serializable when generating both APIs and models. ## Installation Add the generator as a development dependency in the host project: ```bash dart pub add --dev koi_swagger_parser ``` For a typical generated client, add these host runtime dependencies: ```bash dart pub add dio retrofit freezed_annotation json_annotation ``` Add the matching code-generation tools: ```bash dart pub add --dev build_runner retrofit_generator freezed json_serializable ``` For Flutter projects, use `flutter pub add` in place of `dart pub add` if that is how the project manages dependencies. ## Quick start 1. Copy [the complete configuration template](koi_swagger_parser.example.yaml) to `koi_swagger_parser.yaml` in the host project. 2. Set at least one OpenAPI source and the output directories: ```yaml input: swagger_urls: - url: ./openapi.json enabled: true output: base_dir: ./lib/src api_dir: ./lib/src/api models_dir: ./lib/src/api_models generation: preset: name: koi_flutter api: enabled: true use_retrofit: true response_wrapper: mode: passthrough models: enabled: true class_prefix: Koi formatting: run_dart_format: true run_build_runner: true build_runner_mode: build ``` 3. Preview the change set: ```bash dart run koi_swagger_parser generate --all --dry-run ``` 4. Generate the client: ```bash dart run koi_swagger_parser generate --all ``` When `formatting.run_build_runner` is `false`, run build_runner separately: ```bash dart run build_runner build --delete-conflicting-outputs ``` ## CLI usage ```text dart run koi_swagger_parser generate [options] --all, -a Generate all enabled resources. Kept for command compatibility. --config, -c Configuration file path. --cwd Host project working directory. --dry-run Parse and render without writing or deleting files. --watch Start build_runner watch after generation. --verbose, -v Print informational diagnostics and failure stack traces. ``` The loader searches the working directory for, in order: 1. `koi_swagger_parser.yaml` 2. `koi_swagger_parser.yml` 3. `generator_config.yaml` 4. `generator_config.yml` When `--config` points to a file outside the current directory and `--cwd` is not set, the configuration directory becomes the host project working directory. Relative sources and output paths are resolved against the configuration directory. `--cwd` changes where host-project commands run; it does not change those path semantics. ## Library usage The same pipeline is available as a Dart API: ```dart import 'package:koi_swagger_parser/koi_swagger_parser.dart'; Future main() async { final result = await const KoiSwaggerParser().generate( configPath: 'koi_swagger_parser.yaml', dryRun: true, ); print('${result.operationsCount} operations'); print('${result.modelsCount} models'); for (final diagnostic in result.diagnostics) { print(diagnostic.format()); } } ``` On diagnostic errors, generation throws `KoiDiagnosticException`. Automation should match diagnostic `code` values instead of message text. See [Diagnostics](doc/DIAGNOSTICS.md). ## Enum mappings Enum wire values can be mapped to stable Dart member names in configuration: ```yaml generation: models: enum_unknown_fallback: true enum_mappings: OrderStatus: - value: pending name: waitingForPayment description: Waiting for payment - value: done name: completed description: Completed ``` Map syntax is also accepted: ```yaml generation: models: enum_mappings: OrderStatus: pending: waitingForPayment done: name: completed description: Completed ``` The legacy `enum_key_mappings` field remains supported. Name resolution uses this precedence: 1. `enum_mappings` 2. `enum_key_mappings` 3. `x-enumNames`, `x-enum-names`, or `x-enum-varnames` 4. `x-enum-values` 5. A name derived from the wire value Descriptions use configuration first, then `x-enumDescriptions`, `x-enum-descriptions`, and `x-enum-values.description`. With `enum_unknown_fallback: true`, the generator adds a stable `unknown` member and applies `JsonKey.unknownEnumValue` to enum references. ## Naming and type mappings ```yaml generation: mappings: models: UserDto: User properties: UserDto: user_id: id parameters: getUser: user_id: id operations: getUser: fetchUser "DELETE /api/v1/users/{id}": removeUser schemas: Money: type: Money import: package:money2/money2.dart types: string:uuid: type: UuidValue import: package:uuid/uuid_value.dart integer:int64: int imports: UuidValue: package:uuid/uuid_value.dart ``` Operation mapping keys accept either an `operationId` or `METHOD /path`. Schema mappings mark a schema as externally implemented, so no model is generated for it. The external type must provide the JSON conversion behavior required by its generated usage. ## Responses and transport ```yaml generation: api: cancel_token_support: true response_mode: http_response # body | http_response binary_response_mode: bytes # bytes | stream client: class_name: ApiClient file_name: api_client response_wrapper: mode: external_generic # passthrough | external_generic success_data_field: data detect_standard_envelope: true external_generic: import: package:your_network/your_network.dart class_name: BaseResult ``` When Retrofit annotations cannot represent a supported matrix, label, cookie, deep-object, or reserved-character parameter, the generator emits a typed transport adapter in front of a private Retrofit delegate. A `default` response is always treated as an error response. ## Filtering and lifecycle ```yaml output: included_tags: [stores] excluded_paths: [/internal/**] included_operations: [getStore, "POST /api/v1/stores"] excluded_models: [Legacy*] clean_stale_files: true skip_if_unchanged: true manifest_path: ./.dart_tool/koi_swagger_parser/manifest.json ``` Filters accept exact values, `*`, `?`, and `**` globs, or Dart regular expressions prefixed with `regex:`. Exclusions take precedence over inclusions. `included_models` can add otherwise unreferenced components as generation roots. The manifest records only files owned by this generator. Stale cleanup removes an old generated file only when it is still inside the configured API/model roots and its content still matches the previous manifest hash. Modified files and handwritten neighbors are preserved. ## Limitations The current release intentionally does not generate: - Swagger/OpenAPI 2.0 clients. - Callbacks, webhooks, or Link Object call chains. - XML, Protobuf, or arbitrary custom codecs. - A complete JSON Schema 2020-12 implementation. - Server stubs, mock servers, or non-Dart targets. - A pluggable external renderer/template API. Unsupported or lossy constructs produce structured warnings or errors; they are not silently presented as fully supported. Consult [Compatibility](doc/COMPATIBILITY.md) before adopting the generator for a new schema corpus. ## Documentation - [Configuration reference](doc/CONFIGURATION.md) - [Compatibility matrix](doc/COMPATIBILITY.md) - [Diagnostics reference](doc/DIAGNOSTICS.md) - [Architecture](doc/ARCHITECTURE.md) - [Migration from swagger_generator_flutter](doc/MIGRATION.md) - [Changelog](CHANGELOG.md) ## Development ```bash dart pub get dart format . dart analyze dart test dart run tool/verify_generated_package.dart ``` The final command creates a temporary Dart package, invokes this generator and its build_runner integration, and then runs analysis and runtime tests in the generated package. ## Support and contributing Use [GitHub Issues](https://github.com/mrkoi-is/koi_swagger_parser/issues) for reproducible bug reports and feature requests. Include the generator version, Dart version, a minimal OpenAPI document, the relevant configuration, and diagnostic codes. Remove credentials and private service data before sharing a reproduction. Contributions should include focused tests and update the compatibility matrix and configuration reference when behavior changes. Run the development checks above before opening a pull request. ## License [MIT](LICENSE)