Web API 標準答案

WebAPI, Swagger

引言

Web API 程式開發寫法有多種樣式,讓本人非常混亂。剛好花了幾天研究 Swagger API,就順便再整理一輪 Web API 的“標準答案”。

關鍵資訊

我們只送 200 的成功訊息與 400 的文字錯誤訊息。

只要導入 Swagger 模組就能自重生出文件。

錯誤處理

一般可用 BadRequest() 函式表明 400(BadRequest) 並在內容夾雜處理好的文字錯誤訊息。其實錯誤訊息的格式也可以是 Json 等物件格式,但前端的處理上會多好幾個步驟且有不精準問題,綜合累積的經驗若有錯誤直接送回文字格式的錯誤訊息最為通用。

也可丟出 BadHttpRequestException 例外類別,會送回完整的例外訊息,此例外類別預設送回 400(BadRequest)。其它的例外類別都是 500(Internal Server Error) 這是不能被客戶接受的,500 會被客戶直接認定系統有嚴重問題。400 就當作一般錯誤。

參考文件

延伸參考文件

關鍵原碼紀錄

模式一:透過 ActionResult<T> 泛型

  • 這是最建議的方案。

  • 不用特別標註 Swagger Annotations 也能產出 Swagger schema 文字說明。

  • 要用 Ok(), BadRequest() 函式回傳結果。

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;
//※ 用 Swashbuckle 或 NSwag 的碼都一樣。
namespace YourProject.Controllers;

[ApiController]
[Route("api/[controller]/[action]")]
public class FooController : ControllerBase
{
  readonly ILogger<FooController> _logger;
  public FooController(ILogger<FooController> logger)
  {
    _logger = logger;
  }

  [HttpPost]
  public ActionResult<EchoResult> Echo(EchoArgs args)
  {
    try
    {
      // 模擬執行失敗
      if (args.LetMeFail)
      {
        _logger.LogError("這是邏輯錯誤。");
        return BadRequest("這是邏輯錯誤。");
      }

      // 模擬出現預期之外的例外
      if (DateTime.Now.Second % 3 == 0)
      {
        throw new ApplicationException("這是例外訊息!");
      }

      // success
      _logger.LogInformation("這是成功訊息。");
      return Ok(new EchoResult
      {
        Echo = $"{args.Knock}@{DateTime.Now:HH:mm:ss}",
      });
    }
    catch (Exception ex)
    {
      _logger.LogError(ex, "執行XXX出現例外!" + ex.Message);
      return BadRequest("執行XXX出現例外!" + ex.Message);
      // throw new BadHttpRequestException("執行XXX出現例外!" + ex.Message, ex); // 送回完整的例外訊息。
    }
  }
}

模式二:直接用物件

  • 不建議此方案。因為無法簡單的處理邏輯錯誤。這個模式下就算是邏輯錯誤也只能以例外處理!若有十成把握只會成功就可以用此方案。

  • 不用特別標註 Swagger Annotations 也能產出 Swagger schema 文字說明。

  • 可直接回傳回傳結果,不用透過 Ok() 函式。可以少 key in 一點碼。

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;
//※ 用 Swashbuckle 或 NSwag 的碼都一樣。

namespace YourProject.Controllers;

[ApiController]
[Route("api/[controller]/[action]")]
public class FooController : ControllerBase
{
  readonly ILogger<FooController> _logger;
  public FooController(ILogger<FooController> logger)
  {
    _logger = logger;
  }

  [HttpPost]
  public EchoResult Echo2(EchoArgs args)
  {
    try
    {
      // 模擬執行失敗
      if (args.LetMeFail)
      {
        _logger.LogError("這是邏輯錯誤。");
        throw new ApplicationException("這是邏輯錯誤。");
        // ※這個模式下就算是邏輯錯誤也只能以例外處理!
      }

      // 模擬出現預期之外的例外
      if (DateTime.Now.Second % 3 == 0)
      {
        throw new ApplicationException("這是例外訊息!");
      }

      // success
      _logger.LogInformation("這是成功訊息。");
      return new EchoResult
      {
        Echo = $"{args.Knock}@{DateTime.Now:HH:mm:ss}",
      };
    }
    catch (Exception ex)
    {
      _logger.LogError(ex, "執行XXX出現例外!" + ex.Message);
      throw new BadHttpRequestException("執行XXX出現例外!" + ex.Message, ex); // 送回完整的例外訊息。
    }
  }
}

模式三:透過 IActionResult 介面

  • 此方案適用進階的狀況。而進階狀況幾乎不存在。

  • 必需一一標註 Swagger Annotations 才能產出 Swagger schema 文字說明。

  • 要用 Ok(), BadRequest() 函式回傳結果。

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;
//※ 用 Swashbuckle 或 NSwag 的碼都一樣。

namespace YourProject.Controllers;

[ApiController]
[Route("api/[controller]/[action]")]
public class FooController : ControllerBase
{
  readonly ILogger<FooController> _logger;
  public FooController(ILogger<FooController> logger)
  {
    _logger = logger;
  }

  [HttpPost]
  [SwaggerResponse(200, Type = typeof(EchoResult))]
  [SwaggerResponse(400, Type = typeof(string))]
  public IActionResult Echo3([FromBody] EchoArgs args)
  {
    try
    {
      // 模擬執行失敗
      if (args.LetMeFail)
      {
        _logger.LogError("這是邏輯錯誤。");
        return BadRequest("這是邏輯錯誤。");
      }

      // 模擬出現預期之外的例外
      if (DateTime.Now.Second % 3 == 0)
      {
        throw new ApplicationException("這是例外訊息!");
      }

      // success
      _logger.LogInformation("這是成功訊息。");
      return Ok(new EchoResult
      {
        Echo = $"{args.Knock}@{DateTime.Now:HH:mm:ss}",
      });
    }
    catch (Exception ex)
    {
      _logger.LogError(ex, "執行XXX出現例外!" + ex.Message);
      return BadRequest("執行XXX出現例外!" + ex.Message);
      // throw new BadHttpRequestException("執行XXX出現例外!" + ex.Message, ex); // 送回完整的例外訊息。
    }
  }
}

沒圖沒真象

(EOF)

Last updated