構建 REST API 時,要采取的第一步是確定 API 將管理的資源。通常將這些資源描述為復數名詞,如customers
、events
、 或transactions
。在 Web 服務中標識不同的資源時,您將構建一個名詞列表,用於描述用戶可以在 API 中管理的不同數據。
執行此操作時,請確保考慮任何嵌套資源。例如,customers
可能具有guests
或sales
可能包含events
。在定義 API 接口時,建立這些資源層次結構將很有幫助。
確定 Web 服務中的資源後,需要使用這些資源來定義 API 接口。以下是您可能在支付處理服務的 API 中找到的資源的一些示例接口:transactions
GET
/transactions
獲取交易列表。GET
/transactions/<transaction_id>
獲取單個事務。POST
/transactions
創建新事務。PUT
/transactions/<transaction_id>
更新交易。PATCH
/transactions/<transaction_id>
部分更新事務。DELETE
/transactions/<transaction_id>
刪除交易記錄。這六個節點涵蓋了在 Web 服務中transactions
創建、讀取、更新和刪除所需的所有操作。Web 服務中的每個資源都將具有類似的節點列表,具體取決於用戶可以使用 API 執行的操作。
注意: 節點不應包含謂詞。相反,您應該選擇適當的 HTTP 方法來傳達終結點的操作。例如,下面的終結點包含一個不需要的謂詞:
GET /getTransactions
此處,get
在不需要包含在接口中。HTTP 方法已通過指示操作為終結點提供語義含義。您可以從接口中刪除:GET
GET /transactions
此接口僅包含一個復數名詞,HTTP GET
方法傳達操作。
現在看一下嵌套資源的接口示例。在這裡,你將看到guests
嵌套在資源events
下的接口:
GET
/events/<event_id>/guests
獲取來賓列表。GET
/events/<event_id>/guests/<guest_id>
獲取單個來賓。POST
/events/<event_id>/guests
創建新的來賓。PUT
/events/<event_id>/guests/<guest_id>
更新來賓。PATCH
/events/<event_id>/guests/<guest_id>
部分更新來賓。DELETE
/events/<event_id>/guests/<guest_id>
刪除來賓。使用這些接口,可以管理系統中的特定事件。guests
這不是為嵌套資源定義接口的唯一方法。有些人更喜歡使用查詢字符串來訪問嵌套資源。查詢字符串允許您隨 HTTP 請求一起發送其他參數。在以下接口中,追加查詢字符串guests
以獲取特定event_id
:
GET /guests?event_id=23
此節點guests
將篩選出任何未引用給定event_id
.與 API 設計中的許多事情一樣,您需要確定哪種方法最適合您的 Web 服務。
注意: REST API 不太可能在 Web 服務的整個生命周期中保持不變。資源將發生更改,您需要更新接口節點以反映這些更改。這就是 API 版本控制的用武之地。API 版本控制允許您修改 API,而不必擔心破壞現有集成。
有各種各樣的版本控制策略。選擇正確的選項取決於 API 的要求。以下是一些最受歡迎的 API 版本控制選項:
無論您選擇哪種策略,對 API 進行版本控制都是確保其能夠適應不斷變化的需求同時支持現有用戶的重要步驟。
用於格式化 Web 服務數據的兩個常用選項是 XML 和 JSON。傳統上,XML在[SOAP] API中非常流行,但JSON在REST API中更受歡迎。若要比較兩者,請看一個格式化為 XML 和 JSON 的示例資源book
。
下面是一本格式化為 XML 的書:
<?xml version="1.0" encoding="UTF-8" ?>
<book>
<title>Python Basics</title>
<page_count>635</page_count>
<pub_date>2021-03-16</pub_date>
<authors>
<author>
<name>David Amos</name>
</author>
<author>
<name>Joanna Jablonski</name>
</author>
<author>
<name>Dan Bader</name>
</author>
<author>
<name>Fletcher Heisler</name>
</author>
</authors>
<isbn13>978-1775093329</isbn13>
<genre>Education</genre>
</book>
XML 使用一系列元素對數據進行編碼。每個元素都有一個開始和結束標記,數據介於兩者之間。元素可以嵌套在其他元素中。您可以在上面看到這一點,其中幾個標記嵌套在 .<author>``<authors>
現在,看看JSON中的相同內容:book
{
"title": "Python Basics",
"page_count": 635,
"pub_date": "2021-03-16",
"authors": [
{
"name": "David Amos"},
{
"name": "Joanna Jablonski"},
{
"name": "Dan Bader"},
{
"name": "Fletcher Heisler"}
],
"isbn13": "978-1775093329",
"genre": "Education"
}
JSON將數據存儲在類似於Python字典的鍵值對中。與 XML 一樣,JSON 支持將數據嵌套到任何級別,因此您可以對復雜數據進行建模。
JSON和XML本質上都不比另一個更好,但REST API開發人員更喜歡JSON。當
您將 REST API 與 React
或 Vue
等前端框架配對時,尤其如此。
選擇數據格式後,下一步是確定如何響應 HTTP 請求。來自 REST API 的所有響應都應具有類似的格式,並包含正確的 HTTP 狀態代碼。
在本節中,您將查看管理cars
清單 的假設 API 的一些示例 HTTP 響應。這些示例將讓您了解應如何設置 API 響應的格式。為了清楚起見,您將查看原始HTTP請求和響應,而不是使用像.requests
要開始操作,請查看GET
對 /cars
的請求,其中返回以下列表:
GET /cars HTTP/1.1
Host: api.example.com
此 HTTP 請求由四部分組成:
GET
是 HTTP 方法類型。/cars
是 API 接口。HTTP/1.1
是 HTTP 版本。主機:api.example.com
是 API 主機。這四個部分是您向/cars
發送GET
請求所需的全部內容。現在來看看響應。此 API 使用 JSON 作為數據交換格式:
HTTP/1.1 200 OK
Content-Type: application/json
...
[
{
"id": 1,
"make": "GMC",
"model": "1500 Club Coupe",
"year": 1998,
"vin": "1D7RV1GTXAS806941",
"color": "Red"
},
{
"id": 2,
"make": "Lamborghini",
"model":"Gallardo",
"year":2006,
"vin":"JN1BY1PR0FM736887",
"color":"Mauve"
},
{
"id": 3,
"make": "Chevrolet",
"model":"Monte Carlo",
"year":1996,
"vin":"1G4HP54K714224234",
"color":"Violet"
}
]
該 API 返回一個響應,其中包含cars
的列表。您知道由於狀態代碼200 OK
的原因,響應成功。響應的標頭Content-Type
還設置為application/json
。這告訴用戶將響應解析為 JSON。
注意: 當您使用真正的API時,您將看到比這更多的HTTP標頭。這些標頭在 API 之間有所不同,因此在這些示例中已排除它們。
請務必始終在響應上設置正確的標頭Content-Type
。如果發送 JSON,Content-Type
則設置為application/json
。如果為 XML,則將其設置為 application/xml
。此標頭告訴用戶應如何分析數據。
您還希望在響應中包含適當的狀態代碼。對於任何成功的請求,GET
應返回200 OK
。這告訴用戶其請求已按預期處理。
看看另一個GET
請求,這次是針對一輛車:
GET /cars/1 HTTP/1.1
Host: api.example.com
此 HTTP 請求查詢汽車1
的 API。以下是響應:
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 1,
"make": "GMC",
"model": "1500 Club Coupe",
"year": 1998,
"vin": "1D7RV1GTXAS806941",
"color": "Red"
},
此響應包含帶有汽車數據的單個 JSON 對象。由於它是單個對象,因此不需要將其包裝在列表中。與上一個響應一樣,這也有一個狀態代碼。200 OK
注意: 請求永遠不應修改現有資源。如果請求包含數據,則應忽略此數據,並且 API 應返回未更改的資源。GET
接下來,查看添加新車的請求:POST
POST /cars HTTP/1.1
Host: api.example.com
Content-Type: application/json
{
"make": "Nissan",
"model": "240SX",
"year": 1994,
"vin": "1N6AD0CU5AC961553",
"color": "Violet"
}
此POST
請求在請求中包含新車的 JSON。它將標頭Content-Type
設置為application/json
以便 API 知道請求的內容類型。API 將從 JSON 創建新汽車。
以下是響應:
HTTP/1.1 201 Created
Content-Type: application/json
{
"id": 4,
"make": "Nissan",
"model": "240SX",
"year": 1994,
"vin": "1N6AD0CU5AC961553",
"color": "Violet"
}
此響應具有狀態代碼200 OK
,201 Created
用於告知用戶已創建新資源。201 Created
確保對所有成功的請求使用 而不是POST
。
此響應還包括新車的副本id
,其中包含由 API 生成的id
請務必在響應中發回 a,以便用戶可以再次修改資源。
注意: 當用戶使用 POST
或PUT
或PATCH
修改資源時,始終發回資源的副本非常重要。這樣,用戶就可以看到他們所做的更改。
現在看一下請求:PUT
PUT /cars/4 HTTP/1.1
Host: api.example.com
Content-Type: application/json
{
"make": "Buick",
"model": "Lucerne",
"year": 2006,
"vin": "4T1BF3EK8AU335094",
"color":"Maroon"
}
此請求使用上一個請求中的id
使用PUT
所有新數據更新汽車。提醒一下,請使用新數據更新資源上的所有字段。以下是響應:
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 4,
"make": "Buick",
"model": "Lucerne",
"year": 2006,
"vin": "4T1BF3EK8AU335094",
"color":"Maroon"
}
響應包括具有新數據的car
的副本。同樣,您始終希望PUT
發回請求的完整資源。這同樣適用於PATCH
請求:
PATCH /cars/4 HTTP/1.1
Host: api.example.com
Content-Type: application/json
{
"vin": "VNKKTUD32FA050307",
"color": "Green"
}
PATCH
請求僅更新資源的一部分。在上面的請求中,vin
和color
字段將使用新值進行更新。以下是響應:
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 4,
"make": "Buick",
"model": "Lucerne",
"year": 2006,
"vin": "VNKKTUD32FA050307",
"color": "Green"
}
響應包含 car
的完整副本。如您所見,只有vin
和color
字段已更新。
最後,看看 REST API 在收到DELETE
請求時應如何響應。下面是刪除 :
HTTP/1.1 204 No Content
此響應僅包括狀態代碼 。此狀態代碼204 No Content
告訴用戶操作成功,但響應中未返回任何內容。這是有道理的,因為car
已被刪除。沒有理由在響應中將其副本發送回去。
對 REST API 的請求總是有可能失敗。最好定義錯誤響應的外觀。這些響應應包括所發生錯誤的說明以及相應的狀態代碼。在本節中,您將看幾個示例。
首先,請查看對 API 中不存在的資源的請求:
GET /motorcycles HTTP/1.1
Host: api.example.com
此處,用戶向/motorcycles
發送不存在的請求。API 會發回以下響應:
HTTP/1.1 404 Not Found
Content-Type: application/json
...
{
"error": "The requested resource was not found."
}
此響應包括狀態代碼。除此之外,響應還包含一個帶有描述性錯誤消息的 JSON 對象。提供描述性錯誤消息可為用戶提供有關錯誤的更多上下文。
現在看一下用戶發送無效請求時的錯誤響應:
POST /cars HTTP/1.1
Host: api.example.com
Content-Type: application/json
{
"make": "Nissan",
"year": 1994,
"color": "Violet"
此POST
請求包含 JSON,但格式不正確。它缺少末尾的右大括號 (}
)。API 將無法處理此數據。錯誤響應會告知用戶以下問題:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "This request was not properly formatted. Please send again."
}
此響應包括一條描述性錯誤消息以及狀態代碼,告知用戶他們需要修復請求。
還有其他幾種方式,即使請求的格式正確,也可能是錯誤的。在下一個示例中,用戶發送請求,但包含不受支持的媒體類型:POST
POST /cars HTTP/1.1
Host: api.example.com
Content-Type: application/xml
<?xml version="1.0" encoding="UTF-8" ?>
<car>
<make>Nissan</make>
<model>240SX</model>
<year>1994</year>
<vin>1N6AD0CU5AC961553</vin>
<color>Violet</color>
</car>
在此請求中,用戶發送 XML,但 API 僅支持 JSON。該 API 的響應方式如下:
HTTP/1.1 415 Unsupported Media Type
Content-Type: application/json
{
"error": "The application/xml mediatype is not supported."
}
此響應包括狀態代碼,以指示請求包含 API 不支持的數據格式。此錯誤代碼對於格式錯誤的數據有意義,但是即使格式正確也無效的數據呢?
在下一個示例中,用戶發送請求,但包含的數據與其他數據的字段不匹配:
POST /cars HTTP/1.1
Host: api.example.com
Content-Type: application/json
{
"make": "Nissan",
"model": "240SX",
"topSpeed": 120
"warrantyLength": 10
}
在此請求中,用戶向 JSON 添加topSpeed
和warrantyLength
字段。API 不支持這些字段,因此它會以錯誤消息進行響應:
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
{
"error": "Request had invalid or missing data."
}
此響應包括狀態代碼。此狀態代碼表示請求沒有任何問題,但數據無效。REST API 需要驗證傳入的數據。如果用戶隨請求一起發送數據,則 API 應驗證數據並通知用戶任何錯誤。
響應請求(無論是成功的還是錯誤的)是 REST API 最重要的工作之一。如果您的 API 直觀且提供准確的響應,則用戶將更容易圍繞您的 Web 服務構建應用程序。幸運的是,一些優秀的Python Web框架抽象出了處理HTTP請求和返回響應的復雜性。
這兩年被Python初學小白問到最多的問題就是,該用什麼代碼