你真的瞭解RESTful API嗎?

前不久,在網上看到一個段子,一個碼農去面試,面試官問什麼是RESTful API,這看似一個很簡單的常識問題,碼農卻啞巴了。下面來看一下他們的對話:

面試官:瞭解RESTful嗎?
我:聽說過。
面試官:那什麼是RESTful?
我:就是用起來很規範,挺好的
面試官:是RESTful挺好的,還是自我感覺挺好的
我:都挺好的。
面試官:... 把門關上。
我:.... 要幹嘛?先關上再說。
面試官:我說出去把門關上。
我:what ?,奪門而去

    是的,如果沒有去細細的研究,問我我估計也會這麼講,那究竟什麼是RESTful API,它有哪些規範呢?

    概述

    在沒有前後端分離概念之前,一個網站的完成總是“all in one”,在這個階段,頁面、數據、渲染全部在服務端完成,這樣做的最大的弊端是後期維護,擴展極其痛苦,開發人員必須同時具備前後端知識。
    於是後來慢慢的興起了前後端分離的思想:即後端負責數據編造,而前端則負責數據渲染,前端靜態頁面調用指定api獲取到有固定格式的數據,再將數據展示出來,這樣呈現給用戶的就是一個”動態“的過程。

    而關於api這部分的設計則成了一個問題。如何設計出一個便於理解,容易使用的api則成了一個問題,而所謂的RESTful就是用來規範我們的API的一種約束。

    作爲REST,其實是Representational State Transfer(表象層狀態轉變)三個單詞的縮寫,它由Roy Fielding於2000年論文中提出,它代表着分佈式服務的架構風格。

    要深刻理解消化Representational State Transfer這三個單詞到底意味着什麼,可以從以下幾個方面進行理解:
    1.每一個URI代表一種資源;
    2.客戶端和服務器之間,傳遞這種資源的某種表現層;
    3.客戶端通過四個HTTP動詞(get、post、put、delete),對服務器端資源進行操作,實現”表現層狀態轉化”。

    RESTful6大原則

    REST之父Roy Fielding在論文中闡述REST架構的6大基本原則,它們分別是:

    1. C-S架構

    數據的存儲在Server端,Client端只需使用就行。兩端徹底分離的好處使client端代碼的可移植性變強,Server端的拓展性變強。兩端單獨開發,互不干擾。

    2. 無狀態

    http請求本身就是無狀態的,基於C-S架構,客戶端的每一次請求帶有充分的信息能夠讓服務端識別。請求所需的一些信息都包含在URL的查詢參數、header、div,服務端能夠根據請求的各種參數,無需保存客戶端的狀態,將響應正確返回給客戶端。無狀態的特徵大大提高的服務端的健壯性和可拓展性。

    當然,這種無狀態性的約束也是有缺點的,客戶端的每一次請求都必須帶上相同重複的信息確定自己的身份和狀態,造成傳輸數據的冗餘性,但這種確定對於性能和使用來說,幾乎是忽略不計的。

    3.統一的接口

    REST架構的核心內容,統一的接口對於RESTful服務非常重要。客戶端只需要關注實現接口就可以,接口的可讀性加強,使用人員方便調用。

    REST接口約束定義爲:資源識別; 請求動作; 響應信息; 它表示通過uri標出你要操作的資源,通過請求動作(http method)標識要執行的操作,通過返回的狀態碼來表示這次請求的執行結果。

    4.一致的數據格式

    服務端返回的數據格式要麼是XML,要麼是Json(獲取數據),或者直接返回狀態碼,一些知名網站的開放平臺的操作數據的api,post、put、patch都是返回的一個狀態碼 。

    如請求一條微博信息,服務端響應信息應該包含這條微博相關的其他URL,客戶端可以進一步利用這些URL發起請求獲取感興趣的信息,再如分頁可以從第一頁的返回數據中獲取下一頁的URT也是基於這個原理。

    5.可緩存

    在萬維網上,客戶端可以緩存頁面的響應內容。因此響應都應隱式或顯式的定義爲可緩存的,若不可緩存則要避免客戶端在多次請求後用舊數據或髒數據來響應。管理得當的緩存會部分地或完全地除去客戶端和服務端之間的交互,進一步改善性能和延展性。

    6.按需編碼、可定製代碼

    服務端可選擇臨時給客戶端下發一些功能代碼讓客戶端來執行,從而定製和擴展客戶端的某些功能。比如服務端可以返回一些 Javascript 代碼讓客戶端執行,去實現某些特定的功能。提示:REST架構中的設計準則中,只有按需編碼爲可選項。如果某個服務違反了其他任意一項準則,嚴格意思上不能稱之爲RESTful風格。

    最佳示例

    1. 版本控制

    如github開放平臺的API:http://developer.github.com/v3/
    可以發現,一般的項目加版本v1,v2,v3版本號,爲的是兼容一些老版本的接口,這個加版本估計只有大公司大項目纔會去使用。

    2.參數命名規範

    query parameter可以採用駝峯命名法,也可以採用下劃線命名的方式,推薦採用下劃線命名的方式,據說後者比前者的識別度要高,其中,做前端開發基本都後後者,而做服務器接口開發基本用前者。

    http://example.com/api/users/today_login 獲取今天登陸的用戶
    http://example.com/api/users/today_login&sort=login_desc 獲取今天登陸的用戶、登陸時間降序排列
    

      3.url命名規範

      API 命名應該採用約定俗成的方式,保持簡潔明瞭。在RESTful架構中,每個url代表一種資源,所以url中不能有動詞,只能有名詞,並且名詞中也應該使用複數。實現者應使用相應的Http動詞GET、POST、PUT、PATCH、DELETE、HEAD來操作這些資源即可

      不規範的的url,冗餘沒有意義,形式不固定,不同的開發者還需要了解文檔才能調用。

      http://example.com/api/getallUsers       //GET 獲取所有用戶
      http://example.com/api/getuser/1          //GET 獲取標識爲1用戶信息
      http://example.com/api/user/delete/1    //GET/POST 刪除標識爲1用戶信息
      http://example.com/api/updateUser/1   //POST 更新標識爲1用戶信息
      http://example.com/api/User/add         //POST添加新的用戶
      

        規範後的RESTful風格的url,形式固定,可讀性強,根據users名詞和http動詞就可以操作這些資源。

        http://example.com/api/users               //GET 獲取所有用戶信息
        http://example.com/api/users/1           //GET 獲取標識爲1用戶信息
        http://example.com/api/users/1          //DELETE 刪除標識爲1用戶信息
        http://example.com/api/users/1         //Patch 更新標識爲1用戶部分信息,包含在div中
        http://example.com/api/users           //POST 添加新的用戶
        

          4,統一返回數據格式

          對於合法的請求應該返回統一的數據格式,對於返回數據,通常會包含如下字段。

          • code——包含一個整數類型的HTTP響應狀態碼。
          • status——包含文本:”success”,”fail”或”error”。HTTP狀態響應碼在500-599之間爲”fail”,在400-499之間爲”error”,其它均爲”success”(例如:響應狀態碼爲1XX、2XX和3XX)。這個根據實際情況其實是可要可不要的。
          • message——當狀態值爲”fail”和”error”時有效,用於顯示錯誤信息。參照國際化(il8n)標準,它可以包含信息號或者編碼,可以只包含其中一個,或者同時包含並用分隔符隔開。
          • data——包含響應的div。當狀態值爲”fail”或”error”時,data僅包含錯誤原因或異常名稱、或者null也是可以的。

          例如,返回成功的響應json格式:

          {
            "code": 200,
            "message": "success",
            "data": {
              "userName": "123456",
              "age": 16,
              "address": "beijing"
            }
          }
          

            返回失敗的響應json格式:

            {
              "code": 401,
              "message": "error  message",
              "data": null
            }
            

              5. http狀態碼

              HTTP狀態碼也是有規律的:

              1,請求未成功
              2,請求成功、表示成功處理了請求的狀態代碼。
              3,請求被重定向、表示要完成請求,需要進一步操作。通常,這些狀態代碼用來重定向。
              4, 請求錯誤這些狀態代碼表示請求可能出錯,妨礙了服務器的處理。
              5,(服務器錯誤)這些狀態代碼表示服務器在嘗試處理請求時發生內部錯誤。這些錯誤可能是服務器本身的錯誤,而不是請求出錯。

              6. 合理使用query parameter

              在請求數據時,客戶端經常會對數據進行過濾和分頁等要求,而這些參數推薦採用HTTP Query Parameter的方式實現。

              //比如設計一個最近登陸的所有用戶
              http://example.com/api/users?recently_login_day=3
              

              //搜索用戶,並按照註冊時間降序
              http://example.com/api/users?recently_login_day=3

              //搜索用戶,並按照註冊時間升序、活躍度降序
              http://example.com/api/users?q=key&sort=create_title_asc,liveness_desc

                7. 多表、多參數連接查詢設計URL

                在做單個實體的查詢比較容易和規範操作,但是在實際的API並不是這麼簡單而已,因爲常常會設計到多表連接、多條件篩選、排序等。

                比如我想查詢一個獲取在6月份的訂單中大於500元的且用戶地址是北京,用戶年齡在22歲到40歲、購買金額降序排列的訂單列表,那麼接口可能如下:

                http://example.com/api/orders?order_month=6&order_amount_greater=500&address_city=北京&sort=order_amount_desc&age_min=22&age_max=40
                

                  從這個URL上看,參數衆多、調用起來還得一個一個仔細對着,而且API本身非常不容易維護,命名看起來不是很容易,不能太長,也不能太隨意。

                  在.net WebAPI中,我們可以使用屬性路由,屬性路由就是將路由附加到特定的控制器或操作方法上裝飾Controll及其使用[Route]屬性,一種定義路由的方法稱爲屬性路由。

                  這種好處就是可以精準地控制URL,而不是基於約定的路由,簡直就是爲這種多表查詢量身定製似的的。從webapi 2開發,現在是RESTful API開發中最推薦的路由類型。

                  [Route(“api/orders/{address}/{month}”)]
                  

                    而Action中的查詢參數就只有金額、排序、年齡。減少了查詢參數、API的可讀性和可維護行增強了。

                    http://example.com/api/orders/beijing/6?order_amount_greater=500&sort=order_amount_desc&age_min=22&age_max=40
                    

                      所以,在向別人介紹rest的時候,首先需要介紹服務背景,然後再介紹它的一些約束規則,切不可籠統介紹。

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