Files
mr.koi 454e6c51d7 Release 0.2.0
Complete OpenAPI 3.0/3.1 generation, diagnostics, lifecycle safety, enum and naming mappings, bilingual documentation, examples, and pub.dev release validation.
2026-07-31 16:47:39 +08:00

10 KiB

koi_swagger_parser

English | Chinese (Simplified)

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:

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 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:

dart pub add --dev koi_swagger_parser

For a typical generated client, add these host runtime dependencies:

dart pub add dio retrofit freezed_annotation json_annotation

Add the matching code-generation tools:

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 to koi_swagger_parser.yaml in the host project.
  2. Set at least one OpenAPI source and the output directories:
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
  1. Preview the change set:
dart run koi_swagger_parser generate --all --dry-run
  1. Generate the client:
dart run koi_swagger_parser generate --all

When formatting.run_build_runner is false, run build_runner separately:

dart run build_runner build --delete-conflicting-outputs

CLI usage

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:

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.

Enum mappings

Enum wire values can be mapped to stable Dart member names in configuration:

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:

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

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

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

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 before adopting the generator for a new schema corpus.

Documentation

Development

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 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