选择合适的 API 响应结构:通用型 vs. 特定场景

329 阅读2分钟

在构建 API 时,选择一个合适的响应结构对于确保代码的可读性和可维护性至关重要。本文将比较两种常见的响应结构:通用型 ApiResponse 和特定场景的 RegisterResponse,并讨论如何结合两者的优点。

1. 通用型 ApiResponse 结构

@JsonSerializable(genericArgumentFactories: true)
class ApiResponse<T> {
  @JsonKey(name: 'data')
  final T data;

  @JsonKey(name: 'errorCode')
  final int? errorCode;

  @JsonKey(name: 'errorMsg')
  final String? errorMsg;

  const ApiResponse({
    required this.data,
    this.errorCode,
    this.errorMsg,
  });
}

优点

  • 泛型结构,具有较强的通用性,适用于各种数据类型;
  • 包含错误码和错误信息,便于统一处理错误和异常。

缺点

  • 使用 int 类型的 errorCode,可读性较差,开发者需要查阅文档才能了解不同的整数值所代表的具体错误场景;
  • 结构相对简单,可能不适用于某些特定场景。

2. 特定场景 RegisterResponse 结构

@JsonEnum()
enum RegisterResult {
  @JsonValue(0)
  success,
  @JsonValue(1)
  invalidEmail,
  @JsonValue(2)
  invalidPassword,
  @JsonValue(3)
  emailExists,
}

@JsonSerializable()
class RegisterResponse {
  final RegisterResult result;
  final RegisterSuccessResponse? successResponse;

  const RegisterResponse({
    required this.result,
    this.successResponse,
  });
}

优点

  • 针对特定业务场景(如注册),结构更为清晰;
  • 使用枚举类型(如 RegisterResult)表示错误类型,提高代码可读性和可维护性,开发者可以通过阅读代码直接理解各个枚举值对应的错误场景,无需查阅文档。

缺点

  • 可扩展性较差,仅适用于特定业务场景,如果需要支持多种场景,需要定义多个类。

结合通用性和可读性

为了兼顾 ApiResponse 的通用性和 RegisterResponse 的可读性,可以考虑在 ApiResponse 中使用泛型错误码类型:

dartCopy code
@JsonSerializable(genericArgumentFactories: true)
class ApiResponse<T, E> {
  @JsonKey(name: 'data')
  final T data;

  @JsonKey(name: 'errorCode')
  final E? errorCode;

  @JsonKey(name: 'errorMsg')
  final String? errorMsg;

  const ApiResponse({
    required this.data,
    this.errorCode,
    this.errorMsg,
  });
}

然后,在具体的业务场景中,将枚举类型(如 RegisterResult)作为泛型参数传递给 ApiResponse,从而结合通用性和可读性。例如,注册响应可以表示为:

class RegisterApiResponse extends ApiResponse<RegisterSuccessResponse, RegisterResult> {
  RegisterApiResponse({
    required RegisterSuccessResponse data,
    RegisterResult? errorCode,
    String? errorMsg,
  }) : super(data: data, errorCode: errorCode, errorMsg: errorMsg);
}

这样,可以利用泛型实现通用的响应结构,同时也可以通过枚举类型清晰地表示错误场景,提高代码的可读性和可维护性。

总结

在选择 API 响应结构时,需要权衡通用性和可读性。通用型 ApiResponse 结构适用于各种数据类型,便于统一处理错误和异常,但使用整数类型的 errorCode 可能导致可读性和可维护性问题。相反,特定场景的 RegisterResponse 结构针对特定业务场景提供了更清晰的结构和更直观的错误表示,但可扩展性较差。

结合通用性和可读性的方法是在 ApiResponse 中使用泛型错误码类型,并在具体业务场景中使用枚举类型作为泛型参数。这样,可以在保持通用性的同时满足特定场景的需求,提高代码的可读性和可维护性。