Adding more than one converter in ChopperClient flutter

1.1k Views Asked by At

I am creating different .g.dart classes using json-annotation for different set of responses. Now when I am using Chopper Client for making requests and mapping responses into model classes, I am creating converter. But I can only assign one converter to chopper client. what I am trying to achieve is using get_it package to initialize chopper client. How can i assign different converter to chopper client on making different requests. This is base class where get_it package is used for initializing classes.

base.dart

import 'package:chopper/chopper.dart' as chopper;

chopper.ChopperClient getBaseChopperClient(GetIt c) {
  return chopper.ChopperClient(
    baseUrl: 'https://',
    interceptors: [chopper.HttpLoggingInterceptor()],
    converter: HomeModelConverter(),
    errorConverter: chopper.JsonConverter(),
  );
}

c.registerLazySingleton(() {
  var chopper = getBaseChopperClient(c);
  return chopper;
});

c.registerFactory(() => HomeApiService.create(c<chopper.ChopperClient>()));

This ChopperService class from which I am making Get request and mapping response into HomeModelResponse using HomeModelConverter and this HomeModelConverter is assigned in chopper client object above.

home_api_service.dart

part 'home_api.chopper.dart';

@ChopperApi(baseUrl: '')
abstract class HomeApiService extends ChopperService {
  @Get(path: '')
  Future<Response<HomeModelResponse>> getData();

  static HomeApiService create([ChopperClient? client]) =>
      _$HomeApiService(client);
}

This is a converter class specific to HomeModelResponse. Inside decodeJson function, we are explicitly mentioning it to decode to HomeModelResponse.

home_model_converter.dart

class HomeModelConverter implements Converter {
  @override
  Request convertRequest(Request request) {
    final req = applyHeader(
      request,
      contentTypeKey,
      jsonHeaders,
      override: false,
    );

    return encodeJson(req);
  }

  Request encodeJson(Request request) {
    var contentType = request.headers[contentTypeKey];
    if (contentType != null && contentType.contains(jsonHeaders)) {
      return request.copyWith(body: json.encode(request.body));
    }
    return request;
  }

  Response<BodyType> decodeJson<BodyType, InnerType>(Response response) {
    var contentType = response.headers[contentTypeKey];
    var body = response.body;
    if (contentType != null && contentType.contains(jsonHeaders)) {
      body = utf8.decode(response.bodyBytes);
    }
    try {
      var mapData = json.decode(body);
      var popular = HomeModelResponse.fromJson(mapData);
      return response.copyWith<BodyType>(body: popular as BodyType);
    } catch (e) {
      chopperLogger.warning(e);
      return response.copyWith<BodyType>(body: body);
    }
  }

  @override
  Response<BodyType> convertResponse<BodyType, InnerType>(Response response) {
    return decodeJson<BodyType, InnerType>(response);
  }
}

This is HomeModelResponse into which incoming response will automatically be mapped.

home_model_response.dart

part 'home_model_response.g.dart';

@JsonSerializable()
class HomeModelResponse {
  ------------
-----------
  HomeModelResponse({
    ---------
    ---------
  });
  factory HomeModelResponse.fromJson(Map<String, dynamic> json) =>
      _$HomeModelResponseFromJson(json);
  Map<String, dynamic> toJson() => _$HomeModelResponseToJson(this);
}

The above code is working fine for home_api_service and I am getting proper response. Now I want to create another service, for example AddApiService. This will have different converter. How to dynamically change converter in chopper client. Right now HomeModelConverter is hardcoded assigned at the time of initialization. I don't want to create more than one ChopperClient for every converter. Stuck here. Or any option to create a generic converter

If anyone can suggest if this approach is fine or is there any better approach to follow in flutter.

1

There are 1 best solutions below

0
On

Tried myself and did a little bit of workaround. Now working as per my requirement.

Modified initialization of HomeApiService as below:

c.registerFactory(() => HomeModelConverter());

c.registerFactory(() => HomeApiService.create(
    getBaseChopperClient(c, c<HomeModelConverter>())));

Modified intialization of chopper client as below. The only drawback here is that for every new Chopper Service, new object of chopper client is created.

chopper.ChopperClient getBaseChopperClient(
  GetIt c, chopper.Converter converter) {
return chopper.ChopperClient(
  baseUrl: '', // provide your own base url
  interceptors: [chopper.HttpLoggingInterceptor()],
  converter: converter,
  errorConverter: chopper.JsonConverter(),
);

}