作者孙毅,API7.ai 技术工程师,Apache APISIX Committer
万物互联的世界充斥着各式各样的 API,如何兼顾标准 API 至关重要。RESTful API 是目前世界上最风行的 API 架构格调之一,它能够帮忙你实现客户端与服务端关注点拆散,让前后端各自迭代,晋升管理效率;其无状态的个性能够让利用更容易扩大,更容易的实现缓存策略从而晋升零碎性能和用户体验。本文将介绍什么是 RESTful API 以及咱们如何应用它。
首先,抛开 API 这个概念,咱们来聊聊在生活中如何传递信息。
当你在商店将钱拿给老板通知他你须要买电池,老板在收到钱后在货架上找到电池并递给你。一个买电池的交易顺利完成。
计算机软件则通过 API 来实现信息的传递,先来看维基百科定义:
An application programming interface (API) is a way for two or more computer programs to communicate with each other. It is a type of software interface, offering a service to other pieces of software.
软件 A 通过 API 向软件 B 发动申请,软件 B 在查问本人资源后将申请的响应内容通过 API 返回 A。
软件 A 通过 API 向软件 B 发动申请就好比你跟老板说你须要电池,软件 B 在将数据返回给软件 A 就好比老板找到电池后将电池给你。
这一过程软件 B 不须要晓得软件 A 为什么要数据,就好比商店老板不会问你买电池的目标。软件 A 也不须要晓得 B 软件的数据是怎么找到的,就好比你买电池的时候你也不会问老板电池从哪里进货一样。每个软件之间通过 API 传递信息,各司其事,使得程序世界变得有序牢靠。
什么是 RESTful API
Roy Fielding 在他 2000 年的博士论文《建筑风格和基于网络的软件架构设计》中定义了 REST(Representational state transfer),REST 架构格调定义了六个指导性束缚。一个合乎 局部 或全副 束缚的零碎被松散地称为 RESTful。
(图片起源:Seobility)
REST 的约束条件(长龙在排版时能够思考一键截图 or 分点 > 横向叙述)
约束条件 | 详述 | 劣势 |
---|---|---|
Client–server architecture | 通过将用户界面问题与数据存储问题离开,进步了跨多个平台的用户界面的可移植性,并通过简化服务器组件进步了可扩展性。 | 1. 客户端、服务端解耦。 2. 晋升用户平台跨平台的可移植性。 3. 晋升服务器端的可拓展性。 |
Statelessness | 客户端的每个申请到服务器必须蕴含申请所需的所有信息,并且不能利用服务器上存储的任何上下文,会话状态齐全保留在客户端。 | 1. 易扩大,无会话依赖,任何服务器能够解决任何申请。 2. 易缓存,晋升程序性能。 |
Cacheability | 要求申请响应中的数据被隐式或显式标记为可缓存或不可缓存。如果一个响应是可缓存的,那么客户端缓存就被授予为当前的等效申请重用该响应数据的权力。 | 1. 缩小带宽。 2. 缩小提早。 3. 缩小服务器负载。 4. 暗藏网络状态。 |
Layered system | 通过束缚组件行为容许架构由分层层组成,这样每个组件都不能“看到”超出它们与之交互的间接层。通过将零碎常识限度在单个层,升高了整个零碎的复杂性并促成了底层独立性。 | 1. 升高整个零碎的复杂性。 2. 促成底层的独立性。 3. 可不便的施行负载平衡。 4. 可将业务逻辑和安全策略解耦。 |
Code on demand (optional) | 容许通过下载和执行小程序或脚本模式的代码来扩大客户端性能。 | 1. 进步零碎的可扩展性。 |
Uniform interface | 次要蕴含四点: 1. Resource identification in requests. 客户可能通过申请中蕴含的 URI 来辨认一个资源,将服务端资源和客户端申请资源解耦。 2. Resource manipulation through representations. 当客户端领有一个资源的示意,如 URI,那么就有足够的信息来批改或者删除资源。 3. Self-descriptive messages. 每个音讯都包含足够的信息来告知客户客户端该如何解决该信息。 4. Hypermedia as the engine of application state (HATEOAS). 客户端不须要任何额定的编码通过服务端返回的资源链接,就能够使得用户获取所有的资源。 |
1. 简化了整体零碎架构。 2. 进步了交互的可见性。 |
RESTful API 最佳实际
强调组件间的 对立接口 是 REST 架构格调与其余基于网络的格调辨别开来的外围特色,基于此特色,本文梳理了 RSETful 最佳实际,以帮忙你更好的设计 API。
门路名称防止动词
应用 HTTP 办法来表白资源操作行为,而不是将行为动词定义到门路中。
// Good
curl -X GET http://httpbin.org/orders
// Bad
curl -X GET "http://httpbin.org/getOrders"
- GET 获取指定 URI 的资源信息
// 代表获取以后零碎的所有订单信息
curl -X GET http://httpbin.org/orders
// 代表获取订单编号为 1 的订单详情信息
curl -X GET http://httpbin.org/orders/1
- POST 通过指定的 URI 创立资源
// 代表创立一个名称为 order 的资源
curl -X POST http://httpbin.org/orders \
-d '{"name":"awesome", region:"A"}' \
- PUT 创立或全量替换指定 URI 上的资源
// 代表将 id 为 1 的 order 进行数据替换
curl -X PUT http://httpbin.org/orders/1 \
-d '{"name":"new awesome", region:"B"}' \
- PATCH 执行一个资源的局部更新
// 代表将 id 为 1 的 order 中的 region 字段进行更改,其余数据放弃不变
curl -X PATCH http://httpbin.org/orders/1 \
-d '{region:"B"}' \
- DELETE 通过指定的 URI 移除资源
// 代表将 id 为 1 的 order 删除
curl -X DELETE http://httpbin.org/orders/1
URI 应用复数模式
若应用复数的模式来示意获取某一类资源,例如:
curl -X GET "http://httpbin.org/order"
应用复数模式,会使用户产生该零碎中只有一个 order 的困惑,用复数模式在逻辑上则顺畅很多。
curl -X GET "http://httpbin.org/orders"
善用 HTTP 状态码
HTTP 规范定义个状态码,大抵能够分为以下几类:
状态码 | 含意 |
---|---|
2xx | 胜利,操作被胜利接管并解决 |
3xx | 重定向,须要进一步的操作以实现申请 |
4xx | 客户端谬误,申请蕴含语法错误或无奈实现申请 |
5xx | 服务器谬误,服务器在解决申请的过程中产生了谬误 |
应用标准状态码,开发人员能够立刻辨认问题,能够缩小发现不同类型谬误的工夫。
版本治理
随着业务需要的变更,曾经上线的 API 大概率是要对应调整的。如果咱们的 API 有第三方在应用,让每一个客户端依据咱们 API 的变更而变更显然是不可能的,这个时候就要引入 API 版本治理概念了,既能够保障历史 API 失常应用,又能够迭代新的 API 以满足新的业务需要。
常见的版本控制伎俩有:
- 通过申请中门路来做版本控制
// 申请 v1 版本的 API
curl http://httpbin.org/v1/orders
// 申请 v2 版本的 API
curl http://httpbin.org/v2/orders
- 通过 Query 参数来做版本控制
// 申请 v1 版本的 API
curl http://httpbin.org/orders?version=v1
// 申请 v2 版本的 API
curl http://httpbin.org/v2/orders?version=v2
- 通过 Header 来做版本控制
// 申请 v1 版本的 API
curl http://httpbin.org/orders -H "custom-version: v1"
// 申请 v2 版本的 API
curl http://httpbin.org/orders -H "custom-version: v2"
APISIX 如何助力 RESTful API
作为一个动静、实时、高性能的 API 网关,Apache APISIX 能够在任何 RESTful API 服务上运行,并应用插件来增加新的服务和扩大其性能,这合乎 RESTful 定义中的 Layered system。此外,对于一些没有遵循 RESTful API 定义的历史服务,APISIX 也能够帮你在 不改变原有业务代码 的状况下实现接口的转换,使你的接口实现 Uniform interface 这一 REST 限度条件,使你的 API 能够更好的恪守 RESTful API 标准。
分层零碎:反对业务逻辑和平安逻辑的宰割
你能够只用关注业务逻辑的实现,接口的平安逻辑能够交给 APISIX Authentication 类插件解决,例如 key-auth。APISIX 反对大量的 Authentication 插件,咱们以 openid-connet 为例如下图所示:
咱们能够看到,应用 APISIX(API Gateway)在业务服务器后面加一层认证逻辑,就能够起到爱护上游服务的作用,让你的业务逻辑和平安逻辑高效解耦。
Layered system:多负载平衡协定反对
APISIX 作为 API 网关,能够设立在客户端和服务端之间,实现不同的负载需要。你甚至能够自定义负载平衡的逻辑。
反对的负载平衡算法有:
roundrobin
: Round robin balancing with weights.chash
: Consistent hash.ewma
: Pick the node with minimum latency. See EWMA Chart for more details.least_conn
: Picks the node with the lowest value of(active_conn + 1) / weight
. Here, an active connection is a connection being used by the request and is similar to the concept in Nginx.- user-defined load balancer loaded via
require("apisix.balancer.your_balancer")
对立接口:使历史 API 更加 RESTful
对于曾经存在很久的历史 API,如果没有很好的遵循 RESTful API 准则。你能够在不革新原有 API 逻辑的状况下从新通过 APISIX 来封装新的 API 以满足不同的业务场景。
应用 proxy-rewrite 改写客户端申请
在本文中上方提过咱们的门路中不要有动词。
例如:历史版本 API 有 /getOrder
接口,咱们能够通过 proxy-rewrite
插件来将 API 申请代理到历史 API 上:
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '{"methods": ["GET"],"uri":"/orders","plugins": {"proxy-rewrite": {"uri":"/getOrder","scheme":"http",}
},
"upstream": {
"type": "roundrobin",
"nodes": {"127.0.0.1:80": 1}
}
}'
你也能够同样应用该插件进行 API 版本治理上的操作。
应用 response-rewrite 插件改写服务端响应
当咱们的历史 API 存在响应状态码不标准时,咱们能够通过 response-rewrite 代理 response 响应从而达到批改响应状态码的目标。
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '{"methods": ["GET"],"uri":"/orders","plugins": {"response-rewrite": {"status_code": 201,"body":"{\"code\":\"ok\",\"message\":\"new json body\"}","vars":[[ "status","==",200]
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {"127.0.0.1:80": 1}
}
}'
例如,这个例子示意将申请 /orders 门路的 API 中响应为 200 的状态的申请批改为 201。
APISIX 反对十分丰盛的插件,期待你去开掘更多的玩法。
总结
本文具体阐明了什么是 API,什么是 RESTful API 以及其最佳实际。另外还介绍了如何通过 APISIX 来实现业务逻辑和平安逻辑拆散,如何应用 APISIX 在不改变原有业务代码的状况下将历史 API 服务更加 RESTful。心愿本文对你理解 RESTful API 有所帮忙,也欢送你来 GitHub 一起游玩。