IRONSOFTWAREHOME

在Linux上新增.NET Aspire中按ID獲取端點

在Linux上為.NET Aspire新增一個通過ID獲取的端點

Tim Corey

15m 20s

從資料庫表中返回每條記錄對於列出頁面很有用,但大多數API使用者也需要通過其標識符來獲取單個記錄。 第二個端點引入了一些"獲取所有"路徑不需要的決定:對單個物件與集合來說,哪種返回型別更合適,當ID不匹配任何記錄時應發生什麼,以及如何使用正確的HTTP狀態碼將失敗資訊傳遞給調用者。

在他的视频"在Linux上為.NET Aspire新增一個通過ID獲取的端點"中,Tim Corey 續寫Tiny Ticket API,新增了一個GET /api/tickets/{id}端點。 起初只是一個現有路徑的複製粘貼,然後演變成關於邊界情況處理的現場演示:返回單個物件而不是陣列,檢查空結果,以及使用404 Not Found。如果您在關注C# on Linux系列或在構建需要適當狀態碼響應的API,此集覆蓋了完整的思考過程。

複製獲取全部路徑作為起始點

[0:35 - 1:45] Tim打開API服務的GET /api/tickets端點。 新路徑需要一個票務ID的路徑參數,因此URL模式更改為包含int id參數。 儲存過程引用從spTickets_Get,需要一個ID參數。

app.MapGet("/api/tickets/{id:int}", async (int id, IDbConnection db) =>
{
    var tickets = await db.LoadSqlAsync<TicketModel>("spTickets_Get", new { id });
    // Initial version: returns a list, which we'll fix next
    return tickets;
});
C#

一個值得注意的命名便捷性:儲存過程參數是小寫的id,與C#參數名稱完全匹配。 這意味著Dapper可以直接將匿名物件new { id }映射,而不需指定屬性名稱。 如果SQL參數使用不同的大小寫,匿名物件將需要顯式的屬性分配,例如new { Id = id }

返回單一物件而不是列表

[2:39 - 4:16] 通過Swagger的首次測試揭示了一個問題:傳遞ID 2返回一個帶有正確票務的200,但響應正文被包在一個JSON陣列中。 當調用者通過ID請求單個資源時,他們期望獲取的是單一物件,而不是包含一個元素的集合。

在查詢結果中附加.FirstOrDefault()可以解決包裝問題。 null。 這解決了陣列問題,但也引出一個新問題:當ID與任何記錄不匹配時,API應返回什麼?

var output = tickets.FirstOrDefault();
C#

單行更改為現有記錄產生了正確的響應形狀。 然而,使用資料庫中不存在的ID 4進行測試揭示了一個更深的漏洞。響應回來顯示null並附帶200狀態碼。 這在技術上確實是有效的HTTP,但卻誤導了調用者:200表示請求成功且資源已找到,而實際上卻沒有匹配。

使用TypedResults處理未找到的資源

[4:41 - 11:44] 這部分是Tim實時處理設計決策的地方,比起僅僅閱讀最終程式碼更具價值。 他的思維過程經歷了幾個迭代:

首先,他考慮使用.FirstOrDefault(),當列表為空時會拋出異常。 這會產生500錯誤,這比200的空值更糟,因為500暗示了伺服器錯誤,而不是缺失的資源。

然後他後退一步並建立了一個空檢查。 他將結果儲存在變數中,檢查它是否為空,並對每種情況返回不同的響應。 挑戰在於,簡約API處理程式需要在它可以返回多種響應形狀時明確聲明其返回型別。

解決方案是TypedResults,允許您在方法簽名中指定可能的響應型別

app.MapGet("/api/tickets/{id:int}", async Task<Results<Ok<TicketModel>, NotFound>> (int id, IDbConnection db) =>
{
    var tickets = await db.LoadSqlAsync<TicketModel>("spTickets_Get", new { id });
    var output = tickets?.FirstOrDefault();

    if (output is null)
    {
        return TypedResults.NotFound();
    }

    return TypedResults.Ok(output);
});
C#

那個返回型別,TicketModel主體的200,要麼是沒有主體的404。 VS Code中的顏色括號匹配有助於導航巢狀的角括號,這在泛型結果型別中快速堆疊起來。

測試過程中暴露了一個微妙的錯誤:第一版本調用了return它。 端點編譯成功,因為Ok路徑。 當Swagger仍顯示了一個缺失ID的200狀態碼時,Tim注意到了這一點,然後新增了return,在下次運行時404顯示正確。

在Swagger中測試兩種路徑

[11:44 - 14:09] 使用最終程式碼後,Tim在Swagger UI中運行兩種場景。 傳遞ID 3返回帶有票務物件的200。 傳遞ID 4返回404,且響應正文為空。

他還指出Swagger介面中的一個細節,可能會讓初次使用者感到困惑:執行按鈕下方的"Responses"部分顯示可能的響應程式碼(200和404),而不是實際結果。 實際的伺服器響應顯示在該部分上方的另一個面板中。 混淆這兩個面板是"我為什麼拿到200?"的常見原因。

TypedResults方法也自動改善了Swagger文件。 因為返回型別聲明了NotFound,Swagger將兩者顯示為可能的結果,並分別顯示其架構。 閱讀API文件的調用者知道他們需要處理404情況,無需開發者撰寫額外的OpenAPI註解。

總結:優先處理邊界情況而非功能

[14:09 - 15:09] 簡單的獲取全部端點複製粘貼最終演變成一個更深入的API設計練習。 最終版本處理了快樂路徑(找到記錄),預期的失敗(未找到記錄),以及對於意外場景(查詢返回null)的防禦性空檢查。 Tim選擇現場處理這些案例,而不是展示打磨過的程式碼,展示了生產端點所需的那種迭代思考。

結論

[15:09 - 15:20] 在最小API中新增一個通過ID獲取的端點,涉及到路徑定義之外的三項決策:使用TypedResults在返回型別中,以便框架返回正確的HTTP狀態碼。 Results<Ok<t>, NotFound>模式可在任何需要傳達成功或缺席的端點中重複使用。

**系列導航:**這篇文章是C# on Linux系列的一部分,構建Tiny Ticket應用程式。前一篇:新增Swagger UI。 下一篇:新增POST插入端點

範例提示:當您的簡約API處理程式返回多個可能的狀態碼時,始終在Results<>泛型中聲明它們。 這自動生成準確的Swagger文件,並強制編譯器驗證每條程式碼路徑返回有效的結果型別。

觀看完整版影片在他的YouTube頻道,並從C# on Linux系列中獲得更多建立強健API端點的見解。

Earn More by Sharing What You Love

Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!

Let's Stay in Touch!

Join our newsletter, you’ll get exclusive access on article updates. We value your privacy

Key in blue circle

立即免費取得 30 天試用金鑰

Your trial license will be sent to your email address

無任何限制。100% 解鎖。無需信用卡。

bullet_checked無需信用卡或建立帳號無任何限制。100% 解鎖。無需信用卡。
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried IronPDF
獲取您的無義務諮詢
填寫以下表格或發送電子郵件至sales@ironsoftware.com
您的詳細資訊將始終保密。
被全球數百萬工程師信任
Iron Software的客戶標誌
立即獲取您的30天試用金鑰
無需信用卡或帳戶建立