RestFulAPI

欢迎你来读这篇博客,这篇博客主要是关于RestFulApi的学习分享。

序言

正文

chapter 1

实践

API的用户体验优先:

将用户体验置于首位,API设计不仅要满足功能性需求,还要关注非功能性需求,如响应速度、交互体验、API文档的易读性等。

资源导向:

资源为中心:RESTùI API应围绕资源(如用户、订单、文章、事件等)设计,每个资源都有一个唯一的URl(Uniform Resource ldentifier)
,如/users/123 表示特定用户的资源。

API的资源粒度:

精细把控API资源的粒度,既要避免资源过于细化导致调用复杂,也要防止资源过大导致的性能问题,找到最适合业务场景的平衡点。

在API设计中,资源粒度指的是你定义API接口时,对业务对象划分的细致程度。

比如,如果你有一个用户管理的API,你可以设计成:

  • 粗粒度:一个接口返回所有用户的信息;

  • 中粒度:一个接口返回单个用户的所有信息;

  • 细粒度:多个接口分别返回单个用户的基本信息、订单记录、活动参与情况等不同部分的信息。

选择合适的资源粒度很重要,因为它直接影响到API的灵活性、可扩展性和性能。粒度过粗可能导致获取数据时冗余信息多,粒度过细则可能会导致频繁调用接口,增加网络延迟和服务器负担。
理想的粒度应该是既能满足业务需求,又能保持API易用且高效。

HTTP方法的使用:

根据HTTP协议的语义,正确地使用不同的HTTP方法来执行CRUD(Create,Read,Update,Delete)操作:

  • GET:用于获取资源或资源列表,一般不应有副作用。
  • POST:用于新建资源,常出现在集合资源的末端,如 /users,附带资源数据在请求体中。
  • PUT:用于替换整个资源,需提供完整的资源表示,URI指向的是要更新的具体资源。
  • PATCH:用于部分更新资源,仅需提供要修改的属性。
  • DELETE:用于删除指定资源,
Resource Post Get Put Delete
/customers 创建新客户 返回所有客户 批量更新客户 删除所有客户
/customers1 Error 返回1号客户明细 1号客户已存在时 删除1号客户
/customers/1/orders 创建1号客户的新订单 返回1号客户的所有订单 批量更新1号客户的订单 删除1号客户所有订单

无状态性:

每个请求都包含处理请求所需的所有信息,服务器不需要存储会话状态。客户端可以通过标准的认证机制(如OAuth、JWT)来维护状态。

层级化结构:

在更复杂的系统中,可能会倾向于提供能够让客户端通过多层关系进行导航的URI,如/customers/1/orders/99/products,这是错误的做法。

尽量保持URI相对简洁。一旦应用有了某个资源的引用,应能够使用该引用找到与该资源相关的项目。可以通过/customers/1/orders找到客户1的所有订单,然后通过/orders/99/products找到该订单中的产品。

超媒体作为引擎信息:

API响应中包含链接和其他元数据(如链接关系、操作选项),帮助客户端发现和导航到其他相关资源。

版本管理:

API版本管理可以有不同的策略,但常见做法是在URI或请求头中指明版本。

  • 基于URI
  • 基于HTTP header

错误处理:

提供统一格式的错误响应,如使用HTTP状态码表示错误类型,并在响应体中包含详细的错误信息。

幂等性:

对于同一请求多次发送应该产生相同的效果(除非资源状态本身已改变),这对于PUT、DELETE等操作尤其重要。

内容协商:

支持客户端与服务器之间协商数据格式,如JSON、XML或其他内容类型,通过Content-Type和Accept头部来决定请求和响应的内容格式。

过滤与排序:

提供对资源列表的过滤与排序功能,通常通过查询参数实现。

分页与限制:

当资源列表过长时,应提供分页功能,常见的做法是通过查询参数传递页码和每页数量

字段选择:

允许客户端指定需要返回的资源字段,减少不必要的数据传输,提升性能

必要时提供客户端SDK

简化开发流程:SDK充当了API与客户端应用程序之间的桥梁,通过预先封装好HTTP请求、响应处理、身份验证机制、错误处理等复杂的网络交互逻辑,降低了开发者直接调用API的难度和复杂性,提高了开发效率。

增强易用性:SDK通常会提供与目标编程语言更为契合的API接口和方法,使得开发者能以更加自然和便捷的方式调用API,从而专注于业务逻辑的开发,而不是处理低层级的技术细节。

标准化和一致性:SDK可以确保客户端与服务器间的交互遵循一致的标准和最佳实践,避免因开发者自行实现造成的不一致性问题,有利于保证API服务的安全性和稳定性。

提高用户体验:通过SDK可以实现诸如缓存、离线支持等功能,提升客户端应用的性能和用户体验,尤其是对于移动应用和弱网络环境下的表现尤为重要。

快速迭代与支持:当后台API发生变化或新增功能时,通过提供更新的SDK版本,可以让客户更容易地进行升级和适应,避免因API变动而导致的大量代码重构工作。

测试与监控:

设计API的同时应考虑到测试的便捷性,提供Swagger/OpenAPI规范或类似的API描述文件可以帮助自动化测试。同时,为API添加日志记录、性能监控等功能,以便后期维护和优化。实现全面的API性能监控,包括但不限于响应时间、错误率、吞吐量等指标,以便及时发现并解决问题,同时,建立详细的日志系统,记录所有API调用行为及其相关数据,这对于排查问题和审计追踪至关重要。

向后兼容与升级策略:

随着业务发展,API可能需要迭代更新。在设计初期就要考虑如何在不影响现有客户端的情况下升级API这可能涉及到版本控制、逐步弃用旧版本API及过渡策略等问题。在实际的RESTfuIAPI设计中,向后兼容和升级策略可能包括:

版本控制:就像手机系统会有1.0版、2.0版一样,API也可以加上版本号。当有重大更改时,可以发布一个
新的API版本,老版本维持运行一段时间,让开发者逐渐迁移到新版API上。

显式版本号:在APIURL中包含版本号,如https:
//api.example.com/v1/users和https://api.example.com/v2/users分别代表不同版本的用户接口。

非破坏性变更:
尽可能地在不改变原有接口行为的前提下进行升级,比如新增字段但不删除原有的字段或者新增API路径而不是修改已有路径的行为。

兼容模式:在新版本中暂时保留一些旧的行为模式,即使它们已经被优化或替换,直到大部分用户完成迁移。

标准化约束:

尽量遵循现有的网络标准和最佳实践,例如RFC723x系列HTTP规范,确保API的行为可预测且与其他系统兼容。

速率限制:

对于高负载的API,实施合理的速率限制策略,避免因恶意或过度的请求导致服务崩溃。应在API响应中提供有关剩余配额的信息,便于客户端做出相应的调整。

认证与授权:

引入多种认证方式,如基本认证、OAuth、JWT等,根据场景选择合适方案。授权方面,基于角色的访问控制(RBAC)或基于权限的访问控制(ABAC)
可以帮助定义不同用户或客户端对资源的操作权限。

批量操作:

对于批处理操作,提供API支持,允许一次调用执行多个相关的操作,降低客户端与服务器间的通信开销。

你有一个电商应用,平常可能需要一次次发送请求去创建、更新或删除多个订单。采用批量操作的话,就可以在一个API请求中包含多个订单的数据,一次性完成这些操作,这样能大大提高效率,减少网络传输的开销。在RESTful
API设计中,批量操作可能体现为一个特定的接口,接收一个包含多个资源数据的集合作为输入参数,然后统一进行相应的操作处理。
不过要注意的是,批量操作虽然高效,但设计时也需要考虑其复杂性和可能带来的风险,例如错误处理和事务一致性等问题。

异步处理:

有时POST、PUT、PATCH或DELETE操作可能需要一段时间才能完成的处理。如果等待处理完成再向客户端发送响应,可能会导致不可接受的延迟。
在这种情况下,应考虑将操作变为异步。返回HTTP状态码202(Accepted),表示请求已被接受进行处理,但尚未完成。

应公开一个检查异步请求状态的端点,以便客户端可以通过轮询状态端点来监控状态。将状态端点的URI包含在202响应的Location头中。

客户端可以通过定期向上述Location头中提供的状态端点发送GET请求来获取异步操作的最新状态。当操作最终完成时,状态端点应返回适当的HTTP状态码(
如200或201表示成功,或者错误代码表示失败),以及操作结果(如果适用)的相关信息。

缓存策略:

对于那些不会频繁变动且计算成本较高的资源,适当引入缓存机制可以显著提升API性能。通过设置合适的HTTP缓存头(
如Cache-Control、ETag等),让客户端和服务端协同实现高效的缓存管理。

Cache-Control

Cache-Control是HTTP头部的一个指令,用于控制缓存机制如何存储和检索缓存响应。它可以由服务器端或客户端设置,指示缓存何时可以使用已存储的响应,以及缓存应该保留多长时间。常见的一些指令包括:

max-age:定义从服务器响应发出开始,响应在客户端可以被认为是新鲜的最长时间(以秒为单位)。

no-cache: 告诉中间缓存不能直接使用存储的响应,必须先向服务器验证是否有更新版本。

public: 表明响应可以被任何缓存存储,即使是公共中间代理也可以。

private: 表示响应只能被单个用户私有缓存存储,不应由共享缓存(如CDN)存储。

must-revalidate:在缓存项过期后,要求缓存强制向原始服务器验证资源是否仍然有效。

ETagETag 全称为实体标签(Entity Tag),是一种独特的服务器生成的资源版本标识符。

ETag的主要目的是帮助确认资源内容是否发生改变,从而决定是否可以从缓存中提供响应,或是需要从服务器获取新的副本,当服务器首次发送资源时,会在响应头部包含一个ETag值。

客户端在后续请求同一资源时,可以在请求头部包含If-None-Match头,附带之前收到的ETaq值。服务器收到请求后,对比请求中的If-None-Match与当前资源的ETag。如果二者匹配,说明资源内容未变,服务器将返回304
Not Modified响应,
告知客户端可以继续使用本地缓存的资源;如果不匹配,则说明资源已更新,服务器会发送新的资源内容及新的ETag值。

安全性强化:

加密通信:强制要求HTTPS连接,确保数据传输过程中的隐私和完整性。

防止跨站请求伪造(CSRF)攻击:对于需要用户身份验证的AP1,采取措施防范这类攻击,比如添加CSRF 令牌。

健康检查与可用性:

提供一个专门的健康检查API端点,用于快速验证服务是否正常运行,这对于自动化的运维和故障恢复十分有用。

API分层与网关:

在复杂的系统架构中,可能需要引入API网关来实现统一的安全策略、路由管理、限流熔断等功能,并且可以根据不同的层级划分内部服务接口和对外公开的API。

回滚策略:

在API发布新版本后,如果出现严重问题,应有一套快速回滚至先前稳定版本的预案,确保业务连续性

API的可发现性:

通过目录服务或者API门户提供API清单,使开发者能够轻松查找和了解所有可用的API资源,从而提高API的利用率和推广效果。

API性能优化:

通过数据库索引优化、缓存策略、CDN加速、APl Gateway的负载均衡等方式提升API的性能表现,为用户提供更快捷的服务

API的实时统计分析:

实施API调用实时统计和数据分析,洞察API的使用趋势、热点路径、潜在瓶颈等,为优化决策提供数据支持。

API的自动化测试

编写单元测试、集成测试和契约测试,确保API的功能正确性,随着API的演变,保持测试覆盖率并及时更新测试用例。
API的文档更新同步:确保对应的API文档、示例代码和SDK等资料能及时更新,避免开发者依据过时文档编当API发生变化时,写代码导致的问题

API的合规性考虑:

在设计API时要考虑法律法规的要求,例如GDPR对于数据隐私的规定,确保API的设计和使用符合相关法 规标准。

API的扩展性设计:

考虑未来的业务拓展和技术变革,设计API时预留一定的扩展性,例如通过URL路径参数或查询参数灵活控制资源范围,或采用模块化设计以便后续增加新的功能组件。

参考资料

启示录

富贵岂由人,时会高志须酬。

能成功于千载者,必以近察远。


RestFulAPI
https://allendericdalexander.github.io/2024/03/30/RESTfulAPI/
作者
AtLuoFu
发布于
2024年3月30日
许可协议