retrofit.dart is a type conversion dio client generator using source_gen and inspired by Chopper and Retrofit.
Add the generator to your dev dependencies
dependencies:
retrofit: any
logger: any #for logging purpose
dev_dependencies:
retrofit_generator: any
build_runner: any
import 'package:json_annotation/json_annotation.dart';
import 'package:retrofit/retrofit.dart';
import 'package:dio/dio.dart';
part 'example.g.dart';
@RestApi(baseUrl: "https://5d42a6e2bc64f90014a56ca0.mockapi.io/api/v1/")
abstract class RestClient {
factory RestClient(Dio dio, {String baseUrl}) = _RestClient;
@GET("/tasks")
Future<List<Task>> getTasks();
}
@JsonSerializable()
class Task {
String id;
String name;
String avatar;
String createdAt;
Task({this.id, this.name, this.avatar, this.createdAt});
factory Task.fromJson(Map<String, dynamic> json) => _$TaskFromJson(json);
Map<String, dynamic> toJson() => _$TaskToJson(this);
}
then run the generator
# dart
pub run build_runner build
# flutter
flutter pub run build_runner build
import 'package:logger/logger.dart';
import 'package:retrofit_example/example.dart';
import 'package:dio/dio.dart';
final logger = Logger();
void main(List<String> args) {
final dio = Dio(); // Provide a dio instance
dio.options.headers["Demo-Header"] = "demo header"; // config your dio headers globally
final client = RestClient(dio);
client.getTasks().then((it) => logger.i(it));
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 the recommanded to be used as the serialization tool.
...
@GET("/tasks")
Future<List<Task>> getTasks();
}
@JsonSerializable()
class Task {
String name;
Task({this.name});
factory Task.fromJson(Map<String, dynamic> json) => _$TaskFromJson(json);
}
The HTTP methods in the below sample are supported.
@GET("/tasks/{id}")
Future<Task> getTask(@Path("id") String id);
@GET('/demo')
Future<String> queries(@Queries() Map<String, dynamic> queries);
@GET("https://httpbin.org/get")
Future<String> namedExample(
@Query("apikey") String apiKey,
@Query("scope") String scope,
@Query("type") String type,
@Query("from") int from
);
@PATCH("/tasks/{id}")
Future<Task> updateTaskPart(
@Path() String id, @Body() Map<String, dynamic> map);
@PUT("/tasks/{id}")
Future<Task> updateTask(@Path() String id, @Body() Task task);
@DELETE("/tasks/{id}")
Future<void> deleteTask(@Path() String id);
@POST("/tasks")
Future<Task> createTask(@Body() Task task);
@POST("http://httpbin.org/post")
Future<void> createNewTaskFromFile(@Part() File file);
@POST("http://httpbin.org/post")
@FormUrlEncoded()
Future<String> postUrlEncodedFormData(@Field() String hello);
@GET("/tasks/{id}")
Future<HttpResponse<Task>> getTask(@Path("id") String id)
@GET("/tasks")
Future<HttpResponse<List<Task>>>> getTasks()
-
Add a HTTP header from the parameter of the method
@GET("/tasks") Future<Task> getTasks(@Header("Content-Type") String contentType );
-
Add static HTTP headers
@GET("/tasks") @Headers(<String, dynamic>{ "Content-Type" : "application/json", "Custom-Header" : "Your header" }) Future<Task> getTasks();
catchError(Object)
should 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((Object obj) {
// non-200 error goes here.
switch (obj.runtimeType) {
case DioError:
// Here's the sample to get the failed response error code and message
final res = (obj as DioError).response;
logger.e("Got error : ${res.statusCode} -> ${res.statusMessage}");
break;
default:
}
});
}
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")
abstract class RestClient {
factory RestClient(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.
For the project not to be confused with the files generated by the retrofit you can hide them.
File -> Settings -> Editor -> File Types
Add "ignore files and folders"
*.g.dart