api_contract_generator 0.2.0
api_contract_generator: ^0.2.0 copied to clipboard
Annotation-based code generator for api_contract. Automatically generate API contract definitions from annotated Dart classes.
api_contract_generator #
Code generator for api_contract. Automatically generates API contract definitions from annotated Dart model classes.
Features #
- Auto-generate contracts from Dart model classes using
@ApiContractSchemaannotation - Type inference - automatically detects field types from your models
- Built-in type support - handles
DateTime,Uri,Duration,BigInt,RegExp, and primitives - Nested models - automatically generates contracts for referenced model classes
- Field annotations - fine-grained control with
@optionaland@nullable - Two generation modes:
fromModel- infers contracts from model structure (recommended)fromJson- generates from JSON schema with callbackfromJsonSchema- generates from JSON schema map
Installation #
Add both packages to your pubspec.yaml:
dependencies:
api_contract: ^0.2.0
dev_dependencies:
api_contract_generator: ^0.2.0
build_runner: ^2.4.0
Quick Start #
1. Annotate Your Model #
import 'package:api_contract/api_contract.dart';
import 'package:api_contract_generator/api_contract_generator.dart';
part 'user.g.dart';
@ApiContractSchema(mode: ContractMode.strict)
class User {
final int id;
final String name;
@optional
final String? email;
final Profile profile;
}
@ApiContractSchema()
class Profile {
final String bio;
final DateTime createdAt;
}
2. Generate Contract #
dart run build_runner build
3. Use in Your Repository #
class UserRepository {
Future<User> getUser(int id) async {
final response = await api.get('/users/$id');
// Validate response against generated contract
final result = userContract.validate(response);
result.throwIfInvalid();
return User.fromJson(response);
}
}
Annotations #
Class-level: @ApiContractSchema #
@ApiContractSchema(
mode: ContractMode.strict, // or ContractMode.lenient
version: '1.0',
model: UserModel, // optional: for fromJson/fromJsonSchema modes
)
Parameters:
mode- Contract validation mode (default:ContractMode.lenient)strict- Fails on extra fields in API responselenient- Allows extra fields in API response
version- API version string (optional)model- Model class for type inference infromJsonmode (optional)
Field-level Annotations #
@optional // Field can be missing from response
final String? bio;
@nullable // Field must be present but can be null
final String? middleName;
Difference:
@optional- Field may not exist in JSON ({"name": "John"}- no bio field)@nullable- Field exists but value is null ({"name": "John", "bio": null})
Generation Modes #
Mode 1: fromModel (Recommended) #
Auto-detect from model structure:
@ApiContractSchema(mode: ContractMode.strict)
class Post {
final int id; // → required number
final String title; // → required string
@optional
final String? body; // → optional string
final List<String> tags; // → required list
}
Mode 2: fromJson #
Generate from JSON with callback:
@ApiContractSchema(
mode: ContractMode.strict,
model: Post,
)
void generatePostContract(JsonContractGenerator gen) {
gen.fromJson({
'id': 1,
'title': 'Sample Post',
'tags': ['dart', 'flutter'],
});
}
Mode 3: fromJsonSchema #
Generate from schema map:
@ApiContractSchema(mode: ContractMode.strict)
void generatePostContract(JsonSchemaContractGenerator gen) {
gen.fromJsonSchema({
'id': {'type': 'number', 'required': true},
'title': {'type': 'string', 'required': true},
'body': {'type': 'string', 'optional': true},
});
}
Supported Types #
| Dart Type | JSON Type | Generated As |
|---|---|---|
int, double, num |
number | FieldType.number |
String |
string | FieldType.string |
bool |
boolean | FieldType.boolean |
List<T> |
array | FieldType.list |
Map<K,V> |
object | FieldType.map |
DateTime |
string (ISO 8601) | FieldType.string |
Uri |
string (URL) | FieldType.string |
Duration |
number (ms) | FieldType.number |
BigInt |
number | FieldType.number |
RegExp |
string (pattern) | FieldType.string |
| Custom classes | object | FieldType.nested |
Type Inference Rules #
When using fromModel mode:
-
Non-nullable fields →
requiredfinal String name; // → ContractField.required(type: FieldType.string) -
Nullable fields →
optional(unless@nullablespecified)final String? email; // → ContractField.optional(type: FieldType.string) @nullable final String? middleName; // → ContractField.nullable(type: FieldType.string) -
Custom classes →
nestedcontractfinal Profile profile; // → ContractField.nested(nestedContract: profileContract) -
Nullable custom classes →
optional nestedfinal Profile? profile; // → ContractField.optional(nestedContract: profileContract)
Generated Output #
The generator creates a .g.dart file with contract definitions:
// user.g.dart
part of 'user.dart';
final userContract = ApiContract(
mode: ContractMode.strict,
fields: {
'id': ContractField.required(type: FieldType.number),
'name': ContractField.required(type: FieldType.string),
'email': ContractField.optional(type: FieldType.string),
'profile': ContractField.nested(nestedContract: profileContract),
},
);
final profileContract = ApiContract(
fields: {
'bio': ContractField.required(type: FieldType.string),
'createdAt': ContractField.required(type: FieldType.string),
},
);
Build Configuration #
Add build.yaml to your project root (optional):
targets:
$default:
builders:
api_contract_generator:contract:
enabled: true
Examples #
See the api_contract package for complete usage examples with repository pattern integration.
Related Packages #
- api_contract - Runtime API contract validation
License #
MIT License - see LICENSE file for details