设计现代 REST API 的最佳实践

介绍

应用程序编程接口 (API) 是允许应用程序相互通信的中间件。 例如,当您运行像 Facebook 这样的移动应用程序时,它使用 API 来连接到远程数据。 API 是现代 IT 行业中交换数据的标准方式,因为它们提供了许多好处。 例如,移动、桌面和 Web 应用程序可以共享由 API 获取的数据。 API 还加快了与第三方应用程序集成的内部软件的开发。 在大多数情况下,您将使用服务器端脚本语言(如 PHP、Python 或 Node.js)开发 API。

本指南重点介绍在创建对开发人员友好的 API 时要考虑的一些最佳实践。

1.使用JSON数据交换格式

以最常用的数据交换格式接受和响应 API 请求。 虽然一些遗留 API 仍然使用可扩展标记语言 (XML)),但 JavaScript 对象表示法 (JSON)) 格式更加紧凑,并且大多数开发人员都认为它既是人类又是机器可读的,如下所示。

{
  "data" : {
    "product_id" : 123,
    "product_name" : "SPORTS BIKE",
    "retail_price" : 2499.36,
    "remaining_stock" : 786
  }
}

以下代码等效于上述 XML 格式的 JSON 数据。

<data>
  <product_id>123</product_id>
  <product_name>SPORTS BIKE</product_name>
  <retail_price>2499.36</retail_price>
  <remaining_stock>786</remaining_stock>
</data>

如您所见,JSON 比 XML 更漂亮; 因此,在开发新 API 时要考虑它。 此外,像 PHP 这样的大多数编程语言都提供了不同的工具来解析和格式化 JSON 数据,无疑可以更快地访问数据。

2. 在 URL 路径中使用名词而不是动词

创建 API URL 端点时,请考虑使用名词而不是动词。 然后,接受不同的 HTTP 请求方法(GET、POST、PUT 和 DELETE)来完成不同的数据操作。 这使得 URL 更短更整洁。 此外,它还最大限度地减少了完成单个资源的 CRUD(创建、读取、更新和删除)操作所需的 URL 总数。

为了更好地理解这一点,请考虑以下在 URL 中使用动词的 API 端点。

https://www.example.com/api/v1/create_product
https://www.example.com/api/v1/get_products
https://www.example.com/api/v1/update_product
https://www.example.com/api/v1/delete_product

您可以整齐地将上述 URL 合并到单个资源路径,如下所示。

https://www.example.com/api/v1/products

然后,API 使用者可以通过执行以下请求,使用不同的 HTTP 动词来检索、提交、更新和删除数据。

检索产品:

GET  https://www.example.com/api/v1/products

创建产品:

POST https://www.example.com/api/v1/products

更新产品:

PUT  https://www.example.com/api/v1/products/{product_id}

删除产品:

DELETE  https://www.example.com/api/v1/products/{product_id}

3. 以正确的 HTTP 状态码响应

考虑使用不同的超文本传输​​协议 (HTTP) 状态代码来对客户端的请求发出响应,如下所示。

得到 https://www.example.com/api/v1/products

回复:

200 OK

https://www.example.com/api/v1/products/{product_id}

回复:

200 OK

邮政 https://www.example.com/api/v1/products

回复:

201 Created

删除 https://www.example.com/api/v1/products/{product_id}

回复:

204 No Content

此外,在返回错误时使用以下 HTTP 状态代码。

在服务器上找不到资源

404 Not Found

认证失败。 用户名、密码或访问令牌不正确。

401 Unauthorized

授权失败。 当用户经过正确身份验证但没有访问资源的正确权限时使用此错误。

 403 Forbidden

错误的请求。 来自客户端的错误。 例如,数据验证错误。

400 Bad Request

与服务器相关的错误,包括数据库故障。

 500 Internal Server Error

此外,即使在遇到错误时返回 HTTP 状态代码后,您也应该将问题发生的确切原因告知最终用户。 例如,当以 JSON 格式向最终用户返回错误时,您可以包括: HTTP 状态代码。 自定义错误代码。 一个简短的标题。 一条详细的人类可读消息,解释了问题发生的原因。

以下是一些错误消息示例。

授权错误

{
    "errors" : {
    "http_status_code" : 401,
    "title" : "Invalid Login",
    "message" : "The username/password is incorrect."
    "custom_error_code" : 401.1
  }
}

验证错误

{
    "errors" : {
    "http_status_code" : 400,
    "title" : "Validation Error",
    "message" : "The 'product_name' field is required."
    "custom_error_code" : 400.1
  }
}

授权错误

{
    "errors" : {
    "http_status_code" : 403,
    "title" : "Unauthorized",
    "message" : "You're not authorized to access this resource."
    "custom_error_code" : 403.1
  }
}

4. 保护 API 端点

除非您要创建不需要用户登录的公开 API,否则您必须在 API 端点中使用某种形式的身份验证和授权。

身份验证可证明 API 使用者的身份并验证用户名、密码和访问令牌。 另一方面,授权指定分配给最终用户的不同特权和权限。

您应该实施明确的策略来授予和拒绝对 API 端点中不同资源的访问权限。 在更高级的场景中,您可能会考虑对组使用角色和权限,并为 API 用户分配权限。

5. 允许用户页面 API 数据

您的 API 应返回数据的子集以节省带宽并避免使服务器不堪重负。 例如,如果您提供一个返回数千种产品的直销端点,则允许您的 API 使用者通过指定一个 per_page 网址参数。 此外,请确保用户可以使用 page 范围。

例如,下面的 URL 指定了一个页面大小 250 产品,从页面开始 1.

GET  https://www.example.com/api/v1/products?page=1&per_page=250

同样,导航到页面 23,您的 API 使用者可以使用以下 URL。

GET  https://www.example.com/api/v1/products?page=2&per_page=250
GET  https://www.example.com/api/v1/products?page=3&per_page=250

资源受限的 API 使用者(例如移动用户)可以指定较小的页面大小以通过使用以下页面大小的端点来检查网络流量 10 产品。

GET  https://www.example.com/api/v1/products?page=1&per_page=10
GET  https://www.example.com/api/v1/products?page=2&per_page=10
GET  https://www.example.com/api/v1/products?page=3&per_page=10

由于您最有可能从数据库返回数据,因此您可以使用 SQL 实现分页功能 LIMIT 条款。

此外,包括一个很好的做法是 meta 显示分页信息的对象,包括当前页码(page), 页面大小(per_page),以及总记录数(count) 从请求的资源返回,如下所示。

{
  "data" : {
    "product_id" : 123,
    "product_name" : "SPORTS BIKE",
    "retail_price" : 2499.36,
    "remaining_stock" : 786
  },

  ...

"meta" : {
    "page" : 1,
    "per_page" : 3,
    "total_pages" : 5,
    "count" : 15
  }

}

6. 在 API Endpoints 中接受排序参数

允许您的 API 使用者在 URL 中指定排序参数以对数据进行排序 ascending 命令。 另一方面,减号 - 可以在字段名前加上前缀来对数据进行排序 descending 命令。 以下是一些示例,说明如何对 URL 进行排序。

数据排序依据 product_name上升 命令。

GET  https://www.example.com/api/v1/products?sort=product_name

数据排序依据 product_name下降 命令。

GET  https://www.example.com/api/v1/products?sort=-product_name

数据排序依据 retail_price上升 命令。

GET  https://www.example.com/api/v1/products?sort=retail_price

数据排序依据 retail_price下降 命令。

GET  https://www.example.com/api/v1/products?sort=-retail_price

数据排序依据 retail_price 然后通过 product_name上升 命令。

GET  https://www.example.com/api/v1/products?sort=retail_price,product_name

数据排序依据 retail_price 然后通过 product_name下降 命令。

GET  https://www.example.com/api/v1/products?sort=-retail_price,-product_name

7. 允许用户过滤和搜索 API 数据

就像排序数据一样,您的 API 应该提供一种使用 URL 参数过滤数据的方法。 例如,要按名称搜索项目,API 使用者可以发出以下请求。

GET  https://www.example.com/api/v1/products?search=sample_keyword

您还可以允许用户在多个字段名称上指定关键字,如下所示。

GET  https://www.example.com/api/v1/products?category_id=7,is_active=Y

此外,有时,最终用户可能不想检索所有字段名称。 在这种情况下,允许他们使用 field 参数如下图。

GET  https://www.example.com/api/v1/products?fields=product_name,category_name,retail_price
GET  https://www.example.com/api/v1/products?fields=product_name
GET  https://www.example.com/api/v1/products?fields=category_name

8. 限制你的 API 端点

为避免滥用您的服务器资源,请限制您的 API。 例如,您可以指定单个用户在一小时、一天或一个月内可以发出的请求总数。

任何超过该限制的帐户都应失败并显示以下 HTTP 状态代码。

429 Too Many Requests

对 API 进行速率限制可提高其可用性并消除任何拒绝服务 (DOS) 攻击的机会。 你可以使用不同的技术来实现这一点,包括 Redis,它工作得很好。

9. 版本你的 API

在开发 API 时,即使在向公众发布 API 以改进它并提供更多功能之后,您也会进行不同的更改。 您可以通过电子邮件将这些更改传达给最终用户,但您必须对 API 进行版本控制,以避免在每次更新后破坏客户端的应用程序。

新版本发布后,始终至少支持一个以前的版本,并在转换所有使用者后弃用它。 要支持此功能,请在您的 API URL 中包含版本标识符,如下所示。

版本 1:

https://www.example.com/api/v1

版本 2:**

https://www.example.com/api/v2

版本 3:**

https://www.example.com/api/v3

10. 在云中托管您的 API

您可以在虚拟专用服务器、裸机服务器或专用云服务器上部署 API。 这些平台可确保保证 RAM 和 CPU,同时让您完全控制管理您的服务器和安装自定义应用程序,从而使您的 API 运行得更快。

结论

本指南介绍了在创建现代 REST API 时应遵循的最佳实践。 考虑阅读以下资源来编写和实现本指南中讨论的大部分 API 功能。

使用 HTTP 身份验证保护 PHP 资源

使用限制子句分页 MySQL 数据。

使用自定义 URL 参数对 PHP Web 资源 API 进行排序

在 Ubuntu 20.04 上使用 PHP 和 MySQL 的自定义 API 字段

在 Ubuntu 20.04 上使用 Redis 作为 PHP 的速率限制器

注:本教程在Vultr VPS上测试通过,如需部署请前往Vultr.com