.Net WebApi 命名規範

大象醫生公司HTTP Service開發指南

1 WebAPI接口實現規範

1.1 GET方法的幾種實現狀況

1.1.1 基本實現

// GET: api/v1/Products/1455ebe0-832b-46c5-8772-b9483d947a63

    /// <summary>
    /// 獲取特定產品
    /// </summary>
    /// <param name="id">產品標識</param>
    /// <returns></returns>
    [Route("~/api/v1/Products/{id}")]
    [ResponseType(typeof(ProductOutput))]
    public IHttpActionResult GetProduct(Guid id)
    {
        var result = productService.GetProductById(id);
        return Ok(result);
    }

規範編程

  • 首行:以一個具體的URL示例做爲首行,URL以HTTP方法名開始,HTTP方法名大寫,後跟冒號+空格+URL。要求在運行時使用該URL進行調試可以進入方法體;
  • 註釋行:建議以獲取XX資源或符合XX條件的XX資源做爲描述,例如:獲取正在促銷的產品;
  • 路由:在符合默認路由規則時,該部分是可選的。參數部分,做爲本資源的標識時,不須要添加資源名稱做爲前綴。例如,這裏不使用productId,而直接使用id。僅當URL中出現其它資源標識時,該其它資源標識須要添加用於限定的資源名稱做爲前綴。Route特性老是出如今接口方法或ResponseType特性之上。
  • 響應類型:當接口方法返回的是IHttpActionResult類型時,Swagger沒法推導具體的響應類型,必須使用ResponseType加以聲明,以便生成正確的Swagger元數據。ResponseType特性老是出如今接口方法(或SwaggerResponse特性)之上。
  • 接口方法聲明:方法命名老是使用完整的語義,以便清晰描述本方法的具體功能。Swagger根據方法名生成元數據中的operationId,且operationId不容許重複。因此必須確保語義表述準確以免重複。然而在本例中,使用GetProduct或GetProducts來返回特定id的產品或所有產品是容許的命名慣例,並不須要特地命名爲GetProductById或GetAllProducts。
  • 返回結果中間變量:建議定義中間變量var result獲取返回結果值,以便於調試,並使最終結果返回代碼return Ok()中的參數顯得更簡潔。

1.1.2 帶有多個狀態碼返回的實現

// GET: api/v1/Products/1455ebe0-832b-46c5-8772-b9483d947a63

    /// <summary>
    /// 獲取特定產品
    /// </summary>
    /// <param name="id">產品標識</param>
    /// <returns></returns>
    [Route("~/api/v1/Products/{id}")]
    [ResponseType(typeof(ProductOuput))]
    [SwaggerResponse(HttpStatusCode.NotFound)]
    public IHttpActionResult GetProduct(Guid id)
    {
        var result = productService.GetProductById(id);
        if (result == null)
        {
            return NotFound();
        }

        return Ok(result);
    }

規範api

  • SwaggerResponse:SwaggerResponse特性用於描述接口返回除200之外的其它狀態碼,這將在元數據中生成對應的描述。建議SwaggerResponse老是出現接口方法之上。入參包括StatusCode, Description和Type。當沒法利用StatusCode推斷返回意義時,必須使用Description註明描述;當應答體有返回內容時,必須使用Type標註返回類型。
  • 使用XML Documentation的response配置節也能夠達到與SwaggerResponse相似的效果,以下所示。須要注意的是,二者出現衝突時,SwaggerResponse的優先級更高。ui

    /// <response code="404">Not Found</response>

1.1.3 返回集合結果的實現

// GET: api/v1/Products

    /// <summary>
    /// 獲取全部產品
    /// </summary>
    /// <returns>產品集合</returns>
    [Route("~/api/v1/Products")]
    public IEnumerable<ProductOutput> GetProducts()
    {
        var result = productService.GetProducts();
        return result;
    }

規範3d

  • 當返回集合做爲結果時,若是結果集爲空,不須要返回404,只需返回空結果集。所以,在不須要有其它非200返回的狀況下,方法的返回類型能夠是集合類型,而非IHttpActionResult。

1.1.4 返回分頁集合結果的實現

// GET: api/v1/Products?Pager.PageIndex=1&Pager.PageSize=10

    /// <summary>
    /// 獲取全部產品的分頁列表
    /// </summary>
    /// <returns>產品分頁列表</returns>
    [Route("~/api/v1/Products")]
    public IPagedList<ProductOutput> GetPagedProducts([FromUri] Pager pager)
    {
        var result = productService.GetPagedProducts(pager);
        return result;
    }

規範調試

  • 分頁器、篩選器、排序器等,應該經過Query String傳遞。本例中,Query String中的參數PageIndex和PageSize必須使用Pager前綴,才能綁定至方法參數pager中。
  • Pager, IPagedList, SortBy等類型的實現,由Elephant.Core核心庫提供。關於如何引用企業核心庫可參考《大象醫生公司核心庫開發與發佈說明》。

1.2 POST方法的幾種實現狀況

1.2.1 建立資源的基本實現

// POST: api/v1/Products

    /// <summary>
    /// 建立產品
    /// </summary>
    /// <param name="product">產品</param>
    /// <returns></returns>
    [Route("~/api/v1/Products")]
    [SwaggerResponseRemoveDefaults]
    [SwaggerResponse(HttpStatusCode.BadRequest)]
    [SwaggerResponse(HttpStatusCode.Created, Type = typeof(ProductOutput))]
    public IHttpActionResult PostProduct([FromBody]ProductInput product)
    {
        if (ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        var result = productService.CreateProduct(product);

        return CreatedAtRoute("DefaultApi", new { id = product.Id }, result);
    }

規範日誌

  • 建立資源成功時,應當返回201 Created而不是200 OK。同時,須要在HTTP response headers的location節中返回所建立的新資源對應的URL,同時返回該資源的內容。
  • SwaggerResponseRemoveDefaults:能夠在生成的元數據中取消默認返回狀態碼200。此例中,201將成爲新的默認返回狀態碼,顯示在Swagger文檔中。
  • 當有DTO做爲輸入時,須要對DTO進行模型合法性校驗。使用ModelState.IsValid進行校驗,並在校驗失敗時,返回400,同時返回ModelState。ModelState包含了模型校驗失敗的具體緣由。
  • 使用CreatedAtRoute能夠應用一個現成的路由。本例中使用了名稱爲DefaultApi的默認路由,此默認路由一般定義在WebApiConfig.cs文件中。但更多的狀況是,使用一個已存在的自定義路由,此時須要將這一路由聲明爲一個具名路由。例如,前例中GET方法的路由,能夠改寫爲以下方式,使之成爲一個具名路由,並使用GetProductById這一名稱(替換本例中的DefaultApi),此路由即用於建立新資源的URL。本例中new { id = product.Id }中的參數id,將會替換該路由中的參數id,而result則做爲Content中的內容返回。code

    [Route("~/api/v1/Products/{id}", Name = "GetProductById")]
  • 本例中,方法的入參product應當爲一個做爲Input的DTO,而result變量應當爲一個做爲Output的DTO。相關的DTO的命名以Input或Output做爲後綴。後綴不併僅限於使用Input和Output,也可使用Create或Update等,進一步區分用途。排序

1.2.2 其它非冪等性操做的實現

// POST: api/v1/Products/Last/Remove

    /// <summary>
    /// 刪除最後一個產品
    /// </summary>
    /// <returns></returns>
    [Route("~/api/v1/Products/Last/Remove")]
    [SwaggerResponseRemoveDefaults]
    [SwaggerResponse(HttpStatusCode.NotFound)]
    [SwaggerResponse(HttpStatusCode.NoContent)]
    public IHttpActionResult RemoveLastProduct()
    {
        var result = productService.RemoveLastProduct();
        if (!result)
        {
            return NotFound();
        }

        return StatusCode(HttpStatusCode.NoContent);
    }

規範接口

  • 本例中,刪除最後一個產品的操做知足非冪等性,即屢次操做可能刪除多個不一樣的產品,使得產生不一樣的系統狀態。對於原本在語義上有可能使用PUT或DELETE的操做,若是其知足非冪等性,都應當使用POST方法。
  • 當方法表明的操做再也不用於建立資源時,使用操做名詞自己替代Post用於方法的命名,所以本例中的方法不是PostRemoveLastProduct。
  • 當使用非Post前綴的方法名稱時,按照命名慣例,Web API將默認該方法爲Post方法。所以本例中不須要加HttpPost特性(其它HTTP方法須要顯式聲明)。
  • 當操做不包含返回值時,應返回204 NoContent。

1.3 PUT方法的幾種實現狀況

1.3.1 更新資源的基本實現

// PUT: api/v1/Products/1455ebe0-832b-46c5-8772-b9483d947a63

    /// <summary>
    /// 更新產品
    /// </summary>
    /// <param name="id">產品標識</param>
    /// <param name="product">產品</param>
    /// <returns></returns>
    [Route("~/api/v1/Products/{id}")]
    [SwaggerResponseRemoveDefaults]
    [SwaggerResponse(HttpStatusCode.NotFound)]
    [SwaggerResponse(HttpStatusCode.NoContent)]
    public IHttpActionResult PutProduct(Guid id, [FromBody]ProductInput product)
    {
        if (ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        var result = productService.GetProductById(id);
        if (result == null)
        {
            return NotFound();
        }

        productService.UpdateProduct(id, product);

        return StatusCode(HttpStatusCode.NoContent);
    }

規範ip

  • 根據官方的定義,使用PUT方法,意味着或者不存在該資源,則建立一個新的資源;或者存在該資源,使用新的資源完整替換原有資源。不管哪種,屢次操做後獲得的系統狀態的結果是徹底一致的,於是符合冪等性。在本例中,並無由於不存在該資源而建立新的資源,而是返回了404 NotFound,但仍然沒有違反冪等性。具體採用哪種策略,應該根據實際應用場景須要決定。若是建立新資源,則應當返回201 Created。
  • 資源的標識在方法中,經過參數id獨立傳遞,ProductInput並不包含id屬性。在更新前,須要判斷id對應的資源是否存在,而後進行進一步的操做。

1.3.2 其它冪等性操做的實現

// PUT: api/v1/Products/1455ebe0-832b-46c5-8772-b9483d947a63/Disable

    /// <summary>
    /// 下架產品
    /// </summary>
    /// <param name="id">產品標識</param>
    /// <returns></returns>
    [HttpPut]
    [Route("~/api/v1/Products/{id}/Disable")]
    [SwaggerResponseRemoveDefaults]
    [SwaggerResponse(HttpStatusCode.NotFound)]
    [SwaggerResponse(HttpStatusCode.NoContent)]
    public IHttpActionResult DisableProduct(Guid id)
    {
        var result = productService.GetProductById(id);
        if (result == null)
        {
            return NotFound();
        }

        productService.DisableProduct(id);

        return StatusCode(HttpStatusCode.NoContent);
    }

規範

  • 當方法表明的操做再也不用於更新資源時,使用操做名詞自己替代Put用於方法的命名。因爲命名慣例決定了默認HTTP方法是POST,所以這裏須要顯式標識HttpPut特性。
  • 因爲屢次下架同一產品的結果是一致的,因此本例的操做符合冪等性。

1.4 DELETE方法的幾種實現狀況

1.4.1 刪除資源的基本實現

// DELETE: api/v1/Products/1455ebe0-832b-46c5-8772-b9483d947a63

    /// <summary>
    /// 刪除產品
    /// </summary>
    /// <param name="id">產品標識</param>
    /// <returns></returns>
    [Route("~/api/v1/Products/{id}")]
    [SwaggerResponseRemoveDefaults]
    [SwaggerResponse(HttpStatusCode.NotFound)]
    [SwaggerResponse(HttpStatusCode.NoContent)]
    public IHttpActionResult DeleteProduct(Guid id)
    {
        var result = productService.GetProductById(id);
        if (result == null)
        {
            return NotFound();
        }

        productService.DeleteProduct(id);

        return StatusCode(HttpStatusCode.NoContent);
    }

規範

  • DELETE方法應當知足冪等性。本例中,屢次刪除操做都將使系統狀態改變爲產品已刪除的狀態,所以雖然狀態碼的返回存在多個可能,但系統狀態始終是一致的。

1.5 冪等性的界定

冪等性應關注發送多個重複的操做,系統狀態的結果是否始終一致,而不是關注接口返回是否一致。系統狀態在這裏主要指的是業務狀態,而不包括那些業務以外額外生成的狀態變動,例如日誌、統計數據等。符合冪等性的寫操做,可使用POST、DELETE方法;不然,即便語義上屬於更新或刪除操做,也應當使用POST方法,以符合HTTP協議規定,確保基於協議之上的一些外部行爲的結果是符合預期的。

1.5 狀態返回碼

  • 上述示例中,操做成功後沒有返回內容的,200 OK和204 NoContent在大多數狀況下都是通用的。但爲了編程一致上的考慮,統一使用204 NoContent返回。
  • 當違反業務規則約束使得操做失敗時,應當返回409 Conflict。
相關文章
相關標籤/搜索