麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學院 > 開發設計 > 正文

RESTful API URI 設計: 判斷資源是否存在?

2019-11-17 02:12:25
字體:
來源:轉載
供稿:網友

RESTful API URI 設計: 判斷資源是否存在?

相關的一篇文章:RESTful API URI 設計的一些總結。

問題場景:判斷一個資源(Resources)是否存在,URI 該如何設計?

應用示例:判斷 id 為 1 用戶下,名稱為 windows 10 的產品是否存在?

如果這個問題出現在 MVC 項目中,我想我們一般會這樣設計:

public class PRoductService{    public async Task<bool> IsExist(int userId, string productName)    {        ....    }}

看來沒什么問題,的確也沒什么問題,那如果把這部分代碼搬到 asp.net WebAPI 項目中實現,會是怎樣呢?我們來看一下:

public class ProductsController : ApiController{    [HttpGet]    [Route("api/products/isexist/{userId}/{productName}")]    public async Task<bool> IsExist(int userId, string productName)    {        ...    }}

我想你應該發現一些問題了,這種寫法完全是 MVC 的方式,但并不適用于 WebAPI,主要有三個問題:

  • Route 定義混亂,完全違背 REST API URI 的一些設計原則。
  • Action 命名不恰當。
  • bool 返回值不合適。

對于上面的三個問題,我們分別來探討下。

1. URI 設計

首先,我們知道在 REST API 中,URI 代表的是一種資源,它的設計要滿足兩個基本要求,第一名詞而非動詞,第二要能清晰表達出資源的含義,換句話說就是,從一個 URI 中,你可以很直接明了的知道訪問的資源是什么,我們再來看我們設計的 URI:

api/products/isExist/{userId}/{productName}

這是什么鬼???這種設計完全違背 URI 原則,首先,我們先梳理一下,我們想要請求的資源是什么?沒錯,是產品(Products),但這個產品是某一個用戶下的,所以用戶和產品有一個上下級關系,訪問產品首先得訪問用戶,這一點要在 URI 中進行體現,其次,我們是獲取產品?還是判斷產品是否存在?這個概念是不同的,產品的唯一標識和用戶一樣,都是 id,在 URI 的一般設計中,如果要訪問某一唯一標識下的資源(比如 id 為 1 的 product),會這樣進行設計:api/products/{id},HttpClient 請求中會用 HttpGet 方法(api/products/1),這樣我們就可以獲得一個 id 為 1 的 product,但現在的場景是,獲取產品不通過唯一標識,而是通過產品名稱,難道我們要這樣設計:

api/products/{productName}

咋看之下,這樣好像設計也沒什么問題,但總覺得有些不對勁,比如如果再加一個產品大小,難道要改成這樣:api/products/{productName}/{productSize},這種設計完全是不恰當的,上面說到,URI 代表的是一種資源,通過 URI 獲取資源的唯一方式是通過資源的唯一標識,除此之外的獲取都可以看作是對資源的查詢(Query),所以,針對我們的應用場景,URI 的設計應該是這樣(正確):

api/users/{userId}/products: api/users/1/products?productName=windows 10

上面的 URI 清晰明了的含義:查詢 id 為 1 用戶下名稱為 windows 10 的產品。

2. Action 命名

對于 IsExist 的命名,如果沒有很強的強迫癥,其實也是可以接受的,因為 WebAPI 的 URI 并不會像 MVC 的 Route 設計那樣,在訪問的時候,URL 一般會默認 Action 的名字,所以,在 WebAPI Action 設計的時候,會在 Action 前面加一個 Route 屬性,用來配置 URI,也就是說每一個 Action 操作會對應一個 URI 請求操作,這個請求操作也就是 HTTP 的常用方法。

如果我們想把 IsExist 改掉,那用什么命名會好些呢?先回憶一下,我們在使用 Visual Studio 創建 ASP.NET WebAPI 項目的時候,VS 會自動創建一些示例 Action,我們看看能不能從那里得到一些線索:

public class ValuesController : ApiController{    // GET api/values    public IEnumerable<string> Get()    {        return new string[] { "value1", "value2" };    }    // GET api/values/5    public string Get(int id)    {        return "value";    }    // POST api/values    public void Post([FromBody]string value)    {    }    // PUT api/values/5    public void Put(int id, [FromBody]string value)    {    }    // DELETE api/values/5    public void Delete(int id)    {    }}

上面是 Values 資源的一些 Action 實現,我們可以看到,Action 的命名和 HTTP 方法一樣,比如 Get 就是 Get,而不是 GetById,Get 是動詞,表示它對資源的一種操作,具體是通過什么進行操作?在參數中可以很直觀的進行反應,一般會在 HelpPage 中進行注釋說明。

IsExist 的含義還是判斷資源是否存在,其本質上來說就是去獲取一個資源,也就是 Get 操作,所以,在 WebAPI Action 中對此的命名,我們直接使用 Get 會好一下,或者使用 Exist。

3. 請求返回

bool 一般是用在項目方法中的返回值,如果用在 HTTP 請求中,就不是很恰當了,我先貼出幾篇文章:

  • REST API Design - Resource Modeling(重點看下
  • REST API 404: Bad URI, or Missing Resource?
  • Designing REST API for checking if a username exists.
  • Proper route for checking resource existence in a RESTful API
  • When to use HTTP status code 404 in an API(重點看下

上面除去第一篇文章,其他文章都是在討論:檢查一個資源是否存在,REST API 該如何設計(HTTP status code)?客戶端獲取服務的響應不是通過 bool,而是通過 HTTP 狀態碼,主要設計三個:404、204 和 200:

  • 404 is correct since the resource "/users/{username}" was Not Found.
  • If the resource exists but it is empty (as in "null") then you should return 204.
  • If the resource exists and contains any data then you should return 200.

204 和 404 有所不同的是,204 表示資源存在,但是為空,404 代表的是原始資源本身就不存在,并且通過唯一標識查詢不到,而 204 更多的是表示,在一定條件下的資源不存在,但可以通過唯一標識查詢到,所以如果資源不存在返回 204 不恰當,wikipedia 中 200 和 404 詳細說明:

  • 200 OK - ... The actual response will depend on the request method used. In a GET request, the response will contain an entity corresponding to the requested resource.
  • 404 Not Found - The requested resource could not be found but may be available again in the future. Subsequent requests by the client are permissible.

HTTP status code 簡要說明:

  • 2xx codes Tell a UA that it did the right thing, the request worked. It can keep doing this in the future.(請求成功)
  • 3xx codes Tell a UA what you asked probably used to work, but that thing is now elsewhere. In future the UA might consider just going to the redirect.(請求很可能成功)
  • 4xx codes Tell a UA it did something wrong, the request it constructed isn't proper and shouldn't try it again, without at least some modification.(請求失敗)
  • 5xx codes Tell a UA the server is broken somehow. But hey that query could work in the future, so there is no reason not to try it again. (except for 501, which is more of a 400 issue).(請求錯誤)

在上面文章中,有一段很有意思的對話(請略過翻譯):

  • Alien: Computer, please tell me all planets that humans inhabit.(電腦,請告訴我所有適宜人類居住的星球。)Computer: 1 result found. Earth(查詢到一個結果,地球)
  • Alien: Computer, please tell me about Earth.(電腦,請告訴我地球的信息。)Computer: Earth - Mostly Harmless.(地球-無害。)
  • Alien: Computer, please tell me about all planets humans inhabit, outside the asteroid belt.(電腦,請告訴我小行星帶以外,所有適宜人類居住的星球。)Computer: 0 results found.(沒有查詢到結果。)
  • Alien: Computer, please destroy Earth.(電話,請毀滅地球。)Computer: 200 OK.(毀滅成功。)
  • Alien: Computer, please tell me about Earth.(電腦,請告訴我地球的信息。)Computer: 404 - Not Found(沒有找到。)
  • Alien: Computer, please tell me all planets that humans inhabit.(電腦,請告訴我所有適宜人類居住的星球。)Computer: 0 results found.(沒有找到。)
  • Alien: Victory for the mighty Irken Empire!(看不懂啥意思)

搜刮到的一張 HTTP status code 示意圖(點擊查看大圖):

4. 最終代碼

針對一開始的應用問題,最終完善代碼:

public class ProductsController : ApiController{    [HttpGet]    [Route("api/users/{userId}/products")]    public async Task<HttpResponseMessage> Get(int userId, string productName)    {        if (true)        {            return Request.CreateResponse(HttpStatusCode.OK);        }        else        {            return Request.CreateResponse(HttpStatusCode.NotFound);        }    }}public class WebApiTest{    [Fact]    public async Task Exists_Product_ByProductName()    {        using (var client = new HttpClient())        {            client.BaseAddress = new System.Uri(Base_Address);            var response = await client.GetAsync("/api/users/1/products?productName=windows 10");            //var requestMessage = new HttpRequestMessage(HttpMethod.Head, "/api/users/1/products?productName=windows 10");            //var response = await client.SendAsync(requestMessage);//更好的調用方式,只請求HEAD。            Console.WriteLine(response.StatusCode);            Assert.True(response.IsSuccessStatusCode);        }    }}

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 国产乱轮视频 | 日韩视频精品一区 | 国产精品视频一区二区三区四 | 国产一区二区三区四区精 | 在线a免费观看 | 精品二区在线观看 | 色婷婷一区二区三区 | 精品一区二区三区在线观看视频 | 欧美粗暴analvideos| 精品乱码久久久久 | 亚洲国产成人久久一区www妖精 | 久久久久久久久久性 | 91福利免费观看 | 欧美一区二区三区中文字幕 | 中文字幕在线观看网址 | 国产免费一区二区三区视频 | 国产精品视频免费在线观看 | 婷婷一区二区三区 | sese在线视频 | 国产成人自拍小视频 | 免费观看视频在线观看 | 在线观看91精品 | 成年性羞羞视频免费观看 | 欧美日本综合 | 免费午夜网站 | 天堂成人国产精品一区 | 亚洲性综合网 | 一区二区三区视频在线 | 久久精品国产精品亚洲 | 久久国产成人午夜av浪潮 | 毛片a区 | 欧美视频在线一区二区三区 | 美女黄网站免费观看 | 久久日韩| 一级视频网站 | 久久久久久久国产视频 | 国产一级在线看 | wwwxxx视频| 国产精品久久久久久久久久妇女 | 成年人黄色免费网站 | 午夜色片 |