trevorwang / retrofit.dart

retrofit.dart is an dio client generator using source_gen and inspired by Chopper and Retrofit.
https://mings.in/retrofit.dart/
MIT License
1.09k stars 250 forks source link

generate string value of @Part() parameter which is not string type. #566

Open Jaew00Shin opened 1 year ago

Jaew00Shin commented 1 year ago
import 'package:intl/intl.dart';
import 'package:retrofit/retrofit.dart';
import 'package:dio/dio.dart' hide Headers;

part 'example_api_service.g.dart';

extension DateTimeExampleExtension on DateTime {
  toJson() {
    return DateFormat('yyyy-MM-dd').format(this);
  }
}

@RestApi(baseUrl: baseUrl)
abstract class ExampleApiService {
  factory ExampleApiService(Dio dio, {String baseUrl}) = _ExampleApiService;

  @POST('/')
  @MultiPart()
  Future request({
    @Part() required DateTime date,
  });
}

const String baseUrl = ''";

When I write this code, there is an error like below.

[SEVERE] retrofit_generator:retrofit on lib/src/data/data_sources/remote/example_api_service.dart:

Exception: toJson() method have to add to DateTime

I want to use various class type for @Part() parameter. Although I defined toJson extension, it does not work. it is failed to generate code.

Please fix it.

andrei-bucurei commented 1 year ago

The problem here might be that dart extensions are not really extending the type and Retrofit generator is not aware of your extensions.

My "workaround" for this is to use custom types called ApiDateTime and optionally ApiDate if it's a more "pretentious" API:

class ApiDateTime {
  static final DateFormat dateFormat = DateFormat('<your API accepted date-time format>');
  final DateTime dateTime;

  ApiDateTime(this.dateTime);

  factory ApiDateTime.fromJson(String json) {
    return ApiDateTime(dateFormat.parse(json));
  }

  String toJson() {
    return dateFormat.format(dateTime);
  }
}

Let's say we have a legacy API that accepts a different format for properties that should only contain the date part. I can have an additional type with a different DateFormat:

class ApiDate {
  static final DateFormat dateFormat = DateFormat('<your API accepted date format>');
  final DateTime dateTime;

  ApiDate(this.dateTime);

  factory ApiDate.fromJson(String json) {
    return ApiDate(dateFormat.parse(json));
  }

  String toJson() {
    return dateFormat.format(dateTime);
  }
}

I put the workaround in quotes because I actually found it as a very good practice as it gives me full control over how dates are serialized without resorting to interceptors or other more advanced methods.