Skip to content

Latest commit

 

History

History
213 lines (150 loc) · 20.5 KB

rest.md

File metadata and controls

213 lines (150 loc) · 20.5 KB

REST (REpresentational State Transfer)

  • REST = REpresentational State Transfer。
  • REST 的命名是為了喚起 well-behaved web application 應有的樣子 - web application 是一個由 a network of web resources 組成的 virtual state-machine,對某個 resource 的存取/操作 (內部發生 state transition),會導致把 next state 的 representation 移轉 (transfer) 給使用者。
  • REST 是一種 architectural style 而非 standard,提出了 6 點架構上的要求 (architectural constraints) - client-server architecture、statelessness、cacheability、layered system、code on demand (optional) 與 uniform interface,設計上符合 REST architecture constraints 的 web service API 就稱做 RESTful API,而 HTTP-based RESTful API 只是其種一種實現方式。

參考資料:

RESTful API 跟 user-friendly URL 的關係?

可供測試的 RESTful APIs ??

如何規劃 RESTful API 的 URL?

  • Best Practices for Designing a Pragmatic RESTful API | Vinay Sahni #ril

    • 當背後的 data model 已經趨於穩定,想要透過 public API 公開,但 API 一旦公佈之後就很難改動,希望在釋出前就儘量做對。
    • 網路上不乏許多意見,但沒有真正的標準,問題在於選擇太多 ... 如何做 authentication? 要不要做 versioning ... My goal with this post is to describe best practices for a pragmatic API designed for today's web applications. I make no attempt to satisfy a standard if it doesn't FEEL RIGHT. 跟著直覺走,其中以 "It should be friendly to the developer and be explorable via a browser address bar" 的考量最重要 => An API is a developer's UI - just like any UI, it's important to ensure the user's experience is thought out carefully! 關於 browser explorability,在 JSON only responses 一節有句話 "To ensure browser explorability, it should be in the URL." 這說法簡單易懂。
    • The key principles of REST involve separating your API into LOGICAL RESOURCES. These resources are manipulated using HTTP requests where the method (GET, POST, PUT, PATCH, DELETE) has specific meaning.
    • 要如何定義 resource? these should be NOUNS (not verbs!) that make sense from the perspective of the API consumer. Although your internal models may map neatly to resources, it isn't necessarily a ONE-TO-ONE MAPPING. The key here is to not LEAK irrelevant implementation details out to your API! 名詞,從 API consumer 的角度來看,且不一定要跟後端的 data model 有 one-to-one 的對應關係,注意不要洩漏了後端的實作細節。
    • 找出 resource 後,接下來要找出有哪些 action 可以作用在該 resource、如何對應到 API 的操作。RESTful principles 提供了 CRUD action 與 HTTP methods 的對應 (以 ticket 為例):GET /tickets (取得 list of tickets)、GET /tickets/12 (取得特定 ticket)、POST /tickets (建立一個 ticket,注意仍有 s)、PUT /tickets/12 (更新 ticket)、PATCH /tickets/12 (局部更新 ticket)、DELETE /tickets/12 (刪除 ticket) -- 利用現有的 HTTP methods,將重要的功能集中在 /tickets 同一個 endpoint 下。
  • API Design – 7 Important Lessons When Designing an API (2017-11-02) #ril

  • The Entire API Lifecycle | Nordic APIs (2015-10-13) #ril

  • Simple rules for a sane RESTful API design (Example) (2017-03-30) #ril

  • RESTful API Designing guidelines — The best practices (2017-02-03) #ril

  • RESTful and User-Friendly URLs #ril

  • 10 Best Practices for Better RESTful API | Thinking Mobile (2014-06-05) #ril

  • URL Design for RESTful Web Services | API UX 在講 API 的 UX #ril

  • Semantic URL - Wikipedia https://en.wikipedia.org/wiki/Semantic_URL #ril

之前 Wonder 提到 GCP 的 translation restful API,發現也是有人不用 namespace 的,且 hostname 也是看用途的命名 https://cloud.google.com/translate/docs/reference/translate

  • translation.googleapis.com/language/translate/v2
  • translation.googleapis.com/language/translate/v2/detect
  • translation.googleapis.com/language/translate/v2/languages

Resource ??

Relationship ??

Singular / Plural ??

CRUD 以外的操作,例如 Search、Activate、Star/Unstar ??

  • What about actions that don't fit into the world of CRUD operations? - Best Practices for Designing a Pragmatic RESTful API | Vinay Sahni 做法有很多種
    • Restructure the action to appear like a field of a resource. 尤其 action 不帶其他參數時,例如 activate 的動作,可以對應 activated 欄位,透過 PATCH method 做 partial update。
    • Treat it like a sub-resource with RESTful principles. 像 GitHub 的 star/unstar 分別用 PUT /gists/:id/starDELETE /gists/:id/star 表現。
    • Sometimes you really have no way to map the action to a sensible RESTful structure. For example, a multi-resource search doesn't really make sense to be applied to a SPECIFIC resource's endpoint. 這種狀況下就用 /search 也沒關係,即便它不是個 resource -- 重點還是 "right from the perspective of the API consumer"

Filtering/Searching, Sorting, Pagination ??

  • Result filtering, sorting & searching - Best Practices for Designing a Pragmatic RESTful API | Vinay Sahni
    • It's best to keep the base resource URLs as lean as possible. 其他像是 result filtering、sorting、searching 等,建議在 base URL 的基礎上用 query parameters 來實作。
    • Use a unique query parameter for each field that implements filtering. 例如 GET /tickets?state=open 可以針對 state 過濾。
    • Similar to filtering, a generic parameter sort can be used to describe sorting rules. 例如 GET /tickets?sort=-priority (用 - 來表示 descending),複雜的排序則可以用逗號隔開多個欄位,例如 GET /tickets?sort=-priority,created_at
    • Sometimes basic filters aren't enough and you need the power of FULL TEXT SEARCH. 也就是說 filtering 也是一種 search,可以用 q query parameter 來表示,例如 GET /tickets?q=return&state=open&sort=-priority,created_at
    • To make the API experience more pleasant for the average consumer, consider packaging up sets of conditions into easily accessible RESTful paths. 這個考量還滿特別的 (alias 的概念),例如 GET /tickets/recently_closed
  • Pagination - Best Practices for Designing a Pragmatic RESTful API | Vinay Sahni #ril

Response -- Format, Status Code ??

Partial Response ??

Throttling ??

Caching ??

Documentation ??

  • 常用的工具有 API BlueprintSwaggerRAML
  • API Blueprint 支持 Markdown 似乎不錯?
  • 從 code 來產生 API 文件,在實務上會有什麼問題嗎?
  • 是否該考量 OpenAPI 的標準?

參考資料:

Errors ??

  • Errors - Best Practices for Designing a Pragmatic RESTful API | Vinay Sahni

    • Just like an HTML error page shows a useful error message to a visitor, an API should provide a USEFUL error message in a KNOWN CONSUMABLE FORMAT. The representation of an error should be NO DIFFERENT than the representation of any resource, just with ITS OWN SET of fields.

      這跟 API 的 UX 有關。

    • The API should always return sensible HTTP status codes. API errors typically break down into 2 types: 400 series status codes for client issues & 500 series status codes for server issues.

      At a minimum, the API should standardize that all 400 series errors come with consumable JSON error representation. If possible (i.e. if load balancers & reverse proxies can create custom error bodies), this should EXTEND to 500 series status codes.

    • A JSON error body should provide a few things for the developer - a useful error message, a unique error code (that can be looked up for more details IN THE DOCS) and possibly a detailed description. JSON output representation for something like this would look like:

      {
        "code" : 1234,
        "message" : "Something bad happened :(",
        "description" : "More details about the error here"
      }
      
    • Validation errors for PUT, PATCH and POST requests will need a FIELD BREAKDOWN. This is best modeled by using a fixed top-level error code for validation failures and providing the detailed errors in an additional errors field, like so:

      {
        "code" : 1024,
        "message" : "Validation Failed",
        "errors" : [
          {
            "code" : 5432,
            "field" : "first_name",
            "message" : "First name cannot have fancy characters"
          },
          {
             "code" : 5622,
             "field" : "password",
             "message" : "Password cannot be blank"
          }
        ]
      }
      

      這又更進一步,要一次提示多個欄位的問題;也跟 API UX 有關。

  • REST API Error Handling Best Practices (2015-12-10) 不要過度濫用 status code,用 200、400、500 應該就夠了。FB #ril

  • Documenting status and error codes | Document REST APIs #ril

Versioning??

  • /<version>/<endpoint>/<endpoint>/<version>,應該是前著,因為一個 version 下會怎麼拆分不同的 endpoints 會依 version 不同。

參考資料:

  • Versioning - Best Practices for Designing a Pragmatic RESTful API | Vinay Sahni
    • Always version your API. Versioning helps you ITERATE FASTER and prevents invalid requests from hitting updated endpoints. 避免卡到自己。
    • An API is never going to be completely stable. Change is inevitable. What's important is how that change is MANAGED.
    • 但 version 應該放 header 還是 URL? 學術上認為要放 header,但基於 "be explorable via a browser address bar" 的考量,選擇放 URL。
    • 作者很喜歡 Stripe 在 API versioning 這方面的做法 -- URL 只有 major version (例如 /v1/),但發生 backwards-incompatible changes 時,會釋出 dated version (例如 2018-07-27),平常 request 會採用 API settings 裡指定的 dated version,但也可以透過 Stripe-Version header 指定。
  • Versioning a REST API | Baeldung #ril

Tools

參考資料 {: #rerference }

社群:

更多: