为什么不应该在 REST API 中使用布尔值? - geekculture


在 REST API 中使用布尔值坏处:

  • 会阻碍API 可扩展性
  • 会屏蔽和混淆域清晰度
  • 会妨碍代码 可读性和可维护性

让我们深入研究这些领域并审核布尔值在 REST API 中的常用方式。
 
API 可扩展性
一个可扩展的 API应该让未来的变化显而易见并且易于实施。它不应引入复杂性或不必要的重复或破坏现有的消费者。
以Github 的 REST API为例,如果要创建新的存储库,开发人员private通过设置布尔字段(默认值:)来指定存储库是否成功。
HTTP Request: POST /user/repos
{
  "name": "Hello-World",
 
"description": "This is your first repository",
 
"private": false,
  ...
}

这个示例 POST 请求起初看起来很简单。但是,当 Github 后来引入组织公司的存储库时,他们需要将访问限制为仅限公司组织的成员。在这种情况下,布尔字段private不再足够。因此,他们添加了一个visibility具有以下选项的新枚举:
  • internal — 仅限于组织成员
  • public— 可从互联网公开访问
  • private— 仅限于存储库创建者和合作者

有了这一变化,文档声明当两者都使用时visibility将覆盖private。这导致了混淆文档和API中的重复的域概念。
 
领域清晰度
一个清晰的领域应该是有益的。它的组件应该可以通过无处不在的统一语言被发现。它应该通过清晰的边界来封装逻辑以避免下游错误。最后,它应该很难滥用其任何组件。
示例:付款 API — 发送新付款
让我们考虑一个金融服务行业的例子。大多数支付网关 API 将使用布尔字段响应isApproved支付请求。这是HTTP 资源 ( )的单一状态指示器/payments。
HTTP Request: POST /payments
{
  "transactionId": "uniqueId",
 
"paymentDetails": {...}
 
"chargeAmount": 15.00,
  ...
}
HTTP Response:
{
 
"isApproved": true,
 
"approvedAmount": 15.00,
  ...
}

在这个 API 中,“部分批准”的概念是隐含的。API 消费者必须检查 1) 付款isApproved和 2)approvedAmount少于初始chargeAmount. 这里的隐含性质是域逻辑泄露给消费者的一种症状。换句话说,这迫使消费者弄清楚“部分批准”的逻辑是什么,而不是我们直接告诉他们。域边界的这种不清晰也将消费者与域逻辑耦合在一起。
现在让我们看看这个例子如何影响代码的可读性和可维护性。
 
代码可读性和可维护性
代码可读性不仅仅是阅读代码的功能。揭示代码的意图很重要——为什么代码会做它所做的事情。
在前面的示例中,API中“部分批准”的隐含性质促使 API 使用者编写以下代码:
val (isApproved, approvedAmount, chargeAmount) = paymentResponse

if (isApproved && approvedAmount < chargeAmount) {
  var owedAmount = chargeAmount - approvedAmount
  //logic to re-display order total screen with owedAmount
}

不过,还有更好的方法。如果我们在 API 中明确引入“部分批准Partial Approvals”,我们就可以编写反映领域普遍存在的语言的代码——清楚地揭示我们意图的代码。以下是推荐的 API:
HTTP Request: POST /payments/
{
  "transactionId": "uniqueId",
 
"paymentDetails": {...},
 
"chargeAmount": 15.00,
  ...
}
HTTP Response:
{
 
"paymentStatus": "PARTIALLY_APPROVED"
 
"approvedAmount": 10.00,
 
"remainingAmount": 5.00,
  ...
}

现在我们的 API 有一个paymentStatus枚举值为PARTIALLY_APPROVED。API 中的这种有意清晰促使开发人员编写反映 API 语言的代码:

val (paymentStatus, remainingAmount) = paymentResponse

if (paymentStatus.PARTIALLY_APPROVED) {
  var owedAmount = remainingAmount
  //re-display order total screen with owedAmount
}

通过使用枚举,我们允许 API 使用者
  • 1) 通过 API 本身发现不同的值,从而了解有关域的更多信息,以及
  • 2) 从其强类型值中受益,从而减少错误。

 布尔值相比,枚举和数组在 API 设计中为我们提供了更多的灵活性。

何时在 API 中使用布尔值
在某些情况下,我们可以从 REST API 中布尔值的严格性质中受益。但是,这些情况应该以领域本身的约束为指导。

  • API 需要在严格性和灵活性之间取得平衡。根据定义,布尔值是限制性的。
  • API 应该具有指导意义。领域语言应该在他们的API合约发光。合约中每个字段的可能值应该很容易被发现。