回呼
在 OpenAPI 3 規格中,您可以定義回呼 – 您的服務將在回應特定事件時傳送給其他服務的非同步、頻外請求。這有助於您改善 API 提供給用戶端的運作流程。回呼的典型範例是訂閱功能 – 用戶訂閱您服務的某些事件,並在發生此事件或彼事件時收到通知。例如,電子商店可以在每次購買時向管理員傳送通知。這些通知將是「頻外」的,也就是說,它們將通過與訪客使用的連線不同的連線,並且它們將是非同步的,因為它們將脫離常規的請求-回應流程。在 OpenAPI 3 中,您可以定義「訂閱」操作的格式,以及回呼訊息的格式和這些訊息的預期回應。此描述將簡化不同伺服器之間的通訊,並協助您標準化 API 中 Webhook 的使用。
回呼範例
讓我們建立一個回呼定義 – 一個簡單的 Webhook 通知。假設您的 API 提供 POST /subscribe
操作,該操作預期請求主體中具有回呼 URL
1POST /subscribe2Host: my.example.com3Content-Type: application/json4
5{6 "callbackUrl": "https://myserver.com/send/callback/here"7}
API 確認訂閱 —
1HTTP/1.1 201 Created
— 然後在發生特定事件時傳送通知
1POST /send/callback/here2Host: myserver.com3Content-Type: application/json4
5{6 "message": "Something happened"7}
現在讓我們定義 /subscribe
操作
1openapi: 3.0.02info:3 version: 0.0.04 title: test5
6paths:7 /subscribe:8 post:9 summary: Subscribe to a webhook10 requestBody:11 required: true12 content:13 application/json:14 schema:15 type: object16 properties:17 callbackUrl: # Callback URL18 type: string19 format: uri20 example: https://myserver.com/send/callback/here21 required:22 - callbackUrl23 responses:24 "201":25 description: Webhook created
現在讓我們將回呼關鍵字新增至此操作以定義回呼
1paths:2 /subscribe:3 post:4 summary: Subscribe to a webhook5 requestBody: …6 callbacks: # Callback definition7 myEvent: # Event name8 "{$request.body#/callbackUrl}": # The callback URL,9 # Refers to the passed URL10 post:11 requestBody: # Contents of the callback message12 required: true13 content:14 application/json:15 schema:16 type: object17 properties:18 message:19 type: string20 example: Some event happened21 required:22 - message23 responses: # Expected responses to the callback message24 "200":25 description: Your server returns this code if it accepts the callback
讓我們逐行瀏覽此定義
callbacks
是在相關操作 -post
、put
等 (而不是在路徑本身下) 中定義的。在本範例中,是在/subscribe
路徑的post
方法下
1paths:2 /subscribe:3 post:4 …5 callbacks:6 …
這並不表示 API 僅在此操作運作時才會傳送回呼。您的 API 會在您服務的業務邏輯需要時傳送回呼請求。關鍵字層級結構只是讓您可以使用 /subscribe
操作的參數來設定回呼請求 (請參閱下方)。
- 在
callbacks
內,我們定義一或多個回呼訊息。在我們的範例中,我們只有一個訊息。您可以在下方找到具有多個回呼的範例。每個回呼的定義都以事件名稱 (_myEvent_
在我們的範例中) 開頭
1callbacks:2 myEvent: # Event name
- 在事件名稱下,我們定義您的服務將傳送回呼訊息的 URL。在我們的範例中,URL 是使用
{$request.body#/callbackUrl}
表達式指定的
1callbacks:2 myEvent:3 "{$request.body#/callbackUrl}": # The callback URL, refers to the URL passed in the request body
此表達式表示回呼 URL 將基於 /subscribe
操作的參數。我們稍後將詳細說明這些表達式。
- 在 URL 下方,我們指定回呼訊息的方法,並定義訊息格式和預期的回應。這些定義類似於常規請求和回應定義
1callbacks:2 myEvent:3 "{$request.body#/callbackUrl}":4 post: # Method5 requestBody: # Contents of the callback message6 …7 responses: # Expected responses8 …
請注意,當您定義回呼時,您是在定義 API 的規格。回呼功能的實際實作是在伺服器程式碼中完成的。
使用執行階段表達式參照請求欄位
如您所見,在我們的範例中,我們使用 {$request.body#/callbackUrl}
表達式。它是執行階段表達式,設定在回呼中將使用 POST /subscribe
請求的哪些資料。執行階段表示與 API 端點不同,此 URL 並非預先得知,而是根據 API 用戶端提供的資料在執行階段評估的。此值會因用戶端而異。例如,POST /subscribe
請求可以如下所示
1POST /subscribe?p1=query-param-value HTTP/1.12Host: my.example.com3Content-Type: application/json4Content-Length: 1875
6{7 "callbackUrl" : "http://my.client.com/callback"8}9
10201 Created11Location: http://my.example.com?id=123
您可以使用下列表達式來參照其資料
表達式 | 範例 | 描述 |
---|---|---|
{$url} | /subscribe | 父操作 URL。 |
{$method} | POST | 回呼請求的方法。 |
{$request.path.eventType} | myEvent | 事件名稱。 |
{$request.query.param-name} | query-param-value ( p1 查詢參數) | 指定查詢參數的值。 |
{$request.header.header-name} | application/json (Content-Type 標頭) | 「訂閱」請求的指定標頭。 |
{$request.body#/field-name} | callbackUrl | 請求主體中的欄位。如果欄位是陣列,請使用類似 {$request.body#/arrayField/2} 的語法。 |
{$response.header.header-name} | http://my.example.com?id=123 (Location 標頭) | 指定回應標頭的值(對「訂閱」請求的回應)。 |
您可以在回呼定義中結合執行階段表達式和靜態資料。例如,您可以用以下方式定義回呼 URL
1{$request.body#callbackUrl}/data:2– or –3{$request.body#/callbackUrl}/{$request.query.eventType}:
您可以使用表達式來指定查詢參數
1{$request.body#/callbackUrl}/data?p1={$request.query.eventType}
如果字串同時包含執行階段表達式和靜態文字,您應該將執行階段表達式括在大括號中。如果整個字串都是執行階段表達式,您可以省略大括號。
多個回呼
如上所述,您可以使用一個「訂閱」操作來定義多個回呼
1/subscribe:2 post:3 requestBody:4 content:5 application/json:6 schema:7 type: object8 properties:9 inProgressUrl:10 type: string11 failedUrl:12 type: string13 successUrl:14 type: string15 responses:16 "200":17 description: OK18 callbacks:19 inProgress:20 "{$request.body#/inProgressUrl}":21 post:22 requestBody:23 $ref: "#/components/requestBodies/callbackMessage1"24 responses:25 "200":26 description: OK27 "{$request.body#/failedUrl}":28 post:29 requestBody:30 $ref: "#/components/requestBodies/callbackMessage2"31 responses:32 "200":33 description: OK34 "{$request.body#/successUrl}":35 post:36 requestBody:37 $ref: "#/components/requestBodies/callbackMessage3"38 responses:39 "200":40 description: OK
取消訂閱回呼
您如何實作取消訂閱機制取決於您。例如,接收伺服器可以在回呼訊息的回應中返回特定代碼,以表示它不再對回呼感興趣。在這種情況下,客戶端只能在回應回呼請求時取消訂閱。為了讓客戶端可以隨時取消訂閱,您的 API 可以提供一個特殊的「取消訂閱」操作。這是一種相當常見的方法。在這種情況下,您的服務可以為每個訂閱者生成一個 ID 或權杖,並在對「訂閱」請求的回應中返回此 ID 或權杖。要取消訂閱,客戶端可以將此 ID 傳遞給「取消訂閱」操作,以指定要移除的訂閱者。以下範例示範如何在您的規範中定義此行為
1paths:2/subscribe:3 description: Add a subscriber4 post:5 parameters:6 - name: callbackUrl7 in: query8 required: true9 schema:10 type: string11 format: uri12 - name: event13 in: query14 required: true15 schema:16 type: string17 responses:18 '201':19 description: Added20 content:21 application/json:22 type: object23 properties:24 subscriberId:25 type: string26 example: AAA-123-BBB-45627 links: # Link the returned id with the unsubscribe operation28 unsubscribeOp:29 operationId: unsubscribeOperation30 parameters:31 Id: $response.body#/subscriberId32 callbacks:33 myEvent:34 '{$request.query.callbackUrl}?event={$request.query.event}':35 post:36 requestBody:37 content:38 application/json:39 example:40 message: Some event41 responses:42 '200':43 description: OK44
45/unsubscribe:46 post:47 operationId: unsubscribeOperation48 parameters:49 - name: Id50 in: query51 required: true52 schema:53 type: string