Dart-Flutter通用Api响应类动态类数据类型



我的应用程序目前正在为每个作为模型的api响应使用自定义类。但我正在尝试更改它,优化一些小东西,所以我正在尝试实现一个类包装器,例如ApiResponse。但是对于make-fromJson和toJson来说,静态调用和方法不能很好地工作。

作为例子,我会展示我正在尝试的东西。MyModel->类响应。ApiResponse->内部包含任何模型类的主类,并且必须调用其自身的子方法"fromjson/tojson"。测试->类用于测试目的,错误注释在类上。

class MyModel {
String id;
String title;
MyModel({this.id, this.title});
factory MyModel.fromJson(Map<String, dynamic> json) {
return MyModel(
id: json["id"],
title: json["title"],
);
}
Map<String, dynamic> toJson() => {
"id": this.id,
"title": this.title,
};
}
class ApiResponse<T> {
bool status;
String message;
T data;
ApiResponse({this.status, this.message, this.data});
factory ApiResponse.fromJson(Map<String, dynamic> json) {
return ApiResponse<T>(
status: json["status"],
message: json["message"],
data: (T).fromJson(json["data"])); // The method 'fromJson' isn't defined for the type 'Type'.
// Try correcting the name to the name of an existing method, or defining a method named 'fromJson'.
}
Map<String, dynamic> toJson() => {
"status": this.status,
"message": this.message,
"data": this.data.toJson(), // The method 'toJson' isn't defined for the type 'Object'.
// Try correcting the name to the name of an existing method, or defining a method named 'toJson'
};
}
class Test {
test() {
ApiResponse apiResponse = ApiResponse<MyModel>();
var json = apiResponse.toJson();
var response = ApiResponse<MyModel>.fromJson(json);
}
}

不能对Dart上的类型调用方法,因为静态方法必须在编译时解析,并且类型在运行时才有值。

但是,您可以将解析器回调传递给构造函数,并使用每个模型都可以实现的接口(例如Serializable(。然后,通过将ApiResponse更新为ApiResponse<T extends Serializable>,它将知道每种类型的T都将有一个toJson()方法。

以下是更新的完整示例。

class MyModel implements Serializable {
String id;
String title;
MyModel({this.id, this.title});
factory MyModel.fromJson(Map<String, dynamic> json) {
return MyModel(
id: json["id"],
title: json["title"],
);
}
@override
Map<String, dynamic> toJson() => {
"id": this.id,
"title": this.title,
};
}
class ApiResponse<T extends Serializable> {
bool status;
String message;
T data;
ApiResponse({this.status, this.message, this.data});
factory ApiResponse.fromJson(Map<String, dynamic> json, Function(Map<String, dynamic>) create) {
return ApiResponse<T>(
status: json["status"],
message: json["message"],
data: create(json["data"]),
);
}
Map<String, dynamic> toJson() => {
"status": this.status,
"message": this.message,
"data": this.data.toJson(),
};
}
abstract class Serializable {
Map<String, dynamic> toJson();
}
class Test {
test() {
ApiResponse apiResponse = ApiResponse<MyModel>();
var json = apiResponse.toJson();
var response = ApiResponse<MyModel>.fromJson(json, (data) => MyModel.fromJson(data));
}
}

base_reresponse.dart

class BaseResponse {
dynamic message;
bool success;

BaseResponse(
{this.message, this.success});
factory BaseResponse.fromJson(Map<String, dynamic> json) {
return BaseResponse(
success: json["success"],
message: json["message"]);
}
}

list_reresponse.dart

server response for list
{
"data": []
"message": null,
"success": true,
}
@JsonSerializable(genericArgumentFactories: true)
class ListResponse<T> extends BaseResponse {
List<T> data;
ListResponse({
String message,
bool success,
this.data,
}) : super(message: message, success: success);
factory ListResponse.fromJson(Map<String, dynamic> json, Function(Map<String, dynamic>) create) {
var data = List<T>();
json['data'].forEach((v) {
data.add(create(v));
});
return ListResponse<T>(
success: json["success"],
message: json["message"],
data: data);
}
}

single_reresponse.dart

server response for single object
{
"data": {}
"message": null,
"success": true,
}

@JsonSerializable(genericArgumentFactories: true)
class SingleResponse<T> extends BaseResponse {
T data;
SingleResponse({
String message,
bool success,
this.data,
}) : super(message: message, success: success);
factory SingleResponse.fromJson(Map<String, dynamic> json, Function(Map<String, dynamic>) create) {
return SingleResponse<T>(
success: json["success"],
message: json["message"],
data: create(json["data"]));
}
}

data_reresponse.dart

class DataResponse<T> {
Status status;
T res; //dynamic
String loadingMessage;
GeneralError error;
DataResponse.init() : status = Status.Init;
DataResponse.loading({this.loadingMessage}) : status = Status.Loading;
DataResponse.success(this.res) : status = Status.Success;
DataResponse.error(this.error) : status = Status.Error;

@override
String toString() {
return "Status : $status n Message : $loadingMessage n Data : $res";
}
}
enum Status {
Init,
Loading,
Success,
Error,
}

或者如果使用freeezed,则data_response可以是

@freezed
abstract class DataResponse<T> with _$DataResponse<T> {
const factory DataResponse.init() = Init;
const factory DataResponse.loading(loadingMessage) = Loading;
const factory DataResponse.success(T res) = Success<T>;
const factory DataResponse.error(GeneralError error) = Error;
}

用途:(改装库的一部分

@GET(yourEndPoint)
Future<SingleResponse<User>> getUser();
@GET(yourEndPoint)
Future<ListResponse<User>> getUserList();

如果不使用reftofit:

const _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _data = <String, dynamic>{};
final _result = await _dio.request<Map<String, dynamic>>('$commentID',
queryParameters: queryParameters,
options: RequestOptions(
method: 'GET',
headers: <String, dynamic>{},
extra: _extra,
baseUrl: baseUrl),
data: _data);
final value = SingleResponse<Comment>.fromJson(
_result.data,
(json) => Comment.fromJson(json),
);

您可以尝试我的方法来应用通用响应:APIResponse<MyModel>通过实现自定义的可解码抽象类,来自http请求的响应将作为MyModel对象返回。

Future<User> fetchUser() async {
final client = APIClient();
final result = await client.request<APIResponse<User>>(
manager: APIRoute(APIType.getUser), 
create: () => APIResponse<User>(create: () => User())
);
final user = result.response.data; // reponse.data will map with User
if (user != null) {
return user;
}
throw ErrorResponse(message: 'User not found');
}

这是我的源代码:https://github.com/katafo/flutter-generic-api-response

There is another way, 
Map<String, dynamic> toJson() => {
"message": message,
"status": status,
"data": _toJson<T>(data),
};
static T _fromJson<T>(Map<String, dynamic> json) {
return ResponseModel.fromJson(json) as T;
}

最新更新