zukucode
主にWEB関連の情報を技術メモとして発信しています。

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の検証は利用者へ分かりやすいエラーを返すためのものです。同時登録による重複や参照整合性は、データベース側でも保証します。


関連記事