跳至頁尾內容
Iron Academy Logo
學習C#
學習C#

其他類別

在Linux上新增.NET Aspire中的DELETE端點

[[academy-video-youtube({"vid": "x10CYBXrLxg", "start_time": "0", "title": "Adding a DELETE Endpoint in .NET Aspire on Linux", "creator": "Tim Corey", "length": "8m 40s"})]]

每個CRUD API最終都需要一種方法來刪除記錄,DELETE動詞與GET、POST和PUT一起完成四個核心的HTTP操作。 相比其他動詞,DELETE結構上是最簡單的:無請求正文,無驗證管道,無複雜的返回型別。 它引入的是一個設計問題,沒有普遍正確的答案,即當呼叫者請求刪除一個不存在的記錄時應該返回什麼。

在他的视频"Adding a DELETE Endpoint in .NET Aspire on Linux",Tim Corey通過新增最終端點來完成Tiny Ticket API,修正了一個在按照ID儲存過程中出現的參數大寫不一致問題,並討論了在記錄缺失時應該返回404還是204。 這一集還預示著轉向前端的過渡,將成為C# on Linux系列下一階段的重點。 如果您一直在關注此系列,或是首次在簡化API上串連DELETE,這篇文章將逐步講解完整的端點及使參數綁定在專案中保持一致的小重構。

Mapping the DELETE Endpoint

[1:02 - 2:14] 端點註冊遵循與其他路徑相同的結構,僅進行兩處調整。 路徑包含一個MapPut。 沒有輸入記錄,因為除了標識符外不需要其他東西。

app.MapDelete("/api/tickets/{id:int}",
    async Task<Results<NoContent, ValidationProblem>>
    (ISqlDataAccess sql, int id) =>
{
    await sql.SaveDataAsync("dbo.spTickets_Delete",
        new { Id = id }, "TicketDB");
    return TypedResults.NoContent();
});
app.MapDelete("/api/tickets/{id:int}",
    async Task<Results<NoContent, ValidationProblem>>
    (ISqlDataAccess sql, int id) =>
{
    await sql.SaveDataAsync("dbo.spTickets_Delete",
        new { Id = id }, "TicketDB");
    return TypedResults.NoContent();
});

處理器通過Dapper包裝器調用spTickets_Delete儲存過程,並傳遞包含ID的匿名物件。 返回TypedResults.NoContent()產生204狀態,表示操作成功且無返回正文。 返回型別聲明模仿前一集的PUT端點,因為從框架的角度看,兩種操作都有相同的一組可能結果。

修正參數大寫不匹配

[2:14 - 4:32] 在連接DELETE呼叫時,Tim注意到他在系列中早期引入的不一致。 Id = id賦值。 Id。 但,提供GET按ID端點的過程id。 那個小寫變體使得原始處理器在不顯式賦值的情況下通過new { id },在當時感覺很方便但卻使程式碼不一致。

與其讓不對稱性延續下去,他打開了SQL Server Management Studio,並修改GET過程以使用大寫Id

ALTER PROCEDURE spTickets_Get
    @Id int
AS
BEGIN
    SELECT Id, Title, Description, DateCompleted, Priority, CreatedDate
    FROM dbo.Tickets
    WHERE Id = @Id;
END

在過程更新後,Program.cs中的GET處理器現在需要與DELETE和PUT處理器相同的顯式映射,從new { Id = id }。 變更是機械性的,但原因很重要:在儲存過程中保持一致的參數大寫意味著每個端點的參數綁定方式都相同,這消除了稍後閱讀資料存取層時的小但真實的混亂來源。 一個僅在四個地方之一成立的約定不算是約定。

當記錄缺失時返回204 vs. 404

[4:46 - 5:46] 在端點編譯後,Tim停下來對每次DELETE實現時出現的設計問題進行思考。 如果呼叫者傳遞一個不存在的ID,API應該返回什麼? 有兩個合理的答案。

無論是否刪除行,返回204 NoContent將請求視為冪等的。 從呼叫者的角度來看,資源已消失,這正是目標。 這是當前處理器所做的,也是Tiny Ticket專案將要提供的。 對於缺失記錄返回404 NotFound為呼叫者提供了更多資訊,但需要儲存過程報告實際上是否刪除了行,通常通過返回行數使處理器在決定返回哪個響應前進行檢查。

對於前端已知哪些ID存在的內部CRUD API(因為它剛載入了列表),204就可以。對於使用者可能猜測ID的公開API,404可以防止當資料從未存在時產生沉默的錯覺。 Tim提到返回404可能會泄露資料庫中哪些ID存在的資訊,不過對於刪除操作來說,實際風險很低,因為行使端點已經意味著有寫入權限。

通過Swagger測試

[5:46 - 7:08] 當資料庫運行時,Tim啟動API並打開Swagger。 他從GET全部開始,以了解當前資料狀況:來自原始種子的記錄1、2、3,加上來自早期插入測試的107、109和110。

他對107執行DELETE,返回204。110也是如此。為了驗證缺失記錄行為,他對1011執行DELETE,這是一個從未在資料庫中的ID。 響應仍然是204,沒有表明未刪除任何內容。 這就是上一節討論的權衡,現在可以在實際API響應中看到。

第二次GET全部確認了最終狀態:記錄1、2、3和109保留。 DELETE端點在有效ID上運行,對無效ID靜默失敗,正如實現所規定。

總結:CRUD完成

[7:08 - 8:38] 新增DELETE完成Tiny Ticket API的四個CRUD動詞。 每個端點都貫徹相同的結構模式:路由定義、儲存過程名稱、Dapper資料存取調用、型別化結果。 Tim坦言,一個生產API可能會新增更多端點,例如一個PATCH,用於在不傳輸整個物件的情況下將標籤標記為完成,或專用的搜索端點。 然而,系列的目標是讓每個層次保持專注,以便下一層(前端)有一個清晰的表面可以調用。

一致性使得專案讀起來讓人舒適。 Dapper包裝器、POST插入模式驗證管道和型別化結果結合在一起,使得每個新的端點無論實現了哪個動詞都用大致相同數量的程式碼。 這種可預測性使得API成為接下來的前端工作一個令人愉悅的目標。

結論

[8:38 - 8:40] 在一個簡化API中新增DELETE端點需要在路徑中有ID段的TypedResults.NoContent()返回。 該端點完成Tiny Ticket專案的CRUD表面,並為系列的下一階段轉向前端奠定基礎。

系列導航: 這篇文章是C# on Linux系列的一部分,構建Tiny Ticket應用程式。以前:新增PUT更新端點。 下一階段:使用API的前端頁面。

範例提示:如果您想要在不改變儲存過程的情況下有一個更具資訊性的DELETE響應,請從TypedResults.NotFound()。 這樣在不重構資料存取層的情況下新增了404路徑。

在他的YouTube頻道上觀看完整的影片,深入了解在C# on Linux系列中構建CRUD端點。

Hero Worlddot related to 在Linux上新增.NET Aspire中的DELETE端點
Hero Affiliate related to 在Linux上新增.NET Aspire中的DELETE端點

分享您所愛以賺取更多報酬

您是否為使用 .NET、C#、Java、Python 或 Node.js 的開發者建立內容?將您的專業知識轉化為額外收入!

Iron 支援團隊

我們線上24小時,每週5天。
聊天
電子郵件
給我打電話