国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設(shè)計 > 正文

RESTful API URI 設(shè)計: 判斷資源是否存在?

2019-11-17 02:12:25
字體:
供稿:網(wǎng)友

RESTful API URI 設(shè)計: 判斷資源是否存在?

相關(guān)的一篇文章:RESTful API URI 設(shè)計的一些總結(jié)。

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

應(yīng)用示例:判斷 id 為 1 用戶下,名稱為 windows 10 的產(chǎn)品是否存在?

如果這個問題出現(xiàn)在 MVC 項目中,我想我們一般會這樣設(shè)計:

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

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

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

我想你應(yīng)該發(fā)現(xiàn)一些問題了,這種寫法完全是 MVC 的方式,但并不適用于 WebAPI,主要有三個問題:

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

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

1. URI 設(shè)計

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

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

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

api/products/{productName}

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

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

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

2. Action 命名

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

如果我們想把 IsExist 改掉,那用什么命名會好些呢?先回憶一下,我們在使用 Visual Studio 創(chuàng)建 ASP.NET WebAPI 項目的時候,VS 會自動創(chuàng)建一些示例 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 實現(xiàn),我們可以看到,Action 的命名和 HTTP 方法一樣,比如 Get 就是 Get,而不是 GetById,Get 是動詞,表示它對資源的一種操作,具體是通過什么進行操作?在參數(shù)中可以很直觀的進行反應(yīng),一般會在 HelpPage 中進行注釋說明。

IsExist 的含義還是判斷資源是否存在,其本質(zhì)上來說就是去獲取一個資源,也就是 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 該如何設(shè)計(HTTP status code)?客戶端獲取服務(wù)的響應(yīng)不是通過 bool,而是通過 HTTP 狀態(tài)碼,主要設(shè)計三個: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(查詢到一個結(jié)果,地球)
  • 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.(沒有查詢到結(jié)果。)
  • 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. 最終代碼

針對一開始的應(yīng)用問題,最終完善代碼:

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);//更好的調(diào)用方式,只請求HEAD。            Console.WriteLine(response.StatusCode);            Assert.True(response.IsSuccessStatusCode);        }    }}

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 云南省| 三都| 米林县| 喀喇沁旗| 安阳市| 平乡县| 龙川县| 红桥区| 大关县| 建德市| 上饶县| 县级市| 鄂尔多斯市| 同仁县| 乐山市| 南召县| 弋阳县| 汕头市| 涡阳县| SHOW| 上蔡县| 体育| 琼海市| 湄潭县| 会理县| 甘肃省| 裕民县| 江孜县| 故城县| 乌鲁木齐市| 永城市| 天全县| 万州区| 高邑县| 高要市| 临泽县| 廊坊市| 北京市| 道真| 长沙县| 丘北县|