ASP.NET Core NativeAOT ํŠธ๋ผ์ด

aspnetcore nativeaot๋ฅผ ํ•œ๋ฒˆ ๋งŒ๋“ค์–ด ๋ดค๋Š”๋ฐ ์• ์ดˆ์— ์ž…๋ฌธ์ž์ด๊ธฐ๋„ ํ•˜์ง€๋งŒ ๋ชฐ๋ž๋˜ ๊ธฐ๋Šฅ์ด ๋งŽ์ด ์ƒ๊ฒผ๋„ค์š”. ์•„๋ž˜ ๋‚ด์šฉ์€ nativeaot๋ž‘ ๋ฌด๊ด€ํ•˜๊ฒŒ aspnetcore์— ๋Œ€ํ•ด์„œ ๋ชฐ๋ž๋˜ ๊ธฐ๋Šฅ์„ ์ ์–ด ๋†“์€ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

OpenAPI

OpenAPI ๋ผ๋Š” ๊ฒŒ ์ƒ๊ฒจ์„œ SwaggerUI๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ API Document๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก  ์ด์˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

image

SwaggerUI์ฒ˜๋Ÿผ ๋งํฌ๋กœ ์ ‘๊ทผํ•˜๋ฉด ์œ„์™€ ๊ฐ™์€ ์‹์œผ๋กœ ๋‚˜์˜ต๋‹ˆ๋‹ค.
App์„ Buildํ•˜๊ธฐ ์ „์—

builder.Services.AddOpenApi("api_index_document");

์ด๊ฑฐ ํ•œ๋ฒˆ, Build ์ดํ›„์—

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi().CacheOutput();
}

์ด๋ ‡๊ฒŒํ•˜๋ฉด ๋์ด๋„ค์š”. ์ด๊ฑด SwaggerUI๋ž‘ ๋˜‘๊ฐ™์ง€๋งŒโ€ฆ

์œ„ ๋งํฌ์— ๊ฐ€๋ฉด API ๋ฌธ์„œ์˜ ์ด๋ฆ„์„ ์ง€์ •ํ•˜๊ณ , Endpoints๋ฅผ ์–ด๋””๋กœ ์žก์„ ์ง€ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

.http ํŒŒ์ผ

ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋‹ˆ๊นŒ

image

์ด๋Ÿฐ ํŒŒ์ผ์ด ์ƒ๊ฒจ์„œ ๋ณด๋‹ˆ๊นŒ ์ด ํŒŒ์ผ์— Test๋ชฉ์ ์˜ Endpoints๋ฅผ ์ ์–ด๋†“์œผ๋ฉด Postman, curl ๊ฐ™์€ ๊ฒŒ ์—†์ด๋„ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ฒ„ํŠผ ๋ˆŒ๋Ÿฌ์„œ ํ™•์ธํ•ด๋ณผ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

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

Json Response

Json ์‘๋‹ต์— ๋Œ€ํ•ด์„œ ์ฒ˜๋ฆฌ๊ฐ€ ์กฐ๊ธˆ ๋‹ฌ๋ž์Šต๋‹ˆ๋‹ค.

๊ธฐ์กด aspnetcore

var gameDataResponse = await HttpClient.GetAsync(uriBuilder.Uri);
gameDataResponse.EnsureSuccessStatusCode();
var realmindex = await gameDataResponse.Content.ReadFromJsonAsync<ResRealmIndex>();

NativeAOT

์•„๋ž˜์™€ ๊ฐ™์ด ๋ณ€๊ฒฝํ•ด์•ผํ–ˆ์Šต๋‹ˆ๋‹ค.

var gameDataResponse = await HttpClient.GetAsync(uriBuilder.Uri);
gameDataResponse.EnsureSuccessStatusCode();
var realmindex_str = await gameDataResponse.Content.ReadAsStringAsync();
var realmindex = JsonSerializer.Deserialize(realmindex_str, SourceGenerationContext.Default.ResRealmIndex);
namespace VincentBattleNetApiServer.Core;

using VincentBattleNetApiServer.Core.DTOs.Res;

[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(BattlenetAccessToken))]
[JsonSerializable(typeof(ResRealm))]
[JsonSerializable(typeof(ResRealmIndex))]
public partial class SourceGenerationContext : JsonSerializerContext
{
}

์ด๋Ÿฐ ์‹์œผ๋กœ System.Text.Json์„ ์ด์šฉํ•ด์„œ Source Generator๋ฅผ ์ด์šฉํ•ด์„œ ์ฒ˜๋ฆฌํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

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

.NET 8๋ถ€ํ„ฐ aspnetcore ๊ธฐ๋ณธ ํฌํŠธ๊ฐ€ 8080์œผ๋กœ ๋ณ€๊ฒฝ๋จ.

์•„๋ฌด๊ฒƒ๋„ ์•ˆํ–ˆ๋Š”๋ฐ ํฌํŠธ๊ฐ€ ์•Œ์•„์„œ 8080์œผ๋กœ ์žกํžˆ๊ธธ๋ž˜ ๊ฒ€์ƒ‰ํ•ด๋ณด๋‹ˆ ์ด๋Ÿฐ ๊ฒŒ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

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

OpenApi ๋Š” ๋ง ๊ทธ๋Œ€๋กœ ๊ณต๊ฐœ api ์„œ๋น„์Šค์— ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฏ€๋กœ, ๊ณต๊ฐœ Api ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด, ๋ฐฐํฌ ์ฝ”๋“œ์—์„œ ์ง€์›Œ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

if (builder.Environment.IsDevelopment())
{
    builder.Services.AddOpenApi();
}

// ...
var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
};
// ...

๊ทธ๋Ÿผ์—๋„ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์œ ์šฉํ•œ ๋ถ€๋ถ„์ด ์žˆ์Šต๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŒ…

Api์˜ ๋™์ž‘์„ ํ…Œ์ŠคํŠธ ํ•  ๋•Œ, PostMan ๊ณผ ๊ฐ™์€ ์ „๋ฌธ ํด๋ผ์ด์–ธํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๊ณ , .http ํŒŒ์ผ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, Swagger Ui ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์ด ๊ฐ€์žฅ ๊ฐ„ํŽธํ•˜๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

.Net 8.0 ๊นŒ์ง€๋Š” Swashbuckle ์ด ๊ณต์‹ Swagger Ui ๋„๊ตฌ์˜€๋Š”๋ฐ, .Net 9.0 ๋ถ€ํ„ฐ๋Š” ๊ธฐ์กด์˜ Swashbuckle ๋Œ€์‹ , SwaggerUI ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
์ด ํŒจํ‚ค์ง€ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ๋‹ค๋ฅธ UI ๋„๊ตฌ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํด๋ผ์ด์–ธํŠธ ์ƒ์„ฑ

OpenApi ๋ฌธ์„œ์˜ ๋‹ค๋ฅธ ํšจ์šฉ์€ ํด๋ผ์ด์–ธํŠธ๋ฅผ ํ‘œ์ค€ํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.

๋‹ท๋„ท์—์„œ๋Š” NSwag ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, OpenApi ๋ฌธ์„œ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ Api ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ์„œ๋น„์Šค ๊ฐ์ฒด์™€ ๊ด€๋ จ ๋ฐ์ดํ„ฐ ๋ชจ๋ธ์„ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ด๋Š” EF Core ์˜ Db-First ์ ‘๊ทผ๋ฒ•๊ณผ ์œ ์‚ฌํ•œ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

nodejs ์„œ๋ฒ„๋“  kestrel ์„œ๋ฒ„๋“ , openapi ๋ฌธ์„œ๋งŒ ์ œ๊ณตํ•ด์ฃผ๋ฉด, ์œ„ ๋„๊ตฌ๋กœ ๋‹ท๋„ท ๋˜๋Š” ๋‹ค๋ฅธ ์–ธ์–ด์˜ ํด๋ผ์ด์–ธํŠธ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์ฃ .

์ง์ ‘ ์‹œ๋„ํ•ด ๋ดค๋Š”๋ฐ, ์‹œ์Šคํ…œ์˜ ๋ชจ๋“  ์•ฑ์ด ๋‹ท๋„ท์œผ๋กœ ์ž‘์„ฑ๋œ ๊ฒฝ์šฐ์—๋Š”, ์ƒ์„ฑ๋œ ๊ฐ์ฒด๋“ค์ด ๋ญ”๊ฐ€ ๋ถˆํŽธํ•˜์ง€๋งŒ, ๋‹ค๋ฅธ ์–ธ์–ด๋กœ ์ž‘์„ฑ๋œ api ์— ์ ‘๊ทผํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ๋ฅผ ๋‹ท๋„ท์œผ๋กœ ์ž‘์„ฑํ•˜๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด, ์ฝ”๋“œ๋Ÿ‰์„ ์ƒ๋‹นํžˆ ๋งŽ์ด ์ค„์—ฌ์ฃผ๋Š” ์ด์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ๊ฒฌ์œผ๋กœ๋Š”, ๋น„๊ณต๊ฐœ api ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒฝ์šฐ๋ผ๋„, open api ๋ฌธ์„œ๋ฅผ ๋ณ„๋„์˜ ํŒŒ์ผ๋กœ ์ƒ์„ฑํ•ด๋‘๋Š” ํŽธ์ด ๋‚˜์ค‘์— ๋„์›€์ด ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์‹œ์Šคํ…œ์ด ์„ฑ๊ณต์ ์ด๋ฉด, ๋ˆ„๊ตฐ๊ฐ€๋Š” api ์— ์ ‘๊ทผ์„ ์›ํ•  ๊ฒƒ์ด๊ณ , ๊ทธ ๊ฒฝ์šฐ์— ๋งŒ๋“ค์–ด ๋‘” open api ๋ฌธ์„œ๋ฅผ ์ œ๊ณตํ•˜๋ฉด, ํด๋ผ์ด์–ธํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ์ธก์˜ ์—…๋ฌด๊ฐ€ ๋งŽ์ด ํšจ์œจ์ ์ด๊ฒŒ ๋˜๊ณ , ๊ทธ ๋งŒํผ ์ง€์›ํ•  ๊ฑฐ๋ฆฌ๋„ ์ ์–ด์ง€๋‹ˆ๊นŒ์š”.

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

openapi๋Š” .net 9์—์„œ ๋˜ ๋ฐ”๋€Œ์ฃ 

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

๋งž์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ OpenAPI ์ž์ฒด๋Š” ์˜ˆ์ „ ๋‹ท๋„ท ํ”„๋ ˆ์ž„์›Œํฌ ์ดˆ์ฐฝ๊ธฐ ๋•Œ ๋งŽ์ด ํ†ต์šฉ๋˜๋˜ WSDL ๊ธฐ๋ฐ˜ XML ์›น ์„œ๋น„์Šค์˜ ํ˜„๋Œ€์  ํ•ด์„์œผ๋กœ ๋ณผ ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. (๋ฌผ๋ก  ๊ทธ ๋•Œ๋Š” Java ์ธก WSDL ๊ตฌํ˜„๊ณผ ๋‹ท๋„ท ์ธก WSDL ๊ตฌํ˜„์ด ๋‹ฌ๋ผ์„œ ํ˜ธํ™˜์„ฑ์ด ์ข‹์ง€ ์•Š์•˜์—ˆ์Šต๋‹ˆ๋‹ค.)

Google์˜ ๊ฒฝ์šฐ์—๋Š” ๋ณธ์ธ๋“ค์ด ์ œ๊ณตํ•˜๋Š” ์„œ๋น„์Šค์˜ OpenAPI ์ŠคํŽ™์„ ์ •๊ตํ•˜๊ฒŒ ์„ค๊ณ„ํ•ด์„œ ๊ฐ์ข… ์–ธ์–ด๋ณ„ SDK ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ œ์ž‘ ์ž์ฒด๋ฅผ ์ž๋™ํ™”ํ•˜๋Š” ๊ฒƒ์œผ๋กœ๋„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. OpenAPI์— ํˆฌ์žํ•  ์ˆ˜ ์žˆ๋Š” ์—ฌ๋ ฅ์ด๋‚˜ ์—ฌ๊ฑด์ด ์ถฉ๋ถ„ํ•˜๋‹ค๋ฉด ๊ฝค ํฅ๋ฏธ๋กœ์šด ์ ‘๊ทผ ๋ฐฉ์‹์ผ ์ˆ˜ ์žˆ๊ฒ ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค. :smiley:

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