retrofit 3.0.0 copy "retrofit: ^3.0.0" to clipboard
retrofit: ^3.0.0 copied to clipboard

outdated

retrofit.dart is an dio client generator using source_gen and inspired by Chopper and Retrofit.

Retrofit For Dart #

All Contributors

retrofit retrofit_generator Dart CI CircleCI Build Status

retrofit.dart is a type conversion dio client generator using source_gen and inspired by Chopper and Retrofit.

Usage #

Generator #

Add the generator to your dev dependencies

dependencies:
  retrofit: any
  logger: any  #for logging purpose

dev_dependencies:
  retrofit_generator: any
  build_runner: any

Define and Generate your API #

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

Use it #

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));
}

More #

Type 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 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);
}

HTTP Methods #

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 original HTTP response #

  @GET("/tasks/{id}")
  Future<HttpResponse<Task>> getTask(@Path("id") String id);

  @GET("/tasks")
  Future<HttpResponse<List<Task>>> getTasks();

HTTP Header #

  • 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();
    

Error Handling #

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:
      break;
  }
});

Multiple endpoints support #

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.

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:

FutureOr<Task> deserializeTask(Map<String, dynamic> json);
FutureOr<Map<String, dynamic>> serializeTask(Task object);

E.g.

@RestApi(
  baseUrl: "https://5d42a6e2bc64f90014a56ca0.mockapi.io/api/v1/",
  parser: Parser.FlutterCompute,
)
abstract class RestClient {
  factory RestClient(Dio dio, {String baseUrl}) = _RestClient;

  @GET("/tasks")
  Future<List<Task>> getTasks();

  @POST("/tasks")
  Future<void> updateTasks(List<Task> tasks);
}

Task deserializeTask(Map<String, dynamic> json) => Task.fromJson(json);
Map<String, dynamic> serializeTask(User object) => object.toJson();

N.B. It is recommended to use just a single object, if possible, as then only one background thread will be spawned to perform the computation. If you use a list or a map it will spawn a thread for each element.

abstract class RestClient {
  factory RestClient(Dio dio, {String baseUrl}) = _RestClient;

  @GET("/tasks")
  Future<List<Task>> getTasks(); // BAD

  @GET("/tasks_list")
  Future<TaskList> getTasksList(); // GOOD
}

TaskList deserializeTaskList(Map<String, dynamic> json) => TaskList.fromJson(json);

@JsonSerializable
class TaskList {
  const TaskList({required this.tasks});

  final List<Task> tasks;

  factory TaskList.fromJson(Map<String, dynamic> json) => _$TaskListFromJson(json);
}

Hide generated files #

For the project not to be confused with the files generated by the retrofit you can hide them.

Android studio

File -> Settings -> Editor -> File Types

Add "ignore files and folders"

*.g.dart

Credits #

  • JetBrains. Thanks for providing the great IDE tools.

Contributors ✨ #

Thanks goes to these wonderful people (emoji key):


Trevor Wang

🚇 ⚠️ 💻

devkabiir

💻

Nicola Verbeeck

💻

ipcjs

💻

戒尺

💻

Mohaned Benmesken

💻

Bogdan Lukin

💻

sooxt98

💻

SBNTT

💻

Paweł Czochański

💻

bar4488

💻

via-guy

💻

Marco Martinelli

💻

LeonColt

💻

Alex A.F.

💻

William Oprandi

💻

Maciej Brażewicz

💻

river

💻

Renato Burton

💻

Teddy

💻

Ignacio Berdiñas

💻

themadmrj

💻

István Juhos

💻

Akash Mondal

💻

JasonHezz

💻

Garrett Franks

💻

This project follows the all-contributors specification. Contributions of any kind welcome!

1821
likes
0
pub points
99%
popularity

Publisher

verified publishermings.in

retrofit.dart is an dio client generator using source_gen and inspired by Chopper and Retrofit.

Homepage
Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

dio, meta

More

Packages that depend on retrofit