#dart
#dart
Вопрос:
Я совершенно новичок в Dart, поэтому я только что начал внедрять SDK для существующего API, но я столкнулся с некоторыми проблемами, выясняя, как структурировать вещи, чтобы сократить шаблонность, когда я анализирую ответы с сервера.
В принципе, все ответы от API выглядят следующим образом:
{
"data": {
...
},
"error": {
...
}
}
где присутствует либо data
или error
, но никогда оба. Довольно стандартный материал. Форма
error
не так уж интересна, поскольку она одинакова для каждого ответа, но data
объект
отличается для каждого ответа. До сих пор мне удавалось получить что-то «рабочее», объявив базовый класс
, который обрабатывает ошибку и передает ее super
(я должен отметить, что я использую
json_serializer
пакет):
class Response {
Response({this.error});
Error? error;
}
@JsonSerializable(createToJson: false)
class ExampleResponse extends Response {
ExampleResponse({
this.data,
Error? error,
}) : super(error: error);
Map<String, dynamic>? data;
factory ExampleResponse.fromJson(Map<String, dynamic> json) =>
_$ExampleResponseFromJson(json);
}
Это работает, но я теряю всю информацию о типе data
поля. Я не уверен, как подойти к этому
отсюда, чтобы не использовать еще один класс для формы данных:
@JsonSerializable()
class Thing {
Thing(this.name);
String name;
factory Thing.fromJson(Map<String, dynamic> json) => _$ThingFromJson(json);
String toString() => 'Thing{name: $name}';
}
@JsonSerializable()
class ExampleResponseData {
ExampleResponseData(this.thing);
Thing thing;
factory ExampleResponseData.fromJson(Map<String, dynamic> json) =>
_$ExampleResponseDataFromJson(json);
String toString() => 'ExampleResponseData{thing: $thing}';
}
@JsonSerializable(createToJson: false)
class ExampleResponse extends Response {
ExampleResponse({
this.data,
Error? error,
}) : super(error: error);
ExampleResponseData? data;
factory ExampleResponse.fromJson(Map<String, dynamic> json) =>
_$ExampleResponseFromJson(json);
String toString() => 'ExampleResponse{error: $error, data: $data}';
}
В Go я бы просто определил внутреннюю структуру для случаев, когда тип не имеет значения вне
синтаксического анализа JSON, например:
type ExampleResponse struct {
Error *Error `json:"error"`
Data *struct {
Thing Thing `json:"thing"`
} `json:"thing"`
}
но я намного лучше разбираюсь в ООП в целом и на еще более незнакомой почве с Dart. Есть ли
лучший способ справиться с этим, чтобы в итоге не было в два раза больше типов, чем ответов?
Комментарии:
1. Является ли json_serializable строгим требованием для вас, или вы можете рассмотреть другие варианты, такие как pub.dev/packages/built_value ?
2. Я бы сказал, что на данный момент у меня нет никаких строгих требований, кроме формы ответа API. Когда я изначально рассматривал обе библиотеки,
built_value
они казались более шаблонными, но у меня недостаточно понимания того, будет ли это лучше или хуже, учитывая мою текущую проблему.3. Будет ли у вас другой тип «данных» на одной и той же конечной точке, или вы будете знать, какой тип данных ожидать на данной конечной точке?
4. Конечные точки всегда возвращают одну и ту же форму данных. В общих чертах API разработан как псевдо-RPC-сервис, где каждая конечная точка имеет известный формат запроса и ответа, но все ответы преобразуются идентичным образом. Возврат ошибок преобразуется и используется для заполнения
error
поля, возврат без ошибок помещается подdata
поле, но в остальном остается неизменным. Итак, в приведенном выше примере вызов вымышленной/Example
конечной точки всегда возвращает aThing
, который маршалируется вthing
поле внутриdata
объекта.
Ответ №1:
Вы можете найти решение на основе built_value . Идея состоит в том, чтобы использовать generic для типа данных. Встроенное значение может обрабатывать такие случаи, хотя у вас будет немного шаблонности. Ниже вы можете найти пример:
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
import 'package:built_value/standard_json_plugin.dart';
part 'built_value_example.g.dart';
void main(List<String> arguments) {
final resultAJson = endpointA();
final resultA = serializers.deserialize(resultAJson, specifiedType: FullType(Response, [FullType(DataA)]));
print(resultA);
final resultBJson = endpointB();
final resultB = serializers.deserialize(resultBJson, specifiedType: FullType(Response, [FullType(DataB)]));
print(resultB);
}
Map<String, dynamic> endpointA() {
final data = DataA((b) => b..dataAField = 7);
final response = Response<DataA>((b) => b..data = data);
return serializers.serialize(response, specifiedType: FullType(Response, [FullType(DataA)])) as Map<String, dynamic>;
}
Map<String, dynamic> endpointB() {
final data = DataB((b) => b..dataBField = 'data b value');
final response = Response<DataB>((b) => b..data = data..error = 'data b error');
return serializers.serialize(response, specifiedType: FullType(Response, [FullType(DataB)])) as Map<String, dynamic>;
}
abstract class Response<DATA_TYPE> implements Built<Response<DATA_TYPE>, ResponseBuilder<DATA_TYPE>> {
Response._();
factory Response([Function(ResponseBuilder<DATA_TYPE> b) updates]) = _$Response<DATA_TYPE>;
static Serializer<Response> get serializer => _$responseSerializer;
DATA_TYPE get data;
String? get error;
}
abstract class DataA implements Built<DataA, DataABuilder> {
DataA._();
factory DataA([Function(DataABuilder b) updates]) = _$DataA;
static Serializer<DataA> get serializer => _$dataASerializer;
int get dataAField;
}
abstract class DataB implements Built<DataB, DataBBuilder> {
DataB._();
factory DataB([Function(DataBBuilder b) updates]) = _$DataB;
static Serializer<DataB> get serializer => _$dataBSerializer;
String get dataBField;
}
@SerializersFor([
DataA,
DataB,
Response,
])
final Serializers serializers = (_$serializers.toBuilder()
..addPlugin(StandardJsonPlugin())
..addBuilderFactory(FullType(Response, [FullType(DataA)]), () => ResponseBuilder<DataA>())
..addBuilderFactory(FullType(Response, [FullType(DataB)]), () => ResponseBuilder<DataB>()))
.build();
Комментарии:
1. Большое вам спасибо. Мне нужно будет найти время, чтобы разобраться, чтобы лучше понять, как все это работает, но я ценю, что вы нашли время.