[Network] 03. Web API、URI 設計原則

 · 3 mins read

2021.07.27 增加寶典-URI 設計原則

ASP.NET Web API 是一種架構,可讓您更輕鬆建置 HTTP 服務並擴及各種用戶端,包括瀏覽器和行動裝置。 ASP.NET Web 應用程式開發介面是在 .NET Framework 上建置 RESTful 應用程式的理想平台。




URI 統一資源識別元 (Uniform Resource Identifiers,URI) 1

scheme:[//[user[:password]@]host[:port]][/path][?query][#fragment]
  • host:溝通系統的 resource,對 HTTP 而言就是 Web Server
  • port:Tcp port,一般HTTP使用80
  • query:Resource 或 Client 的額外資訊
  • fragment:Resource的 特定位置



  • URI 必須透過名稱解析服務 (ex: DNS),找到 Server (或 代理、閘道、負載平衡器) 的 IP 位址,並藉此訪問 ​




URI 設計原則

  • 簡短便於輸入的 URI:
    • 去除無意義且重覆的單詞,例如 https://api.example.com/api/v1/employees,由 domain 就能得知這是一個 API,但在路徑又重覆了一次 api。
  • 使用者能讀懂的 URI:
    • 使用有意義的英文單字,而不使用縮寫。
  • 小寫英文字母的 URI:
    • 一律使用小寫英文字母,更不可大小寫字母混用。
  • 修改方便的 URI:
    • 例如 https://api.example.com/v1/employees/1,即可看出該員工 ID 為 1,而且只要修改 ID 就能獲取其他員工的資源。
  • 不暴露 server 架構的 URI:
    • 例如 https://api.example.com/v1/employees.php,就知道應該是用 PHP 程式語言編寫的,這讓黑客更容易針對漏洞發起惡意攻擊。
  • 規則統一的 URI:
    • 例如使用英文字母複數 https://api.example.com/v1/employees 來取得所有員工資源組
    • 用單數 https://api.example.com/v1/employee/1 來取得一位員工的資源,類似這種不統一的 URI 容易造成 client 的混亂。 不使用空格及需要編碼的字元。 使用連接符 - 連結多個英文單字: 但應避免多個英文單字連結,而是使用路徑 / 劃分的方式。 URI 應加入 API 的版本號: 如 https://api.example.com/v1/employees。

▍API 設計範例

方法一組資源 URI:https://api.example.com/v1/employees單個資源 URI:https://api.example.com/v1/employees/1
GET取得資源組 (所有資料)取得指定的一筆資源
POST新增一筆資源 
PUT 覆蓋指定的一筆資源
PATCH 更新指定的一筆資源 (部份更新)
DELETE 刪除指定的一筆資源

▍資料筆數與位置查詢參數 資料量如果很多的話,API 就要設計成能夠指定欲取得的資料筆數 limit 和資料位置 offset or max_id,這兩個查詢參數也是 client 實現分頁機制所須要的。

項目查詢參數名稱參數值說明備註
資料筆數limit5每次取得的資料量 
資料位置-相對位置offset10識別已取得的資料位置從 0 (0-based) 開始計數
資料位置-絕對位置max_id1識別已取得的資料位置使用唯一值,如員工 ID
  • 相對位置:適用儲存的資料量少,且新增與刪除頻率低。
    https://api.example.com/v1/employees?limit=2&offset=1
    
  • 絕對位置:適用儲存的資料量多,且新增與刪除頻率高。
    http://192.168.0.200:3000/v1/employees?limit=2&max_id=1
    



參考資料:https://www.footmark.info/programming-language/design/restful-webapi-design-guide/


HTTP頭欄位 1

  • 使用者代理 將 請求訊息 轉移至 Server,請求訊息 (request message) 範例:

    GET /31/fetch-api HTTP/1.1
    Host: notfalse.net
    User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:53.0) Gecko/20100101 Firefox/53.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
    Accept-encoding: gzip, deflate, br
    accept-language: zh-TW,zh;q=0.8,en-US;q=0.6,en;q=0.4
    Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
    
    • User-Agent:瀏覽器的瀏覽器身分標識字串
    • Accept:能夠接受的回應內容類型(Content-Types)。
    • Accept-Encoding:能夠接受的編碼方式列表。
    • Authorization:用於超文字傳輸協定的認證的認證資訊




  • Cookie 是一種伺服器會傳送 HTTP 回應中的資料。 用戶端 (選擇性) 儲存在 cookie,然後將它傳回 subsequet 要求。 這可讓用戶端與伺服器共用狀態。
  • 若要設定的 cookie,伺服器會納入回應 Set-cookie 標頭。 Cookie 的格式為名稱 / 值組,以選擇性屬性。

  • 伺服器 HTTP 回應可以包含多個 Set-cookie 標頭和其他參數。

    Set-Cookie: session-id=1234567; max-age=86400; domain=example.com; path=/;
    
    • max-age:最大壽命,設定 cookie 的最長使用期限。 (優先使用)
    • Expires: 設定 cookie 的到期日。
    • path:將 cookie 限制為網域內指定的路徑




  • 將 cookie 加入至 HTTP 回應中,建立 CookieHeaderValue 執行個體,表示 cookie。 然後呼叫 AddCookies 擴充方法,其定義於 System.Net.Http。HttpResponseHeadersExtensions 類別,以新增 cookie。

    public HttpResponseMessage Get()
    {
        var resp = new HttpResponseMessage();
      
        var cookie = new CookieHeaderValue("session-id", "12345");
        cookie.Expires = DateTimeOffset.Now.AddDays(1);
        cookie.Domain = Request.RequestUri.Host;
        cookie.Path = "/";
      
        resp.Headers.AddCookies(new CookieHeaderValue[] { cookie });
        return resp;
    }
    
  • 若要從用戶端要求中擷取的 cookie,呼叫 GetCookies 方法:

    string sessionId = "";
      
    CookieHeaderValue cookie = Request.Headers.GetCookies("session-id").FirstOrDefault();
    if (cookie != null)
    {
        sessionId = cookie["session-id"].Value;
    }