你有需求? 点击这里 尝试让 AI 为你生成Baklib调研方案!

Baklib Logo

REST API 设计最佳实践

  浏览:26 巴克励步

REST API设计需功能规格说明书,围绕客户端、服务器端、资源三要素,定义端点、HTTP方法、负载格式、返回码等,需正式文档、安全、缓存、版本控制,遵循名词端点、HTTP方法对应CRUD等最佳实践。

REST API 设计最佳实践
Baklib Dagle Tanmer CMS DXP DAM

在开始 REST API 设计之前,你需要一份功能规格说明书。它规定了系统做什么,而不是如何做。它可能包含一些模拟截图和信息流图,但本质上是一份高层级文档。相比之下,API 设计则深入到其运作的细节。

快速概览

网络上充斥着无数倡导“API设计”和“最佳实践”等的网站和页面。

API 设计大约 80% 是常识,其余部分是技术性的。

Web API 将服务器数据暴露给客户端用户,并接收来自他们的请求。大多数消费者网络流量都是应请求向客户端提供的数据。在相反方向上,客户端提供登录数据、进行购买、填写政府表格等。

在服务器端,信息通常存储在像 MySQL 这样的数据库中。客户端 API 封装了对数据库的操作,例如下载信息、存储新的客户端信息以及更改客户端信息。

基本思路是根据反映主要数据库表的主要数据类别来划分 API。尽管客户端 API 请求会转化为服务器上的数据库操作,但 API 客户端对底层数据库一无所知。

例如,一个商业零售网站将拥有关于客户、产品、制造商等的数据。可以访问像亚马逊这样的网站来获得概念。

在 API 术语中,API 目标将是一个URL,如 https://www.example.com,数据类别将由端点描述,例如 /customers、/products 等。一个完全限定的

URL-端点将如下所示:https://www.example.com/customers

更复杂的交易可能需要单独的端点,也许会产生一个数据库视图,以JSON或XML文件的形式返回给客户端。最后,可以在端点中添加查询以过滤输出:

https://www.example.com/customers/cust_details?yourname=”John Doe”&custNum=123456

在每个端点内,你需要为相关的REST调用(GET、POST、PUT、PATCH、DELETE等)提供定义、模板和示例。

其他要素


  • 正式的 开发文档 是API设计中不可或缺的一部分。没有它,一切都会变得没有意义。

API设计还必须明确规定:


  • HTTP请求的输入和输出负载格式(通常在有负载时为JSON或XML)。 * HTTP返回代码及其在特定API上下文中的含义:每个人都知道404响应意味着"页面未找到",但在API上下文中具体是什么未找到?以及如何纠正这个错误?

REST API设计要素

一个REST API围绕三个参与者构建:

1. 客户端

在客户端,我们已经了解了一些命令。很少有客户端开发人员会直接发出这些命令。你可能会使用cURL在沙盒环境中测试它们,但更可能的是,你会使用一个程序库。最普遍的客户端编程环境是JavaScript:fetch()调用处理HTTP/HTTPS请求。同时有相关的例程来设置和解析JSON文件。一个很好的入门资源是 MDN web docs – JavaScript。

一些API供应商为客户端开发者提供了专门的库,有效地封装了HTTP REST API调用。这对于我们熟知的商业风格API来说可能效果很好。但对于需要或返回大量数据的B2B API,其效果可能就不那么理想了。

2. 服务器端

服务器端发生的事情是万物的关键,并且没有硬性的规则。这就是“80%的常识”。服务器必须使用REST API命令作为用户界面的基础,来提供信息或征求用户响应。服务器端开发人员可以使用本地Node.js安装进行大量的设计和测试。Node.js允许您在开发机器上设置一个服务器(https://localhost:<端口号>)用于开发和测试。可以将Node.js作为一个起点。

3. 资源

  • 资源是存在于服务器上的实体,可通过HTTP GET命令访问。有时,资源不是数据库对象,而是要调用的后端过程,该过程使用客户端提供的任何数据来执行请求。
  • 资源可以通过POST命令创建。它可能是对现有资源的复制。
  • PUT命令将更新现有资源,如果没有可更新的内容,则创建一个新资源。
  • 要更新资源(例如数据库中的单个字段)而不替换它,请使用PATCH命令。
  • DELETE命令将删除资源。

良好API设计的重要性

1. 优势

良好的API设计将吸引用户;糟糕的API设计会让他们望而却步,转而寻找其他方案。如果您的API是商业产品的一部分,那么这就直接关系到利润或亏损。

2. 不足之处

在技术层面,还有更多需要考虑的因素:你的API可能看起来很棒,易于使用,各方面都表现优异——但它的速度却慢得令人难以忍受。缓慢的性能也会让用户望而却步,从而导致收入损失。

3. 糟糕之处

💛🧡🧡客户评价:Baklib 的多站点功能能够在一个位置进行更改并共享这些文档到不同的平台。它帮助我们避免了信息在多个地方,而只有一个来源的单一可信源追踪。

如果其他方面都很好,但服务器端的编程风格是“意大利面条式代码”怎么办?错误修正会变得困难,更新则成为一场噩梦。糟糕的服务器端编码将导致维护成本增加。

市面上有许多商业产品可以帮助进行API设计,但同样,常识是无法替代的。

API设计最佳实践

确保API的可扩展性

API必须解决现实世界的挑战:在负载和输出过长的情况下对其进行测试。

采用国际设计标准

OpenAPI v3规范是一个良好的起点。请参考这里:OpenAPI规范以及这里:Swagger编辑器

尽可能简单,但绝不简陋

这是一个风格问题,但它会影响性能:在响应查询时,提供所有必需的信息,但不要提供更多。如果你需要从一条大型记录中提供三个字段,那么包含这些字段的所有记录的JSON文件就过度了,甚至可能适得其反。它会减慢响应速度,甚至可能导致瓶颈情况。它也可能导致客户端缓冲区溢出。

充分利用REST

存在一些"手段"可以绕过REST,最常见的是维护状态的方法。最广为人知的是cookies。它们有其用武之地,大多数网站都会使用它们,通常是为每个请求提供会话用户凭证。偏离REST规范甚至可能带来安全风险。

端点路径应使用名词而非动词

这个端点https://www.example.com/customers使用了名词——customers。应避免使用https://www.example.com/listingCustomers这种类型的示例。REST API中唯一的动词是GET、POST、PUT、PATCH、DELETE等命令。

为CRUD功能使用HTTP方法

缩写CRUD代表创建、读取、更新和删除。应使用相应的HTTP方法,而不是通过"聪明"的编程技巧来绕过。你可以不通过HTTP访问远程数据库;但不要这样做,这不是平台无关的。

与HTTP响应状态码配合使用

HTTP响应状态码在此处有文档记录:HTTP响应状态码。

HTTP响应状态码表明一个特定的HTTP请求是否已成功完成。响应分为五类:

  1. 信息响应(100 – 199)
    1. 成功响应(200 – 299)
    2. 重定向消息(300 – 399)
    3. 客户端错误响应(400 – 499)
    4. 服务器错误响应(500 – 599)

在许多情况下,我们需要一个表示成功的 200 响应。400 响应通常可以在客户端进行纠正并重新提交请求。500 响应可能需要采取“稍后再试”的操作。一个例外是 511,即由控制服务器访问的代理服务器发出的需要网络身份验证,这意味着客户端凭据不正确。

添加筛选、排序和分页

在 GET 查询中,这三者都是通过在端点后添加参数来实现的。没有标准方法,很大程度上取决于后端开发人员。请参阅REST API 设计:筛选、排序和分页。

一种有趣的分页方法基于以下范式:

  1. 使用GET查询时,提供一个必需的页面长度(以行为单位)。
    1. GET返回第一页数据和一个特殊的延续URL,全部包含在一个JSON文件中。
    2. 重复使用延续URL进行GET请求,直到没有更多数据为止。

强制执行安全性

强制使用HTTPS进行数据传输,而不是HTTP。这是一个庞大的主题,远远超出了短篇博客的范围。作为起点,请查阅以下内容:内容安全策略(CSP)REST API安全最佳实践:认证与授权,以及REST API安全要点

从最后一个链接,我们有一个快速检查清单:

  1. 保持简单。保护一个API/系统——只需达到必要的安全程度。
  2. 始终使用HTTPS。始终使用SSL。
  3. 使用密码哈希。始终加密密码。切勿以明文发送。
  4. 切勿在URL上暴露敏感信息。用户名、密码、会话令牌和API密钥不应出现在URL中,因为它们可能被Web服务器日志捕获,从而容易被利用。
  5. 考虑使用OAuth进行授权。
  6. 考虑在每个请求中添加时间戳。在自定义HTTP头中实现。
  7. 输入参数验证。我们在上面提到过这一点。如果参数验证失败,则拒绝请求。

添加缓存数据

缓存存储了频繁访问数据的副本。缓存响应数据可以

  • 减少带宽使用
  • 降低响应延迟
  • 减轻服务器负载
  • 临时隐藏网络故障

GET 请求会自动缓存。PUT 和 DELETE 则不会。

可以使用请求中的缓存控制头来控制缓存。有关缓存的教程,请参见此处:缓存 REST API 响应

API 版本控制

以下情况需要进行版本控制:

  • 错误修正
  • 添加新功能
  • 全新发布

典型的版本控制方案基于三位数字代码:

<主版本>.<次版本>.<维护构建级别>

错误修正不得对 API 进行任何更改。这对 API 用户是透明的。它增加的是维护构建级别

添加新功能不得以任何方式更改现有的 API 调用。API 用户可以自由选择是否使用它们。增加的是次版本号。

主版本发布可能不一定向后兼容。这要求至少在已知的弃用期内,之前的版本仍需可用。

所有这一切引出了一个问题:如何将版本号包含在 API 调用中,以确保不破坏现有的客户端代码。以下是关于此主题的一种方法:如何对 REST API 进行版本控制。另一个简洁的描述在此处:四种 REST API 版本控制策略

定义所需功能以及如何获取,同时遵循当前标准

通常,您会使用OpenAPI标准。您可以使用Swagger 来按照标准制作API原型。这是我们第一次接触到需要迭代进行设计和实施,并设定项目里程碑来评估进度的问题。这是一个重要的项目管理问题,超出了非正式博客的范围。

考虑构建良好的客户端实现,而不仅仅是网络访问

这基本上是使用客户端SDK(软件开发工具包)与原始cURL命令行请求之间的区别。大多数客户端编程环境都提供此类SDK作为内置库或包。JavaScript的fetch() API可以实现这一点,尽管它需要为调用进行相当多的“设置”。有一些商业产品可以打包或替换fetch调用,以使开发人员的生活更轻松。例如,请参阅10个最佳JavaScript HTTP请求库

关注使用场景

这是一个文档问题。许多CCMS(包括Baklib)提供了一个三栏分割窗口,左侧是简短的目录,中间是文档文本,右侧是示例代码,并提供开发者语言选择的选项。

如果可能,示例代码应能提供有实际意义的结果。

一些开发文档工具提供了一个沙盒,您可以在其中尝试真实的HTTP请求。或者,该沙盒可能需要链接到CCMS文档工具。

常见的API设计错误

以下是一些常见的API设计错误:

  • 不要使用过多的端点。相反,应考虑以下参数:{some_spec}
  • 使用正确的HTTP命令(PUT、POST、UPDATE)
  • 在客户端验证输入数据
  • 确保API是可扩展的
  • 确保API是安全的(使用HTTPS而非HTTP)
  • 避免轮询重复请求。使用webhooks
  • 谨慎使用HTTP响应代码,并确保有良好的错误处理机制
  • 开发过程中未能维护开发文档
  • 无法应对高负载:响应时间问题

结论

你无法回避一个必要性:必须知道你可以编码实现你的设计。反之,你也应注意设计出你可以编码实现的内容!

在服务器端,你可以使用任何合理的编码平台;选择往往是基于“信仰”而非硬逻辑。如今,你可以在客户端和服务器端都使用JavaScript编码。这在开发人员资源的部署上可能是一个巨大的优势。

设计REST API与其实现并非完全脱节。即使服务器端所需的一切都已明确定义,你也需要让它运行起来才能进行客户端API的开发。无论是使用真实的开发服务器,还是在本地机器上使用Node.js,都没有任何区别。

在某种程度上,设计客户端是最困难的部分。你需要满足(很可能)非技术用户的需求。使用 Postman 或类似工具让 HTTP API “良好” 运行是没问题的;困难的工作在于将这一切封装到用户界面中。为此,有适用于 JavaScript 等的 UX 工具,但这超出了本文范围。重要的是设计-实现-文档化的迭代过程。

最后,你必须根据你的功能规格说明来评估这一切。

因此,一些额外的资源将有助于确保成功设计 REST API:

如果你对 JavaScript、HTML、CSS 和其他网络技术是新手,网上有一些很好的课程。

我使用过这些:

我喜欢的书籍:

  • JavaScript: The Definitive Guide, D. Flanagan, O’Reilly
  • Node.js: The Comprehensive Guide, S. Springer, Rheinwerk Computing

最重要的是:善用搜索引擎!



Baklib通过知识访问技术、创新的用户界面提供支持,汇集了业界最广泛的知识访问方法、联合搜索、流程智能、多语言功能和灵活的外观的强大功能,所有这些都在一个搜索框后面,以实现独特的在线自助服务。
Baklib Birds
to top icon