2023年12个必备的书籍API
使用 OpenAPI 和 Prism 模拟回调
回调是服务为响应某个操作而向其他服务发出的传出异步请求。它们与 JavaScript 等流行编程语言中的回调函数非常相似。但它们是在 API 抽象级别执行的。
回拨在日常生活中随处可见,例如当您订购包裹时。如果您订阅更新,运送包裹的物流公司将向您发送有关事件的通知,例如:“您的包裹已准备好领取”、“您的包裹已到达最终目的地”。
这种类型的通信是异步且实时发生的。非常酷的东西!
其他方法
回调解决了异步通信问题。通常,执行计算密集型操作的系统使用 Kafka、RabbitMQ 或基于 JMS 的消息队列。使用主题实现对事件的选择性订阅。但是,由于底层协议不是 Web 友好的(不是基于 HTTP),因此典型的 Web 应用程序无法利用这些解决方案。
另一种常见方法是使用配置 WebHooks。GitHub 或 Stripe 公开了一个用于设置它们的 UI。
我说过 WebHook 吗?简单解释一下:WebHook 是接收回调请求的调用方 API 端点。
这种解决方案的缺点是您需要使用 WebHook 的 URL 手动更新外部服务(如 GitHub)。这使您的配置变得分散,难以维护和更新。
为什么要回调
- 它们在 OpenAPI 中是标准化的
- 它是一个 Web 标准,意味着它被设计用于在基于 HTTP 的环境中安全地使用,通常是公开可用的(面向客户端)
- 支持选择性数据订阅
- 接收端点配置保留在调用方,这使其成为单一事实来源
如何使用 OpenAPI 和 Prism 设置回调
现在让我们设定一个目标。目标是模拟一个完整的、真实的回调命中 WebHook 的示例。我们将使用 Prism 作为模拟工具。
假设有一家名为 Ship-n-Pray Ltd. 的物流公司。作为该公司的合作伙伴,我们决定集成他们的 API 来自动化我们的流程。例如,当包裹到达时,我们希望向客户发送电子邮件。或者跟踪和统计物流公司的运营情况。
幸运的是,他们公开了一个 API,让我们可以跟踪这一点。此外,这是一个 OpenAPI 规范。我们正在与专业人士打交道!
Ship-n-Pray Ltd 的 API 的 OpenAPI 规范
logistics.oas3.yaml
openapi: 3.0.0
paths:
/tracking/{parcelId}/subscribe:
parameters:
- name: parcelId
in: path
required: true
description: The parcel identifier
schema:
$ref: '#/components/schemas/parcelId'
post:
summary: Subscribe to notifications about given parcel
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
url:
type: string
format: uri
token:
type: string
required:
- url
- token
responses:
202:
description: 'Successfully subscribed to notifications about given parcel'
content:
text/plain:
examples:
ok:
value: 'ok'
callbacks:
notification:
'{$request.body#/url}?token={$request.body#/token}':
post:
summary: 'Receive single notification about a parcel'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/notification'
responses:
200:
description: 'Notification successfully processed'
content:
text/plain:
examples:
ok:
value: 'ok'
components:
schemas:
parcelId:
type: string
pattern: '^[0-9]{16}$'
notification:
type: object
properties:
parcelId:
$ref: "#/components/schemas/parcelId"
status:
type: string
enum:
- pick-up
- in-transit
- delivered
required:
- parcelId
- status
好吧,等一下,内容相当多。让我描述一下重要的几行。
1.我们将POST
在端点执行请求/tracking/{parcelId}/subscribe
,以便订阅有关 所标识的包裹的通知parcelId
。
注意: $ref: '#/components/schemas/parcelId'
这是一个技巧,使我们能够重用parcelId
模式定义(在文档末尾的组件部分中定义)
2.请求主体部分定义预期的输入负载:
url
使您可以告诉物流公司您希望在哪个 URL 上接收通知token
是我们安全的基础。每次订阅都会生成令牌并存储在我们这边。在收到通知时,我们将验证令牌是否由我们生成。
注意: token 可能是随机生成的数据(我们需要将其存储在我们这边)。它也可能是公钥(那么我们只需要验证它是否与我们的秘密私钥匹配)。
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
url:
type: string
format: uri
token:
type: string
required:
- url
- token
3.接下来,responses
部分定义单个202
响应。202
表示“接受”以供进一步处理。
最重要的部分: 。在我们的例子中,keywordcallbacks
下的键是它们的名称。然后是标题 – 。此路径是运行时表达式。路径表示将从请求正文中提取并构建通知接收 URL。callbacksnotification'{$request.body#/url}?token={$request.body#/token}'
urltoken
客户端服务的 OpenAPI 规范
client.oas3.yaml
openapi: 3.0.0
paths:
/notify:
post:
summary: 'Receive notification about a parcel'
security:
- TokenSecurity: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/notification'
responses:
'200':
description: 'Notification successfully processed'
content:
text/plain:
examples:
ok:
value: 'ok'
components:
securitySchemes:
TokenSecurty:
type: apiKey
name: token
in: query
schemas:
parcelId:
type: string
pattern: '^[0-9]{16}$'
notification:
type: object
properties:
parcelId:
$ref: "#/components/schemas/parcelId"
status:
type: string
enum:
- pick-up
- in-transit
- delivered
required:
- parcelId
- status
我们的 API 规范定义了一个处理通知接收的端点。就这么简单!
让我们模拟
我们已经定义了物流服务 API 和我们的 API 的规范。现在是时候启动prism
实例并查看一些操作了。
下面的命令将为港口prism
的物流公司运行实例4010
。
prism mock -p 4010 logistics.oas3.yaml
现在请打开新的控制台并运行以下命令:
prism mock -p 4011 client.oas3.yaml
准备好?
curl -v -H'Content-type: application/json' -d'{ "url": "http://localhost:4011/notify", "token": "dontpeek" }' http://127.0.0.1:4010/tracking/7352110771638879/subscribe
以下是物流服务的输出:
[CLI] … awaiting Starting Prism…
[HTTP SERVER] info Server listening at http://127.0.0.1:4010
[CLI] info POST http://127.0.0.1:4010/tracking/7352110771638879/subscribe
[HTTP SERVER] post /tracking/7352110771638879/subscribe info Request received
[NEGOTIATOR] info Request contains an accept header: */*
[VALIDATOR] success The request passed the validation rules. Looking for the best response
[NEGOTIATOR] success Found a compatible content for */*
[NEGOTIATOR] success Responding with the requested status code 202
[CALLBACK] info notification: Making request to http://localhost:4011/notify?token=dontpeek...
[CALLBACK] info notification: Request finished
以及客户端服务控制台相应的输出:
[CLI] … awaiting Starting Prism…
[HTTP SERVER] info Server listening at http://127.0.0.1:4011
[CLI] info POST http://127.0.0.1:4011/notify
[HTTP SERVER] post /notify info Request received
[NEGOTIATOR] info Request contains an accept header: */*
[VALIDATOR] success The request passed the validation rules. Looking for the best response
[NEGOTIATOR] success Found a compatible content for */*
[NEGOTIATOR] success Responding with the requested status code 200
哇哦!发生什么事了?
- 请求
POST
已提出http://127.0.0.1:4010/tracking/7352110771638879/subscribe
- Prism 回复
202
表示订阅已被接受。 - 请求体包含回调URL和token
- 回调定义包含有关如何构造 WebHook URL 的配方,这将导致
http://localhost:4011/notify?token=dontpeek
- 发生 Parcel 事件,触发通知请求
/notify
Prism使用模拟有效负载向我们的端点执行请求- 客户端控制台显示已收到通知
对于那些喜欢图表的人来说,这里有一个序列图。它展示了订阅回调和接收三个通知的过程。
恭喜,您刚刚模拟了两个服务并强制它们相互通信。本教程到此结束!
那很好,但是我为什么需要 Prism?
测试回调可能会变得很复杂。你可能需要编写一些小工具来模拟调用者服务。或者用curl “手动”调用它。或者强制服务调用你的 API 并相信它确实会这样做。
听起来还挺简单的?现在想象一下你的 API 会随着时间而改变。你需要维护该工具,但你丢失了curl命令,而且没有关于如何快速测试 API 的文档。哦,多么熟悉啊!
但是,等一下,您有一个始终保持最新的 OpenAPI 规范(因为您的老板告诉您这样做),并且 Prism 可以将其变成 API 任何部分的功能齐全的模仿。现在您既不需要秘密命令,也不需要非文档化的工具。