Validation support in minimal APIs ์•Œ์•„๋ณด๊ธฐ

๋‹ค๋ฅธ ์ฃผ์ œ๋กœ ๋‚ด์šฉ์ด ๊ธธ์–ด์งˆ ๊ฑฐ ๊ฐ™์•„์„œ ๊ธ€์„ ์ƒˆ๋กœ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

asp.net core 9๊นŒ์ง€ minimal api๋Š” validation ๊ธฐ๋Šฅ์ด ๊ณต์‹์ ์œผ๋กœ ์ œ๊ณต๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๊ฐ€ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‚˜ filter๋ฅผ ํ†ตํ•ด ํ•ด๊ฒฐํ–ˆ์—ˆ๋Š”๋ฐ์š”.

.net 10 ๋ถ€ํ„ฐ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ๊ณต์‹์ ์œผ๋กœ ๊ธฐ๋Šฅ์ด ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.

.net 10 preview 3 ๋ถ€ํ„ฐ ํ…Œ์ŠคํŠธ ํ•ด ๋ณผ ์ˆ˜ ์žˆ์œผ๋ฉฐ ๊ฝค ์œ ์šฉํ•ด ๋ณด์ž…๋‹ˆ๋‹ค. ๋‹ค๋งŒ ์•„์ง๊นŒ์ง€๋Š” ์ผ๊ด€์„ฑ์ด ๋ถ€์กฑํ•œ ์ƒํƒœ์ž…๋‹ˆ๋‹ค.

6๊ฐœ์˜ ์ข‹์•„์š”

interceptor ๊ธฐ๋ฐ˜ ์†Œ์Šค์ œ๋„ค๋ ˆ์ดํ„ฐ์— ์˜์กดํ•˜๊ธฐ ๋•Œ๋ฌธ์— csproj์— ๋‹ค์Œ ๊ตฌ์„ฑ์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

<InterceptorsNamespaces>$(InterceptorsNamespaces);Microsoft.AspNetCore.Http.Validation.Generated</InterceptorsNamespaces>

์‚ฌ์šฉ ๋ฐฉ๋ฒ•์€ ๋งค์šฐ ๋‹จ์ˆœํ•œ๋ฐ์š”.

builder.Services.AddValidation();

DI์— Validation์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ฐ”๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

2๊ฐœ์˜ ์ข‹์•„์š”

minimal api ์ƒ˜ํ”Œ

app.MapPost("minimal", ([FromBody] Dto dto) => dto);

Case 1. RequiredAttribute

public class Dto
{
    [Required]
    public string Required { get; init; }
}

1-1. ๋นˆ BODY ์ „๋‹ฌ

Post /minimal
Accept: application/json
Content-Type: application/json

{
}

.NET 8

200 OK
{
  "required": null
}

.NET 10

400 Bad Request
{
  "title": "One or more validation errors occurred.",
  "errors": {
    "Required": [
      "The Required field is required."
    ]
  }
}

1-2. ๋ช…์‹œ์  null ์ „๋‹ฌ

Post /minimal
Accept: application/json
Content-Type: application/json

{
  "Required": null,
}

.NET 8

200 OK
{
  "required": null
}

.NET 10

400 Bad Request
{
  "title": "One or more validation errors occurred.",
  "errors": {
    "Required": [
      "The Required field is required."
    ]
  }
}

Case 2. RequiredAttribute with Inline initialization

public class Dto
{
    [Required]
    public string Required { get; init; } = "inline"
}

2-1. ๋นˆ BODY ์ „๋‹ฌ

Post /minimal
Accept: application/json
Content-Type: application/json

{
}

.NET 8, 10

200 OK
{
  "required": "inline"
}

2-2 . ๋ช…์‹œ์  null ์ „๋‹ฌ

Post /minimal
Accept: application/json
Content-Type: application/json

{
  "Required": null,
}

.NET 8

200 OK
{
  "required": null
}

.NET 10

400 Bad Request
{
  "title": "One or more validation errors occurred.",
  "errors": {
    "Required": [
      "The Required field is required."
    ]
  }
}
3๊ฐœ์˜ ์ข‹์•„์š”
์ž…๋ ฅ ์กฐ๊ฑด .net 8 .net 10 with validation
[Required] null error
null [Required] null error
[Requred] with inline โ€œinlineโ€ โ€œinlineโ€
null [Requred] with inline null error
5๊ฐœ์˜ ์ข‹์•„์š”

๊ณ„์†ํ•ด์„œ Reflection์„ ๋Œ€์‹ ํ•ด์„œ Source Generator ๊ธฐ๋ฐ˜ ์ธํ”„๋ผ์— ํˆฌ์ž๋ฅผ ๋งŽ์ด ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋‹ท๋„ท ์ฝ”์–ด ์ดˆ๊ธฐ๋ถ€ํ„ฐ ์‹œ์ž‘๋œ DI ์ค‘์‹ฌ์˜ ํŒจ๋Ÿฌ๋‹ค์ž„ ๋ณ€ํ™”์™€ ๋”๋ถˆ์–ด์„œ Source Generator ๊ธฐ๋ฐ˜์˜ ์ฝ”๋“œ ํ™•์žฅ ํŒจ๋Ÿฌ๋‹ค์ž„์— ๋Œ€ํ•ด์„œ๋„ ์ ์ฐจ ๋ฐ‘๊ทธ๋ฆผ์ด ๋ถ„๋ช…ํ•˜๊ฒŒ ๊ทธ๋ ค์ง€๋Š” ๊ฒƒ ๊ฐ™์•„์„œ ์ž˜ ๋ด๋‘˜ ํ•„์š”๊ฐ€ ์žˆ๋Š” ๋ถ€๋ถ„์ด ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. :+1:

7๊ฐœ์˜ ์ข‹์•„์š”

record ๋Š” .net 10 preview 4์—์„œ ์ง€์›ํ•œ๋‹ค๊ณ  ํ•˜๋Š”๊ตฐ์š”.
์•„์ฃผ ์ข‹๋„ค์š”.

์ž”์—ฌ์ด์Šˆ

3๊ฐœ์˜ ์ข‹์•„์š”