tonik 0.4.0
tonik: ^0.4.0 copied to clipboard
Pure Dart OpenAPI 3.0/3.1 code generator. Creates type-safe API client packages for Dart and Flutter with sealed classes, pattern matching, and full encoding support.
Tonik #
A Dart code generator for OpenAPI 3.0 and 3.1 specifications.
Generate type-safe API client packages for Dart and Flutter. Tonik produces idiomatic code with sealed classes for oneOf, exhaustive pattern matching for responses, and full OpenAPI encoding support.
Key Features #
Type-Safe Response Handling by Status Code and Content Type #
Tonik generates distinct types for each response defined in your spec. When an endpoint returns different schemas for 200, 400, and 404—you get separate, strongly-typed classes for each:
final response = await petApi.updatePet(body: pet);
switch (response) {
case TonikSuccess(:final value):
switch (value) {
case UpdatePetResponse200(:final body):
print('Updated: ${body.name}');
case UpdatePetResponse400():
print('Invalid input');
case UpdatePetResponse404():
print('Pet not found');
}
case TonikError(:final error):
print('Network error: $error');
}
Different content types (JSON, url encode, plain text) on the same status code? Each gets its own typed accessor.
Composition with Sealed Classes #
oneOf, anyOf, and allOf generate idiomatic Dart code:
oneOf→ Sealed class with exhaustive pattern matchinganyOf→ Class with nullable fields for each alternativeallOf→ Merged class combining all member schemas
// oneOf with discriminator → sealed class
final result = switch (searchResult) {
SearchResultUser(:final value) => 'User: ${value.name}',
SearchResultProduct(:final value) => 'Product: ${value.title}',
};
No Name Conflicts #
Use Error, Response, List, or any Dart built-in as schema names. Tonik uses scoped code emission to properly qualify all type references—no naming collisions with dart:core or Dio.
Integer and String Enums #
Both work out of the box, with optional unknown-value handling for forward compatibility:
status:
type: integer
enum: [0, 1, 2]
x-dart-enum: [pending, active, closed]
All Parameter Encoding Styles #
Path, query, and header parameters support all OpenAPI styles: simple, label, matrix, form, spaceDelimited, pipeDelimited, and deepObject.
Pure Dart #
Install with dart pub global activate tonik and run. No JVM, no Docker, no external dependencies.
Documentation #
- Features Overview – Complete feature reference
- Configuration –
tonik.yamloptions, name overrides, filtering - Data Types – OpenAPI to Dart type mappings
- Composite Data Types –
oneOf,anyOf,allOfusage - Authentication – Interceptor patterns for auth
- URI Encoding Limitations – Dart URI class constraints
Quick Start #
Install #
dart pub global activate tonik
Generate #
tonik --package-name=my_api --spec=openapi.yaml
Use #
Add the generated package to your project:
dart pub add my_api:{'path':'./my_api'}
Then import and use:
import 'package:my_api/my_api.dart';
final api = PetApi(CustomServer(baseUrl: 'https://api.example.com'));
final response = await api.getPetById(petId: 1);
switch (response) {
case TonikSuccess(:final value):
print('Pet: ${value.body.name}');
case TonikError(:final error):
print('Failed: $error');
}
See the petstore integration tests for more examples.
Feature Summary #
| Category | What's Supported |
|---|---|
| Responses | Multiple status codes, multiple content types, response headers, default and range codes (2XX) |
| Composition | oneOf (sealed classes), anyOf, allOf, discriminators, nested composition |
| Types | Integer/string enums, date, date-time with timezone, decimal/BigDecimal, uri, binary |
| Parameters | Path, query, header; all encoding styles (form, simple, label, matrix, deepObject, etc.) |
| Request Bodies | application/json, application/x-www-form-urlencoded, application/octet-stream, text/plain |
| Configuration | Name overrides, filtering by tag/operation/schema, deprecation handling, content-type mapping |
| OAS 3.1 | $ref with siblings, $defs local definitions, boolean schemas, nullable type arrays |
Acknowledgments #
Special thanks to felixwoestmann, without whom this project would not exist.