Complete OpenAPI 3.0/3.1 generation, diagnostics, lifecycle safety, enum and naming mappings, bilingual documentation, examples, and pub.dev release validation.
373 lines
10 KiB
Markdown
373 lines
10 KiB
Markdown
# 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<T>` 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<void> 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)
|