OpenAPI Retrofit Generator
Note: This package is a complete rework of swagger_parser with enhanced features, improved architecture, and better maintainability.
Generate type-safe Dart REST clients from OpenAPI/Swagger specifications
Automatically create Retrofit-based REST clients and immutable data models from your API definition files. Save hours of boilerplate coding and eliminate manual typing errors.
Platform Support
✅ All Platforms Supported: Web, Mobile (iOS/Android), Desktop (Windows/macOS/Linux)
This is a code generator (dev dependency) that creates platform-agnostic Dart code. While pub.flutter-io.cn may not list platform badges (since the generator itself only runs during development), the generated REST clients work on all Dart platforms including Flutter Web, thanks to Dio's universal HTTP support. Your generated API clients are fully compatible with any platform your Dart/Flutter app targets.
Why OpenAPI Retrofit Generator?
- Full Spec Support: OpenAPI 2.0 (Swagger), 3.0, and 3.1
- Extensively Tested: Validated with 358 distinct OpenAPI schemas across all 3 serializers in comprehensive end-to-end tests
- Format Flexible: Works with JSON and YAML schemas
- Remote & Local: Generate from URLs or local files
- Multiple Serializers: Choose from
json_serializable,freezed, ordart_mappable - Type Safe: Strongly-typed models with null safety
- Multi-Schema: Handle multiple API definitions in one project
- Retrofit Integration: Built on battle-tested Retrofit + Dio
Quick Start
1. Install
Add to your pubspec.yaml:
dependencies:
dio: ^5.9.0
retrofit: ^4.9.0
json_annotation: ^4.9.0
dev_dependencies:
openapi_retrofit_generator: ^2.0.0
build_runner: ^2.10.0
json_serializable: ^6.11.0
retrofit_generator: ^10.1.0
2. Configure
Create openapi_generator.yaml in your project root:
openapi_generator:
schema_path: api/openapi.yaml # Path to your OpenAPI file
output_directory: lib/api # Where to generate code
json_serializer: json_serializable # Choose: json_serializable, freezed, or dart_mappable
3. Generate
Run the generator:
dart run openapi_retrofit_generator
dart run build_runner build -d
4. Use
import 'package:dio/dio.dart';
import 'api/export.dart';
void main() async {
final dio = Dio(BaseOptions(baseUrl: 'https://api.example.com'));
final client = RestClient(dio);
// Type-safe API calls
final users = await client.users.listUsers();
final user = await client.users.getUser(userId: '123');
print('Found ${users.length} users');
print('User: ${user.name}');
}
What Gets Generated?
From a Pet Store OpenAPI spec, you get:
lib/api/
├── pets/
│ └── pets_client.dart # @RestApi() class with all endpoints
├── models/
│ ├── pet.dart # Data class with toJson/fromJson
│ ├── create_pet_request.dart
│ └── pet_status.dart # Enum for status values
├── rest_client.dart # Root client aggregating all APIs
└── export.dart # Barrel export for easy imports
Example Generated Client:
@RestApi()
abstract class PetsClient {
factory PetsClient(Dio dio) = _PetsClient;
@GET('/pets')
Future<List<Pet>> listPets(@Query('limit') int? limit);
@POST('/pets')
Future<Pet> createPet(@Body() CreatePetRequest body);
@GET('/pets/{id}')
Future<Pet> getPet(@Path('id') String petId);
}
Example Generated Model:
@JsonSerializable()
class Pet {
final String id;
final String name;
final PetStatus status;
const Pet({
required this.id,
required this.name,
required this.status,
});
factory Pet.fromJson(Map<String, dynamic> json) => _$PetFromJson(json);
Map<String, dynamic> toJson() => _$PetToJson(this);
}
Serialization Options
Choose the serializer that best fits your project:
json_serializable (Default)
Standard Dart JSON serialization with @JsonSerializable:
dependencies:
json_annotation: ^4.9.0
dev_dependencies:
json_serializable: ^6.11.0
freezed
Immutable data classes with union types and copyWith:
dependencies:
freezed_annotation: ^3.1.0
dev_dependencies:
freezed: ^3.2.0
openapi_generator:
json_serializer: freezed
dart_mappable
Fast, type-safe mapping:
dependencies:
dart_mappable: ^4.6.0
dev_dependencies:
dart_mappable_builder: ^4.6.0
openapi_generator:
json_serializer: dart_mappable
Required: When using dart_mappable, you must create a build.yaml file in your project root with the following configuration:
global_options:
dart_mappable_builder:
runs_before:
- retrofit_generator
options:
renameMethods:
fromJson: fromJsonString # Can be any name except "fromJson"
toJson: toJsonString # Can be any name except "toJson"
fromMap: fromJson # Must be exactly "fromJson"
toMap: toJson # Must be exactly "toJson"
This configuration is automatically validated before generation to ensure compatibility with Retrofit.
Configuration
Basic Configuration (Single Schema)
Create openapi_generator.yaml or add to pubspec.yaml:
openapi_generator:
# ============ REQUIRED ============
# Input: Choose ONE of these
schema_path: api/openapi.yaml # Path to local OpenAPI file
# OR
# schema_url: https://api.example.com/openapi.json # URL to remote OpenAPI file
# Output: Must specify where to generate
output_directory: lib/api # Where to generate code
# ============ OPTIONAL ============
name: my_api # API identifier (defaults to schema filename)
json_serializer: json_serializable # Serializer (default: json_serializable)
root_client: true # Generate root client (default: true)
root_client_name: RestClient # Root client name (default: RestClient)
client_postfix: Client # Client suffix (default: null)
Required: schema_path OR schema_url, and output_directory
Everything else is optional with sensible defaults.
Common Options
openapi_generator:
# ... basic config above ...
# Code organization
merge_clients: false # Combine all endpoints into one client
put_clients_in_folder: true # Place clients in /clients subdirectory
export_file: true # Generate barrel export file
# Enum handling
unknown_enum_value: true # Add 'unknown' to enums for forward compatibility
# HTTP options
original_http_response: false # Return HttpResponse<T> instead of T
extras_parameter_by_default: false # Add @Extras() to all methods
# Tag filtering
include_tags: [public, v2] # Only generate these tags
exclude_tags: [internal, deprecated] # Skip these tags
default_client: api # Name for untagged endpoints
Multiple API Schemas
Generate clients for multiple APIs in one project:
openapi_generator:
# ============ REQUIRED (ROOT) ============
# Must provide default output directory for all schemas
output_directory: lib/api
# ============ OPTIONAL (ROOT) ============
# These settings apply to all schemas as defaults
json_serializer: json_serializable
client_postfix: Client
# ============ REQUIRED (SCHEMES) ============
schemes:
# Each schema MUST have schema_path OR schema_url
- schema_path: api/v1.yaml # REQUIRED: input source
name: api_v1 # OPTIONAL: defaults to filename
root_client_name: ApiV1Client # OPTIONAL: overrides for this schema
# Inherits: output_directory, json_serializer, client_postfix from root
- schema_url: https://petstore.swagger.io/v2/swagger.json # REQUIRED
name: petstore # OPTIONAL
json_serializer: freezed # OPTIONAL: overrides root default
client_postfix: Service # OPTIONAL: overrides root default
output_directory: lib/petstore # OPTIONAL: overrides root default
Multi-schema rules:
- Root level:
output_directoryis required (provides default for all schemas) - Schema level: Each schema requires
schema_pathORschema_url - Inheritance: All root settings become defaults; each schema can override any option
Advanced Usage
Command Line Arguments
Override config file options via command line:
# Custom config file
dart run openapi_retrofit_generator -f my_config.yaml
# Override output directory
dart run openapi_retrofit_generator --output_directory lib/generated
# Override schema source
dart run openapi_retrofit_generator --schema_path api/openapi.yaml
dart run openapi_retrofit_generator --schema_url https://api.example.com/openapi.json
# Override serializer
dart run openapi_retrofit_generator --json_serializer freezed
# Help
dart run openapi_retrofit_generator -help
Using Freezed
For freezed serializer, create build.yaml in your project root:
global_options:
freezed:
runs_before:
- json_serializable
json_serializable:
runs_before:
- retrofit_generator
Then run:
dart run openapi_retrofit_generator
dart run build_runner build -d
Using dart_mappable
For dart_mappable serializer, you must create build.yaml in your project root:
global_options:
dart_mappable_builder:
runs_before:
- retrofit_generator
options:
renameMethods:
fromJson: fromJsonString # Can be any name except "fromJson"
toJson: toJsonString # Can be any name except "toJson"
fromMap: fromJson # Must be exactly "fromJson"
toMap: toJson # Must be exactly "toJson"
This configuration is automatically validated before generation. The generator will throw an error if:
build.yamlis missingfromMapis not renamed tofromJsontoMapis not renamed totoJsonfromJsonis not renamed (or still namedfromJson)toJsonis not renamed (or still namedtoJson)
Then run:
dart run openapi_retrofit_generator
dart run build_runner build -d
Interceptors & Authentication
Add interceptors to your Dio instance for auth, logging, etc.:
final dio = Dio(BaseOptions(baseUrl: 'https://api.example.com'));
// Auth interceptor
dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) {
options.headers['Authorization'] = 'Bearer $token';
return handler.next(options);
},
));
// Logging
dio.interceptors.add(LogInterceptor(responseBody: true));
final client = RestClient(dio);
Error Handling
try {
final user = await client.users.getUser(userId: '123');
} on DioException catch (e) {
if (e.response?.statusCode == 404) {
print('User not found');
} else if (e.type == DioExceptionType.connectionTimeout) {
print('Connection timeout');
} else {
print('Error: ${e.message}');
}
}
Complete Configuration Reference
For all available configuration options, see:
- example/openapi_generator.yaml - Fully documented example
- example/README.md - Working example project
Key Options
| Option | Default | Description |
|---|---|---|
schema_path |
- | Path to local OpenAPI file |
schema_url |
- | URL to remote OpenAPI file |
output_directory |
- | Where to generate code (required) |
json_serializer |
json_serializable |
Serializer: json_serializable, freezed, dart_mappable |
root_client |
true |
Generate root client aggregating all APIs |
client_postfix |
null |
Suffix for client classes (e.g., Client, Api) |
merge_clients |
false |
Combine all endpoints into one client |
unknown_enum_value |
true |
Add unknown to enums for compatibility |
include_tags |
[] |
Only generate endpoints with these tags |
exclude_tags |
[] |
Skip endpoints with these tags |
default_client |
api |
Name for endpoints without tags |
skipped_parameters |
[] |
Parameter names to exclude |
original_http_response |
false |
Return HttpResponse<T> with headers |
extras_parameter_by_default |
false |
Add @Extras() to all methods |
Examples
Check out the example directory for a complete working example:
cd example
dart run openapi_retrofit_generator
dart run build_runner build -d
dart run lib/main.dart
Troubleshooting
Build Runner Issues
If you encounter issues with build_runner, try:
dart run build_runner clean
dart run build_runner build --delete-conflicting-outputs
Generation Errors
Enable verbose output to debug issues:
dart run openapi_retrofit_generator --verbose
Type Errors
Ensure your OpenAPI spec is valid:
- Use
requiredfields correctly - Define proper types (
string,integer,object, etc.) - Add
nullable: truefor optional fields in OpenAPI 3.0+
Migration from swagger_parser
This package is a complete rework of swagger_parser. To migrate:
-
Update
pubspec.yaml:dev_dependencies: openapi_retrofit_generator: ^2.0.0 # was: swagger_parser -
Update config file name and key:
- Rename
swagger_parserconfig key toopenapi_generatorin your YAML files - The config file is now
openapi_generator.yaml(wasswagger_parser.yaml)
- Rename
-
Remove deprecated configuration options:
- Truly removed (no longer available):
language: kotlin- Only Dart generation is supportedreplacement_rules- Replaced by improved automatic naming with conflict resolution. Use proper component names in your OpenAPI schema
- Auto-handled (no longer needed, just delete them):
use_freezed3,use_multipart_file,enums_to_json,enums_parent_prefix,dart_mappable_convenient_when
- Truly removed (no longer available):
-
Review default changes:
use_x_nullablenow defaults totrue(wasfalse)export_filenow defaults tofalse(wastrue)
-
Regenerate your code:
dart run openapi_retrofit_generator dart run build_runner build -d
Most configurations will work with minimal changes. See the complete changelog for details.
Contributing
Contributions are welcome! Here's how you can help:
- Report bugs: Open an issue with reproduction steps
- Request features: Describe your use case and proposed solution
- Submit PRs: Add features, fix bugs, or improve documentation
- Write tests: Supplement E2E tests with new scenarios
Before contributing, please:
- Check existing issues and PRs
- Follow the existing code style
- Add tests for new features
- Update documentation as needed
License
MIT License - see LICENSE file for details.
Acknowledgments
This package is a complete rework of swagger_parser (GitHub) originally created by Carapacik. We've rebuilt the architecture from the ground up while preserving and enhancing all the features that made swagger_parser great.
Resources
Libraries
- openapi_retrofit_generator
- Provides generation functions that generates REST clients and data classes from OpenApi definition file openapi_retrofit_generator