Core Dart/Flutter code generation library for OpenAPI specifications
npm install @dorval/core

Core library for generating type-safe Dart/Flutter API clients from OpenAPI specifications.
- šÆ Type-safe API clients - Generate strongly-typed Dart code from OpenAPI specs
- āļø Freezed models - Immutable data classes with copyWith, equality, and more
- š JSON serialization - Built-in fromJson/toJson with json_serializable
- š Multiple HTTP clients - Support for Dio, HTTP, Chopper, and Retrofit
- š Full OpenAPI 3.0 support - Handle complex schemas, references, and more
- šØ Customizable generation - Control naming, organization, and features
- ā
Null safety - Full support for Dart's sound null safety
- š Smart header consolidation - Reduce duplicate header classes with definitions
- š Discriminated unions - Proper Freezed union types with @Freezed(unionKey) and @FreezedUnionValue
``bash`
npm install @dorval/coreor
yarn add @dorval/coreor
pnpm add @dorval/core
`javascript
const { generateDartCode } = require('@dorval/core');
// Basic usage
await generateDartCode({
input: './openapi.yaml',
output: {
target: './lib/api'
}
});
`
`javascript
const { generateDartCode } = require('@dorval/core');
await generateDartCode({
// INPUT OPTIONS
input: './path/to/openapi.yaml', // or URL or OpenAPI object
// OUTPUT OPTIONS
output: {
target: './lib/generated/api', // Output directory
mode: 'split', // File organization
// 'single' - All code in one file
// 'split' - Separate models and services (default)
// 'tags' - Group by OpenAPI tags
client: 'dio', // HTTP client library
// 'dio' - Feature-rich, supports interceptors (default)
// 'http' - Lightweight, built-in Dart package
// 'chopper' - Code generation based
// 'retrofit' - Annotation-based (experimental)
override: {
// Generator options
generator: {
freezed: true, // Generate Freezed models (default: true)
jsonSerializable: true, // Add JSON serialization (default: true)
nullSafety: true, // Enable null safety (default: true)
partFiles: true, // Generate part files (default: true)
equatable: false // Add Equatable support (default: false)
},
// Method naming strategy
methodNaming: 'operationId', // How to name service methods
// 'operationId' - Use OpenAPI operationId (default)
// 'methodPath' - Generate from HTTP method + path
// Dio-specific options
dio: {
baseUrl: 'https://api.example.com', // Override base URL
interceptors: ['AuthInterceptor'] // Custom interceptors
}
}
},
// POST-GENERATION HOOKS
hooks: {
afterAllFilesWrite: 'dart format .' // Commands to run after generation
// Can also be an array: ['dart format .', 'flutter pub get']
}
});
`
field from your OpenAPI specification:`yaml
OpenAPI spec
paths:
/pets/{id}:
get:
operationId: showPetById
Generated Dart method
Future showPetById(String id);
`$3
Generates method names from HTTP method and path:`yaml
OpenAPI spec
paths:
/pets/{id}:
get: ...
/users/{userId}/settings:
post: ...
Generated Dart methods
Future getPetsById(String id);
Future postUsersByUserIdSettings(String userId, SettingsDto body);
`Usage Examples
$3
`javascript
const { generateDartCode } = require('@dorval/core');async function generate() {
const result = await generateDartCode({
input: './petstore.yaml',
output: {
target: './lib/api'
}
});
console.log(
Generated ${result.length} files);
}
`$3
`javascript
await generateDartCode({
input: 'https://api.example.com/openapi.json',
output: {
target: './lib/generated',
mode: 'split',
client: 'dio',
override: {
generator: {
freezed: true,
jsonSerializable: true
},
methodNaming: 'methodPath',
dio: {
baseUrl: 'https://api.production.com'
}
}
},
hooks: {
afterAllFilesWrite: [
'dart format ./lib/generated',
'flutter pub run build_runner build'
]
}
});
`$3
`javascript
// Generate multiple APIs in one project
const apis = [
{ input: './user-api.yaml', output: { target: './lib/api/user' } },
{ input: './admin-api.yaml', output: { target: './lib/api/admin' } },
{ input: './public-api.yaml', output: { target: './lib/api/public' } }
];for (const api of apis) {
await generateDartCode(api);
}
`$3
`javascript
// package.json
{
"scripts": {
"generate:api": "node scripts/generate-api.js",
"prebuild": "npm run generate:api"
}
}// scripts/generate-api.js
const { generateDartCode } = require('@dorval/core');
generateDartCode({
input: process.env.API_SPEC_URL || './openapi.yaml',
output: {
target: './lib/api',
override: {
methodNaming: 'methodPath'
}
}
}).then(() => {
console.log('ā
API client generated successfully');
}).catch(console.error);
`Generated File Structure
`
lib/api/
āāā api_client.dart # Dio client wrapper
āāā api_config.dart # API configuration
āāā models/ # Data models
ā āāā user.f.dart # Freezed model
ā āāā user.f.freezed.dart # Generated Freezed code
ā āāā user.f.g.dart # Generated JSON serialization
ā āāā params/ # Request parameter models
ā ā āāā get_users_params.f.dart
ā ā āāā index.dart
ā āāā headers/ # Header parameter models
ā ā āāā get_users_headers.f.dart
ā ā āāā index.dart
ā āāā index.dart # Barrel exports
āāā services/ # API services
āāā users_service.dart # Service implementation
āāā api_exception.dart # Error handling
āāā index.dart # Barrel exports
`Generated Dart Code Usage
After generation, use the API client in your Flutter app:
`dart
import 'package:dio/dio.dart';
import 'api/api_client.dart';
import 'api/services/users_service.dart';void main() async {
// Initialize client
final apiClient = ApiClient(
dio: Dio(),
baseUrl: 'https://api.example.com',
);
// Create service
final usersService = UsersService(apiClient);
// Make type-safe API calls
final users = await usersService.getUsers(
limit: 10,
offset: 0,
);
// Handle errors
try {
final user = await usersService.getUserById('123');
} on ApiException catch (e) {
print('API Error: ${e.message}');
}
}
`Flutter Dependencies
Add these to your
pubspec.yaml:`yaml
dependencies:
dio: ^5.0.0
freezed_annotation: ^3.0.0
json_annotation: ^4.8.1dev_dependencies:
build_runner: ^2.4.0
freezed: ^3.0.0
json_serializable: ^6.7.0
`Run build_runner after generation:
`bash
flutter pub run build_runner build --delete-conflicting-outputs
`API Reference
$3
Main function to generate Dart code from OpenAPI specification.
Parameters:
-
options (DartGeneratorOptions): Configuration objectReturns:
-
Promise: Array of generated filesThrows:
- Error if OpenAPI spec is invalid
- Error if output directory cannot be created
$3
`typescript
interface DartGeneratorOptions {
input: string | OpenAPIObject;
output: {
target: string;
mode?: 'single' | 'split' | 'tags';
client?: 'dio' | 'http' | 'chopper' | 'retrofit';
override?: {
generator?: {
freezed?: boolean;
jsonSerializable?: boolean;
nullSafety?: boolean;
partFiles?: boolean;
equatable?: boolean;
};
methodNaming?: 'operationId' | 'methodPath';
dio?: {
baseUrl?: string;
interceptors?: string[];
};
};
};
hooks?: {
afterAllFilesWrite?: string | string[];
};
}interface GeneratedFile {
path: string;
content: string;
}
`Comparison with Similar Tools
| Feature | @dorval/core | OpenAPI Generator | Swagger Codegen |
|---------|--------------|-------------------|-----------------|
| Dart/Flutter Focus | ā
Native | ā ļø Generic | ā ļø Generic |
| Freezed Support | ā
Built-in | ā Manual | ā Manual |
| Dio Integration | ā
Native | ā ļø Basic | ā ļø Basic |
| Method Naming Control | ā
Yes | ā No | ā No |
| TypeScript Config | ā
Yes | ā Java/CLI | ā Java/CLI |
| Bundle Size | ā
Small | ā Large | ā Large |
Troubleshooting
$3
Generated methods return
Map instead of models
- Check that your OpenAPI spec uses $ref for response schemas
- Ensure models are defined in components/schemasDuplicate method names
- Use unique
operationId in your OpenAPI spec
- Or switch to methodNaming: 'methodPath'Import errors in generated code
- Run
flutter pub get after generation
- Run flutter pub run build_runner build`Contributions are welcome! Please check out the main repository.
MIT Ā© 2025
- GitHub Repository
- NPM Package
- CLI Package
- Report Issues