Jaguar-dart/client

Protobuf support

Closed this issue · 16 comments

At least that what's I understand from this line https://github.com/Jaguar-dart/client/blob/master/resty/lib/src/response.dart#L514
Am I right @tejainece ? I tried to put my proto repo for serialization but I get this error:

Unhandled exception:
FormatException: Unexpected character (at line 2, character 1)
�name���
^

#0      _ChunkedJsonParser.fail (dart:convert/runtime/libconvert_patch.dart:1358:5)
#1      _ChunkedJsonParser.parseNumber (dart:convert/runtime/libconvert_patch.dart:1254:9)
#2      _ChunkedJsonParser.parse (dart:convert/runtime/libconvert_patch.dart:922:22)
#3      _parseJson (dart:convert/runtime/libconvert_patch.dart:29:10)
#4      JsonDecoder.convert (dart:convert/json.dart:540:36)
#5      JsonCodec.decode (dart:convert/json.dart:167:41)
#6      StringResponse.decode (package:jaguar_resty/src/response.dart:514:26)
#7      Get.one (package:jaguar_resty/src/jaguar_resty_base.dart:387:70)
<asynchronous suspension>
#8      _$Api.getPerson (package:client/main.dart:30:16)
<asynchronous suspension>
#9      MyApi.getPerson (package:client/main.dart:20:18)
#10     main (package:client/main.dart:43:28)
<asynchronous suspension>
#11     _startIsolate.<anonymous closure> (dart:isolate/runtime/libisolate_patch.dart:289:19)
#12     _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12)

Yes. I have been working on it.

@tejainece I tried the new resty version but I still don't understand how Protobuf can be applied here, as I still see some hardcoded Json calls :(

Are you using retrofit 2.6.1? It uses converters.

There is no hard coding.

It uses decodeOne to decode. decodeOne uses appropriate CodecRepo based on content type.

I can't use CodecRepo repo for protobuf :( or at least I don't know how... https://github.com/Jaguar-dart/jaguar_serializer_protobuf/
I'm trying to do this:

class ProtoCodecRepo extends ProtoSerializerRepo implements CodecRepo<Uint8List> {
  @override
  decode<T>(Uint8List object) {
    return from(object);
  }

  @override
  List<T> decodeList<T>(Uint8List object) {
    return from(object);
  }

  @override
  T decodeOne<T>(Uint8List object) {
    return from(object);
  }

  @override
  Uint8List encode(object) {
    return to(object);
  }

  @override
  Iterable<Serializer> get serializers => [];
}

But it dosesn't work :(

error: Superinterfaces don't have a valid override for 'addAll': SerializerRepoImpl.addAll ((Iterable<Serializer<dynamic>>) → void), ProtoSerializerRepo.addAll ((Map<dynamic, (dynamic) → dynamic>, {toJson: Map<dynamic, (dynamic) → dynamic>}) → void). (inconsistent_inheritance at [client] lib/main.dart:16)
error: Superinterfaces don't have a valid override for 'add': SerializerRepoImpl.add ((Serializer<dynamic>) → void), ProtoSerializerRepo.add (<T>((dynamic) → T, {toJson: (dynamic) → T}) → void). (inconsistent_inheritance at [client] lib/main.dart:16)
error: Superinterfaces don't have a valid override for 'getByType': SerializerRepoImpl.getByType (<T>(Type) → Serializer<T>), ProtoSerializerRepo.getByType ((Type) → (dynamic) → dynamic). (inconsistent_inheritance at [client] lib/main.dart:16)

Fixed it. Use jaguar_serializer 2.2.6

@tejainece I manage to retrieve data as protobuf now ! :D that's great but I can't manage to send protobuf data yet...

I guess we miss something on annotation side, because if I'm trying this:

 @PostReq(path: "/api/v1/person")
  Future<Person> addPerson(@AsJson() Person person) {
    return super.addPerson(person).timeout(timeout);
  }

it will generate

 Future<Person> addPerson(Person person) async {
    var req = base.post
        .path(basePath)
        .path("/api/v1/person")
        .json(jsonConverter.to(person));
    return req.go().then(decodeOne);
  }

So how can we fix this ? adding a @AsSerialized(contentType='application/octet-stream') annotation ? Like this it can use the converters instead of the jsonConverter. Let me know what you think :)

Or we can modify a bit the AsBody to be able to pass the contentType='application/octet-stream'

Also now retrofit generation doesn't work anymore :/ my classes get nowerror: Missing concrete implementations of ApiClient.decodeList, ApiClient.decodeOne and getter ApiClient.jsonConverter. (non_abstract_class_inherits_abstract_member_three at [client] lib/main.dart:10)

Ho just notice that the declaration has changed, it was class AddressesApi extends _$AddressesApiClient implements ApiClient and now it's class AddressesApi extends ApiClient with _$AddressesApiClient {

After that it only stay error: Missing concrete implementation of getter ApiClient.jsonConverter. (non_abstract_class_inherits_abstract_member_one at [client] lib/main.dart:10) this one shouldn't be mandatory

Just declare jsonConverter and leave it as null.

Or we can modify a bit the AsBody to be able to pass the contentType='application/octet-stream'

I think, this already works. Not sure about content type. If you use @AsBody() for List parameter, it sends as bytes. If you use @AsBody() for String, it will send as text. I will fix content type.

Maybe in the future, we also want a way to encode String as bytes.

Just declare jsonConverter and leave it as null.

sure, but it's anoying if we don't care about json to add this to all api we create... for my project I've like 20 api class ^^ why not making it really protocol agnostic and just ask converters/serializer

I already tried @AsBody but it doesn't work as it doesn't use converters, here is what is generated:

Future<Person> addPerson(Person person) async {
    var req = base.post
        .path(basePath)
        .path("/api/v1/person")
        .body(person?.toString());
    return req.go(throwOnErr: true).then(decodeOne);
  }

I will fix that.

@tejainece I can do it :) just let me know if you prefer modifying AsBody (with retrocompatibilty) or adding a new one AsSerialized. I prefer re using AsBody personally, it feel more natural :)

AsSerialized should be good. I like you proposal from earlier:

@AsSerialized(contentType='application/octet-stream')