书籍:Flutter Apprentice - 尝试根据 Api 响应制作通用的 ModelConverter

问题描述

Raywenderlich 出色的 Flutter book 中,第 13 章 致力于使用库Chopper 从 api 获取响应JsonConverter

Github 中的代码here

他还建议使用成功/错误类型的响应包装器,如函数式编程。

从 Response 到 Success/Error 包装器的 ModelConverter,适用于 APIRecipeQuery 模型并且仅在一行 final recipeQuery = APIRecipeQuery.fromJson(mapData); 中使用一种方法。进行泛型转换似乎很合乎逻辑,因为它是一个非常有用的类。

import 'dart:convert';
import 'package:chopper/chopper.dart';

import 'model_response.dart';
import 'recipe_model.dart';

class ModelConverter implements Converter {
  @override
  Request convertRequest(Request request) {
    // Add a header to the request that says you have a request type of application/json using jsonHeaders.
    // These constants are part of Chopper.
    final req = applyHeader(
      request,contentTypeKey,jsonHeaders,override: false,);

    return encodeJson(req);
  }

  @override
  Response<BodyType> convertResponse<BodyType,InnerType>(Response response) {
    return decodeJson<BodyType,InnerType>(response);
  }

  Request encodeJson(Request request) {
    final contentType = request.headers[contentTypeKey];
    // Confirm contentType is of type application/json.
    if (contentType != null && contentType.contains(jsonHeaders)) {
      return request.copyWith(body: json.encode(request.body));
    }
    return request;
  }

  Response decodeJson<BodyType,InnerType>(Response response) {
    final contentType = response.headers[contentTypeKey];
    var body = response.body;
    if (contentType != null && contentType.contains(jsonHeaders)) {
      body = utf8.decode(response.bodyBytes);
    }
    try {
      final mapData = json.decode(body);
      if (mapData['status'] != null) {
        return response.copyWith<BodyType>(
            body: Error(Exception(mapData['status'])) as BodyType);
      }
/*
The only line is next
*/
      final recipeQuery = APIRecipeQuery.fromJson(mapData);
      return response.copyWith<BodyType>(
          body: Success(recipeQuery) as BodyType);
    } catch (e) {
      chopperLogger.warning(e);
      return response.copyWith<BodyType>(body: Error(e) as BodyType);
    }
  }

所以,我尝试在构造函数中将模型作为参数传递:

class ModelConverter <T extends JsonConverter> implements Converter {
  final T model;
  ModelConverter ({@required this.model});

和 我在 recipe_service.dart 中使用 converter: ModelConverter(model: APIRecipeQuery) 调用它,但我不知道如何静态引用模型,并且无法访问方法 model.fromJson

接下来,我尝试只传递函数转换器:

class ModelConverter implements Converter {
  Function fromJson;
  ModelConverter ({@ required this.fromJson});

在 API 中使用 getter,在 recipe_service.dart 中使用 converter: ModelConverter(fromJson: APIRecipeQuery.fjConverter)

class APIRecipeQuery {
  static Function get fjConverter => _ $ APIRecipeQueryFromJson;

但我无法让它工作。

使 ModelConverter 通用的最佳方法是什么? 提前致谢。

解决方法

this post 中解决

model_converter.dart

. . .
typedef CreateModelFromJson = dynamic Function(Map<String,dynamic> json);

class ModelConverter<Model> implements Converter {
  final CreateModelFromJson fromJson;

  ModelConverter({@required this.fromJson});
. . .
  final query = fromJson(mapData) as Model;
. . .

和 recipe_service.dart

. . .
      converter: ModelConverter<APIRecipeQuery>(
        fromJson: (json) => APIRecipeQuery.fromJson(json),),. . .