Dart客户端类型通用REST Api调用



我的理解是可以使用REST方法通过HTTP调用和处理CRUD操作。我的目标是通过[POST, GET, PUT, DELETE]管理大约5个实体的CRUD事务。总的来说,即使我可以在辅助函数中重用一些样板文件,我也必须编写20个不同的原型。

我想减少泛型类型的代码量。我是这么想的:

abstract class RestResource
{
int id;
static String name = "";
RestResource({required this.id});
Map<String, dynamic> toJson() => throw UnimplementedError();
factory RestResource.fromJson(Map<String, dynamic> json) => throw UnimplementedError();
}
class ActualResource extends ResourceRest
{
final String additional;
static String name = "resource";
ActualResource({required this.additional, required int id}) : super(id: id);
@override
Map<String, dynamic> toJson() { 
// return serialized 
};
@override
factory RestResource.fromJson(Map<String, dynamic> json) { 
// create object from json 
};
}
// Example for GET request for a resource with an id ex: api/resource/1234
Future<Resource> fetch<Resource extends RestResource>(int id) async {
Uri url = Uri.http('http://www.someurl.com/api/', Resource.name + id.toString());
http.Response res = await _httpClient.get(url);
validateHTTPResponse(res);
return Resource.fromJson(convert.jsonDecode(res.body));
}
// This is how I'd want to call it
int id = 1234;
ActualResource r = await fetch<ActualResource>(id);

我的问题。Resource是泛型类型,即使它扩展了RestResource的定义。调用工厂方法Resource.fromJson会触发以下智能感知错误:

在Resource.name

The getter 'name' isn't defined for the type 'Type'.
Try importing the library that defines 'name', correcting the name to the name of an existing getter, or defining a getter or field named 'name'.

在Resource.fromJson

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'

我想开始讨论开发人员如何做这样的事情,因为这将节省大量的时间和精力。

经过进一步的研究,我发现我的方法目前不适用于Dart w/Flutter,因为Dart:mirror仅在VM上可用。这就是解决方案。我希望它能帮助其他flutter开发人员在编写REST Api客户端时减少样板文件的数量。感谢gnter Zöchbauer给出的答案:Dart客户端类型通用REST Api调用

abstract class RestSerializable {
RestSerializable.fromJson(); 
Map<String, dynamic> toJson();
}
class ResourceA implements RestSerializable { // whatever you need + fromJson() + toJson() }
class ResourceB implements RestSerializable { // whatever you need + fromJson() + toJson() }
RestReource fromJson<RestReource extends RestSerializable>({required dynamic json}) {
return jsonFactories[RestReource]!(json);
}
final jsonFactories = <Type, Function> {
ResourceA : (Map<String, dynamic> json) => ResourceA.fromJson(json),
ResourceB : (Map<String, dynamic> json) => ResourceB.fromJson(json),
};
final unencodedPathFactories = <Type, String> {
ResourceA : "/api/resourceA/",
ResourceB : "/api/resourceB/",
};
RestReource fromJson<RestReource extends RestSerializable>({required dynamic json}) {
return jsonFactories[RestReource]!(json);
}
String unencodedPath<RestResource extends RestSerializable>() {
return unencodedPathFactories[RestResource]!;
}
class RestApiClient {
static const String AUTHORITY = "localhost:port";
final http.Client _httpClient;
// This is just one example.... You can add for POST, PUT, DELETE
// GET Details
Future<Resource> fetch<Resource extends RestSerializable>(int id) async {
Uri url = Uri.http(AUTHORITY, unencodedPath<Resource>() + id.toString());
http.Response res = await _httpClient.get(url);
this.validateHTTPResponse(res, unencodedPath<Resource>());
return fromJson<Resource>(json: convert.jsonDecode(res.body));
}
}

最新更新