ASP.NET Coreでリクエストの入力値を検証する
APIがJSONを受け取れても、その値が処理に使えるとは限りません。商品名が空、価格が負の値といった入力を、保存前に検証します。
DTOへ条件を書く
using System.ComponentModel.DataAnnotations;
public sealed class CreateProductRequest
{
[Required]
[StringLength(100, MinimumLength = 1)]
public string Name { get; init; } = string.Empty;
[Range(0, 1_000_000)]
public int Price { get; init; }
}[ApiController]を付けたControllerでは、モデル検証に失敗するとAction実行前に400応答が返ります。
[ApiController]
[Route("api/products")]
public sealed class ProductsController : ControllerBase
{
[HttpPost]
public IActionResult Create([FromBody] CreateProductRequest request)
=> Ok(new { request.Name, request.Price });
}失敗する入力を試す
{"name":"","price":-1}をPOSTすると、名前の必須条件と価格の範囲条件に違反します。Actionの中へブレークポイントを置いても到達しないことを確認できます。[ApiController]の自動応答を使う場合、通常はAction内にif (!ModelState.IsValid)を繰り返し書く必要はありません。
一方、int Priceを省略すると既定値の0になり、この例の[Range(0, ...)]には合格します。省略そのものを拒否したい場合はint?にして[Required]を付けるなど、型と検証条件を要件に合わせて設計します。
必須と空白を区別する
[Required]はnullや空文字を拒否しますが、空白だけの文字列を許すかはAPIの仕様として確認してください。空白を取り除いた後の値で判定したい場合は、明示的な検証を加えます。
なお、属性による検証は単一項目の形式・範囲に向いています。「終了日は開始日より後」など複数項目の関係や、在庫・権限のようにDBを参照する条件は、別の検証処理で扱います。
APIの検証は利用者へ分かりやすいエラーを返すためのものです。同時登録による重複や参照整合性は、データベース側でも保証します。