.NET Aspire で Linux 上に PUT アップデートエンドポイントを追加する
[[academy-video-youtube({"vid": "hSRI_JKiH5M", "start_time": "0", "title": "Linux上 for .NET AspireでPUT更新エンドポイントを追加する", "creator": "Tim Corey", "length": "8m 43s"})]]
APIがレコードを読み取り、作成できるようになったら、次の操作は既存のものを更新することです。 PUTエンドポイントは、呼び出し元が提供するデータでリソース全体を置き換えるため、リクエスト本文には変更されたものだけでなく、すべてのフィールドが必要です。 PUT(完全置換)とPATCH(部分変更)の違いは、入力タイプを設計する方法、ならびに呼び出し元がエンドポイントとどのようにやり取りするかにとって重要です。
彼のビデオ"Adding a PUT Update Endpoint in .NET Aspire on Linux"で、Tim CoreyはTiny Ticket APIに更新エンドポイントを追加し、挿入レコードにはなかったフィールド(IDや完了日など)を含む専用の更新レコードタイプを作成し、検証属性を適用し、Swaggerを通じたラウンドトリップをテストします。 エピソードは以前のインストールで確立された同じパターンに従いますが、nullableなDateTimeフィールドとPUTとPATCHのセマンティクスの違いを紹介します。 もし最小APIでCRUDエンドポイントを構築しているなら、この記事では更新の側面をカバーしています。
更新レコードタイプの作成
[1:54 - 4:04] 前のエピソードからの挿入レコードは、タイトル、説明、優先度を受け入れました。 更新レコードには、修正対象のチケットのIDとDateCompletedタイムスタンプの2つの追加フィールドが必要です。Timは挿入レコードをコピーして調整します。
public record TicketUpdateRecord(
[Required, Range(1, int.MaxValue)] int Id,
[Required, MinLength(1)] string Title,
[Required] string Description,
DateTime? DateCompleted,
[Range(1, 5)] int Priority
);public record TicketUpdateRecord(
[Required, Range(1, int.MaxValue)] int Id,
[Required, MinLength(1)] string Title,
[Required] string Description,
DateTime? DateCompleted,
[Range(1, 5)] int Priority
);[Range(1, int.MaxValue)]制約を追加することで、データベースに負の値またはゼロが到達するのを防ぎます。 チケットがまだ解決されていない場合は完了日を要求しないため、DateTime?です。 これは無効な状態が許容されるため、検証属性は必要ありません。
記録のプロパティが正確に一致することを確認するために、TimはspTickets_Updateストアドプロシージャからフィールドリストを引き出します。 その整合性により、Dapperはレコードを手動のプロパティとパラメータの配線なしで直接マッピングできます。
PUTエンドポイントのマッピング
[4:04 - 5:44] エンドポイント登録は確立されたパターンに従います。 /api/ticketsルートにバインドされ、ハンドラーは更新記録と共にストアドプロシージャを呼び出します:
app.MapPut("/api/tickets", async Task<Results<NoContent, ValidationProblem>>
(TicketUpdateRecord ticket, ISqlDataAccess sql) =>
{
await sql.SaveDataAsync("dbo.spTickets_Update", ticket, "TicketDB");
return TypedResults.NoContent();
});app.MapPut("/api/tickets", async Task<Results<NoContent, ValidationProblem>>
(TicketUpdateRecord ticket, ISqlDataAccess sql) =>
{
await sql.SaveDataAsync("dbo.spTickets_Update", ticket, "TicketDB");
return TypedResults.NoContent();
});戻り値の型としてResults<NoContent, ValidationProblem>を宣言すると、そのエンドポイントが成功した場合に204を、バリデーションが失敗した場合に400を生成することをフレームワークに伝えます。 ValidationProblemバリアントは、前のエピソードで登録されたパイプラインによって自動的に処理されます; ハンドラー自体は成功ケースを返すだけで構いません。
注目すべきは、Dapperラッパーがデータアクセスを簡潔に保つ方法です:ストアドプロシージャ名、モデル、接続文字列名。 3つのパラメータでデータベースコール全体をカバーします。 ラッパーはシリーズの初期に書かれ、各新しいエンドポイントが修正なしでそれを再利用することで成果を上げ続けています。
PUTとPATCH:完全置換が重要な場合
[6:06 - 6:46] 試験の前に、TimはPUTとPATCHの違いを明確にするために一時停止します。 PUTリクエストはリソース全体を置き換える: リクエストボディ内のすべてのフィールドは、対応するデータベース列を上書きします。呼び出し元が変更するつもりがない場合でも。 PATCHリクエストはボディに含まれるフィールドのみを更新します。
Tiny Ticketプロジェクトの場合、PUTが正しい選択です。なぜなら、フロントエンドが完全なチケットをロードし、ユーザーがフィールドを編集し、完全なオブジェクトを返送するためです。 本番アプリケーションでは、Timは特にチケットを完了済みとしてマークするなど一般的な単一フィールド操作用のPATCHエンドポイントを追加する可能性が高いと述べています。1つの日付を反転させるために全体のオブジェクトを送信するのは無駄に感じます。
Swaggerを通じた更新のテスト
[6:46 - 8:26] Tim launches the API and opens Swagger. PUTをテストする前に、すべてのエンドポイントをGETしてデータの現在の状態を確認します。 テストレコードの1つ(ID 109)は、以前のテストからタイトル、説明、優先度の値が空であります。 それが更新のターゲットになります。
彼はID 109、'Sample Record'というタイトル、説明、および優先度5でPUTリクエスト本文を入力します。実行後、応答は204として返されます。再度GET allを実行すると、レコードが更新された値を持っていることが確認されます。
検証を確認するために、彼はタイトルフィールドをクリアしてもう一度実行します。 応答は構造化されたエラーメッセージとともに400として返されます:"チケットタイトルフィールドは必須です。" 挿入エンドポイントの同じ検証属性が更新レコードに適用されます。なぜなら、彼らは同じ注釈パターンを使用しているからです。
まとめ:CRUDの進捗
[8:26 - 8:43] PUTエンドポイントが完了し、Tiny Ticket APIは4つのCRUD操作のうち3つをカバーします:読み取り(GET allとGET by ID)、作成(POST)、および更新(PUT)。 各エンドポイントは同じ構造パターンに従い、コードベースが予測可能になります。 残された操作はDELETEであり、Timが次のエピソードとしてプレビューします。
結論
[8:38 - 8:43] ミニマルAPIにPUTエンドポイントを追加するには、バリデーション属性を持つ専用の更新記録、コレクションURLとのMapPut登録、データアクセスラッパーを通じたストアドプロシージャコールが必要です。 Results<NoContent, ValidationProblem>戻り値の型により、フレームワークは成功とバリデーション失敗の両方の応答を処理できます。 DateTime?のようなnullableなフィールドは不完全なデータに対して有効な値としてnullが許されるため、バリデーション属性を要求せずに通過します。
シリーズナビゲーション: この記事はC# on Linuxシリーズの一部であり、Tiny Ticketアプリを構築しています。以前: POST挿入エンドポイントの追加。 次: DELETEエンドポイントの追加。
例のヒント:更新ストアドプロシージャが変更された行数を返す場合、204を返す前にそれを確認してください。0のカウントはIDがどのレコードとも一致しなかったことを意味し、静かに成功する代わりに404を返すべきです。
彼のYouTubeチャンネルでフルビデオをご覧いただき、C# on LinuxシリーズでのCRUDエンドポイント構築に関するさらなる洞察を得てください。

