REST API一對多,多對多調用設計

最近一直在思考Rest API的設計,普通的CRUD應用REST是比較簡單並且明確的,大多數搜索結果都有REST API的設計理念,概括來說就是URL代表資源,HTTP Method代表要做什麼事情,HTTP response status code代表做事情的結果,如:
Get /users/2
Response 404

代表了請求ID爲2的User,返回了404代表資源沒有找到。

https://www.zhihu.com/question/28570307 最高票回答也解決了一些在設計rest API涉及的問題,例如某些動詞很難去名詞化,這要涉及到業務的抽象,詞性的轉換。另外比如像search這種有兩種詞性的,其實設計的時候已經可以作爲URL的一部分了。這點在github API中已經有體現:
https://api.github.com/
"repository_search_url": "https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}",


類似login這種,雖然有提到是在操作session,但是在實際應用中,一般就非rest的處理了,用/login作爲endpoint,大家看起來也不會認爲有很大的問題。

在業務系統中會遇到更加複雜的問題,其中包括
[list]
[*]1. 一對多,多對多的rest API設計,包括創建,更新
[*]2. 雙向綁定的循環序列化問題。
[/list]

這裏先記錄一下我看到的針對1這個問題的處理。

一般來說,這種關聯分兩種情況:
[list]
[*]一種情況是多方的實體不能脫離單方的實體存在,或者多方的實體不會直接被獲取,舉例:
每個人都有多條教育記錄,而教育記錄一般不需要直接使用,都是從個人爲起點獲取的。URL如下:
GET /persons/{PERSON_ID}/edu-histories


[*]另外一種情況是多方實體和單方實體都是獨立存在的,然而他們之間是有關聯的。比如訂單和商品,這時候就需要多個API了。
獲取單個訂單 GET /orders/{order_id}
獲取單個商品 GET /products/{product_id}
獲取某個訂單的所有商品 GET /orders/{order_id}/products
獲取某個商品關聯的所有訂單 GET /products/{product_id}/orders

創建這種關聯可以用POST/PUT/PATCH去實現,在body中加入被關聯實體即可。具體實現在stackoverflow也有討論應該用哪個method更符合規範,大家都比較提PATCH,實際應用中可以針對自己的web server支持不支持PATCH來做調整。

在這種情況下,實體儘量單獨返回,不要返回關聯實體,例如獲取order,不會直接把關聯的product返回來。這樣造成的一個缺陷就是,需要client端調用多次才能返回所有的結果。
[/list]


這種缺陷其實是RestAPI原本設計理念的第三層 -- hateoas 所提及的,即,每個restAPI發回的結果可能不僅僅是當前的一個結果,它還應當包含對其他相關對象引用的link,就像我們去訪問一個網址,網址上不僅僅會返回給我們內容,還會給我們提供其他相關的超級鏈接一樣。 只有完成了Hateoas才能算是真正的Restful。

另外一種實現是把這種關聯認爲是一類資源,URL直接用relationship表示:
GET /order-product-relationship
[{"orderId":1,"productId":2},{"orderId":1,"productId":3}]



待續
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章