Package selection guidance compiled from public package information, community data, and project usage.
Retrofit_generator is a code generation tool for Flutter that creates Dio-based HTTP clients using source_gen, inspired by Retrofit and Chopper. It simplifies API integration by generating type-safe client classes from annotated interfaces, reducing boilerplate and improving maintainability. The package supports JSON serialization and works across multiple platforms including Android, iOS, macOS, Windows, and Linux. Developers define endpoints with annotations, and the generator produces efficient, clean client code. Ideal for projects requiring structured, scalable REST API interactions.
Use cases
Generating type-safe HTTP clients
Automating API client creation
Reducing boilerplate in network layers
Integrating with Dio for HTTP requests
Building scalable REST APIs in Flutter apps
Key features
Annotation-based API definition
Code generation via source_gen
Integration with Dio HTTP client
Support for JSON serialization
Cross-platform compatibility
Suitable for
Flutter developers using Dio
Teams needing maintainable API clients
Projects with complex REST APIs
Developers wanting to reduce manual HTTP code
Apps requiring consistent API layer design
Considerations
Requires build_runner for code generation
Needs understanding of annotations and source_gen
May increase build time
Limited to static API definitions
Dependent on correct annotation usage
Original README
Original README snapshot from the linked source repository. Visit the repository for the latest content.
dependencies:retrofit:^4.9.0logger:^2.6.0# for logging purposejson_annotation:^4.9.0dev_dependencies:retrofit_generator:^10.0.1build_runner:^2.6.0json_serializable:^6.10.0
You can customize the code generation behavior by creating a build.yaml file in your project root:
targets:$default:builders:retrofit_generator:options:# Control whether to add '// dart format off/on' comments (default: true)format_output:true# Enable automatic response type casting (default: true)auto_cast_response:true# Generate empty request body for methods without parameters (default: false)empty_request_body:false# Enable useResult annotation for methods (default: false)use_result:false
format_output
By default, retrofit_generator wraps the generated code with // dart format off and // dart format on comments to preserve the formatting. If you're combining retrofit with other generators (like riverpod) and need more control over formatting, you can disable this:
# dart
dart pub run build_runner build
# for watch mode (recommended during development)
dart pub run build_runner watch
Lean Builder Support (Experimental)
Retrofit now has experimental support for lean_builder, a faster build system for Dart. While lean_builder support is still under development, the infrastructure has been added for future use.
Important: lean_builder is an optional dependency and is NOT required to use retrofit_generator. It's only needed if you want to try the experimental lean_builder support.
To prepare for lean_builder support, add it to your dev_dependencies:
dev_dependencies:lean_builder:^0.1.2# Optional - only if you want to use lean_builder
Note: For now, please continue using build_runner as shown above. Full lean_builder integration will be available in a future release once lean_builder reaches stability.
Use it
import'package:dio/dio.dart';
import'package:logger/logger.dart';
import'package:retrofit_example/example.dart';
final logger = Logger();
voidmain(List<String> args) {
final dio = Dio(); // Provide a dio instance
dio.options.headers['Demo-Header'] = 'demo header'; // config your dio headers globallyfinal client = RestClient(dio);
client.getTasks().then((it) => logger.i(it));
}
More
Types
Types conversion
Before you use the type conversion, please make sure that a factory Task.fromJson(Map<String, dynamic> json) must be provided for each model class. json_serializable is recommended to be used as the serialization tool.
Retrofit supports streaming responses using @DioResponseType(ResponseType.stream). When using this annotation, the return type must be either Stream<Uint8List> (for raw bytes) or Stream<String> (for text).
import'dart:convert';
import'dart:typed_data';
import'package:dio/dio.dart'hideHeaders;
import'package:retrofit/retrofit.dart';
@RestApi(baseUrl: 'https://api.example.com')
abstractclassRestClient{
factoryRestClient(Dio dio, {String? baseUrl}) = _RestClient;
// For binary data (images, files, etc.)@GET('/download/file')
@DioResponseType(ResponseType.stream)
Stream<Uint8List> downloadFile();
// For text data (SSE, NDJSON, etc.)@GET('/events')
@DioResponseType(ResponseType.stream)
Stream<String> getServerSentEvents();
}
Note: When using Stream<String>, make sure to import dart:convert in your source file.
Server-Sent Events (SSE)
For SSE support, you can use the simple_sse package to parse the stream:
dependencies:simple_sse:^2.0.0
import'package:simple_sse/simple_sse.dart';
final client = RestClient(dio);
// Get the string stream and transform it to SSE eventsfinal eventStream = client
.getServerSentEvents()
.transform(constLineSplitter())
.transform(constSseEventTransformer());
awaitfor (final event in eventStream) {
print('Event: ${event.event}');
print('Data: ${event.data}');
print('ID: ${event.id}');
}
HTTP Header
Add a HTTP header from the parameter of the method
Add global HTTP headers to all requests in the API
You can define headers at the @RestApi level that will be automatically included in all requests:
@RestApi(
baseUrl: 'https://api.example.com',
headers: {
'User-Agent': 'MyApp/1.0.0',
'X-Platform': 'mobile',
},
)
abstractclassApiService{
factoryApiService(Dio dio, {String? baseUrl}) = _ApiService;
// This request will automatically include User-Agent and X-Platform headers@GET('/users')
Future<List<User>> getUsers();
// You can add method-specific headers that combine with global headers@GET('/profile')
@Headers(<String, dynamic>{'Authorization': 'Bearer token'})
Future<User> getProfile();
// Method-level headers override global headers with the same key@GET('/settings')
@Headers(<String, dynamic>{'X-Platform': 'web'})
Future<Settings> getSettings();
}
Note: Method-level headers (via @Headers or @Header parameter) will override global headers if they have the same key.
Error Handling
catchError(Object) can be used for capturing the exception and failed response. You can get the detailed response info from DioError.response.
client.getTask('2').then((it) {
logger.i(it);
}).catchError((obj) {
// non-200 error goes here.switch (obj.runtimeType) {
caseDioException:
// Here's the sample to get the failed response error code and messagefinal res = (obj asDioException).response;
logger.e('Got error : ${res.statusCode} -> ${res.statusMessage}');
break;
default:
break;
}
});
Errors can also be caught and handled at the client level using CallAdapters. For example:
This feature allows you to adapt the return type of a network call from one type to another.
For example:
Future → Future<Result>
This feature provides flexibility in handling API responses, enabling better integration with custom response wrappers or error handling libraries.
The CallAdapter takes the original return type R and transforms it into a new type T. This is particularly useful when working with response wrappers like Either, Result, or ApiResponse.
Below is an example using a custom CallAdapter with a Result wrapper:
If you want to use multiple endpoints to your RestClient, you should pass your base url when you initiate RestClient. Any value defined in RestApi will be ignored.
@RestApi(baseUrl: 'this url will be ignored if baseUrl is passed')
abstractclassRestClient{
factoryRestClient(Dio dio, {String? baseUrl}) = _RestClient;
}
final client = RestClient(dio, baseUrl: 'your base url');
If you want to use the base url from dio.option.baseUrl, which has lowest priority, please don't pass any parameter to RestApi annotation and RestClient's structure method.
Multithreading (Flutter only)
If you want to parse models on a separate thread, you can take advantage of the compute function, just like Dio does when converting String data responses into json objects.
For each model that you use you will need to define 2 top-level functions: