연습 - EF Core를 최소 API에 추가

완료됨

회사의 개발자인 여러분은 새로운 최소 API에 대해 들어 보았습니다. 관리자가 여러분에게 다음 프로젝트에서 사용할지 말지를 알아볼 수 있도록 최소 API 프로젝트를 만들어 보라고 합니다.

참고

이 모듈에서는 로컬 개발에 .NET CLI(명령줄 인터페이스) 및 Visual Studio Code를 사용합니다. 이 모듈을 완료하면 Visual Studio(Windows), Mac용 Visual Studio(macOS) 또는 Visual Studio Code(Windows, Linux 및 macOS)를 사용한 연속 개발을 사용하여 개념을 적용할 수 있습니다.

이 모듈에서는 .NET 8.0 SDK를 사용합니다. 기본 설정 터미널에서 다음 명령을 실행하여 .NET 8.0이 설치되어 있는지 확인합니다.

dotnet --list-sdks

다음 예제와 유사한 출력이 표시됩니다.

6.0.317 [C:\Program Files\dotnet\sdk]
7.0.401 [C:\Program Files\dotnet\sdk]
8.0.100 [C:\Program Files\dotnet\sdk]

8으로 시작하는 버전이 나열되어 있는지 확인합니다. 나열되는 버전이 없거나 명령을 찾을 수 없는 경우 최신 .NET 8.0 SDK를 설치합니다.

프로젝트 설정

먼저 프로젝트를 만들어야 합니다. .NET 6을 설치했으며 사용할 준비가 되었습니다. 이 단원에서는 피자 관리 API에 데이터 지속성을 추가합니다.

  1. 터미널에서 dotnet new를 실행하여 웹 API를 만듭니다.

    dotnet new web -o PizzaStore -f net8.0
    

    PizzaStore 디렉터리가 표시됩니다.

  2. 다음 명령을 입력하여 PizzaStore 디렉터리로 이동합니다.

    cd PizzaStore
    
  3. Swashbuckle 패키지를 설치합니다.

    dotnet add package Swashbuckle.AspNetCore --version 6.5.0
    
  4. Visual Studio Code에서 프로젝트를 엽니다.

  5. Visual Studio Code를 사용하여 프로젝트 루트에 Db.cs라는 파일을 만들고 다음 콘텐츠를 제공합니다.

    namespace PizzaStore.Models 
    {
        public class Pizza
        {
              public int Id { get; set; }
              public string? Name { get; set; }
              public string? Description { get; set; }
        }
    }
    

    이전 Pizza 클래스는 피자를 나타내는 간단한 개체입니다. 이 코드는 데이터 모델입니다. 나중에 EF(Entity Framework) Core를 사용하여 이 데이터 모델을 데이터베이스 테이블에 매핑합니다.

  6. Program.cs를 열고 강조 표시된 코드를 추가합니다.

    using Microsoft.OpenApi.Models;
    
    var builder = WebApplication.CreateBuilder(args);
    
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen(c =>
    {
         c.SwaggerDoc("v1", new OpenApiInfo {
             Title = "PizzaStore API",
             Description = "Making the Pizzas you love",
             Version = "v1" });
    });
    
    var app = builder.Build();
    if (app.Environment.IsDevelopment())
    {
       app.UseSwagger();
       app.UseSwaggerUI(c =>
       {
          c.SwaggerEndpoint("/swagger/v1/swagger.json", "PizzaStore API V1");
       });
    }
    
    app.MapGet("/", () => "Hello World!");
    
    app.Run();
    

    Visual Studio Code에서 프로젝트를 디버그하기 위해 자산을 추가하라는 프롬프트가 표시될 수 있습니다. 대화 상자에서 Yes를 선택합니다.

프로젝트에 EF Core 추가

항목을 할 일 목록에 저장하려면 EntityFrameworkCore.InMemory 패키지를 설치합니다.

  1. Ctrl + '를 눌러 Visual Studio Code에서 터미널을 엽니다. 터미널 창에서 다음 코드를 입력하여 EF Core InMemory 패키지를 추가합니다.

    dotnet add package Microsoft.EntityFrameworkCore.InMemory --version 8.0
    
  2. Program.csPizza.cs 파일의 맨 위에 using Microsoft.EntityFrameworkCore;를 추가합니다.

    이제 프로젝트에 EF Core를 추가했으므로 원하는 데이터에 코드를 연결하여 데이터를 저장하고 쿼리할 수 있습니다. 이 단계를 수행하려면 PizzaDb 클래스를 만듭니다. PizzaDb 클래스는 다음 작업을 수행합니다.

    • 데이터베이스의 Pizza 목록에서 Pizzas 속성을 노출합니다.
    • UseInMemoryDatabase를 사용하여 메모리 내 데이터베이스 스토리지를 연결합니다. 데이터는 앱이 실행되는 동안에는 여기에 저장됩니다.
  3. 메모리 내 데이터베이스를 설정하려면 Pizza.cs 파일 하단에 다음 코드를 추가합니다(마지막 } 위에). PizzaStore.Models 네임스페이스 내에 두 개의 클래스 정의가 있습니다.

    class PizzaDb : DbContext
    {
        public PizzaDb(DbContextOptions options) : base(options) { }
        public DbSet<Pizza> Pizzas { get; set; } = null!;
    }
    

    DbContext는 데이터베이스에서 엔터티 인스턴스를 쿼리하고 저장하는 데 사용되는 연결 또는 세션을 나타냅니다.

  4. Program.cs 파일의 상단에 using PizzaStore.Models;를 추가합니다.

  5. Program.cs에서 AddSwaggerGen 호출 앞에 다음 코드를 추가합니다.

    builder.Services.AddDbContext<PizzaDb>(options => options.UseInMemoryDatabase("items"));
    

항목 목록 반환

  • 피자 목록의 항목 목록에서 읽으려면 app.Run(); 호출 위에 다음 코드를 추가하여 “/pizzas” 경로를 추가합니다.

    app.MapGet("/pizzas", async (PizzaDb db) => await db.Pizzas.ToListAsync());
    

애플리케이션 실행

  1. 모든 변경 내용을 저장했는지 확인합니다. 터미널에서 dotnet run을 호출하여 앱을 실행합니다. 이 작업은 앱을 빌드하고 5000~5300의 포트에서 호스트합니다. HTTPS에는 7000~7300 범위의 포트가 선택됩니다.

    참고

    임의 포트 선택 동작을 재정의하려는 경우 launchSettings.json에서 사용할 포트를 설정할 수 있습니다.

    dotnet run
    

    터미널에서 출력은 다음과 같습니다.

    Building...
     info: Microsoft.Hosting.Lifetime[14]
           Now listening on: https://localhost:7200
     info: Microsoft.Hosting.Lifetime[14]
           Now listening on: http://localhost:5100
     info: Microsoft.Hosting.Lifetime[0]
           Application started. Press Ctrl+C to shut down.
     info: Microsoft.Hosting.Lifetime[0]
           Hosting environment: Development
     info: Microsoft.Hosting.Lifetime[0]
           Content root path: /<path>/PizzaStore
    
  2. 브라우저에서 https://localhost:{PORT}/swagger으로 이동합니다. GET /pizzas 단추를 선택한 다음 사용해 보기실행을 선택합니다. Response body 아래에 빈 목록이 표시됩니다.

  3. 터미널에서 Ctrl+C를 눌러 프로그램 실행을 중지합니다.

새 항목 만들기

Pizzas 목록에 대한 POST 새 항목에 코드를 추가해 보겠습니다. Program.cs에서 이전에 만든 app.MapGet 아래에 다음 코드를 추가합니다.

app.MapPost("/pizza", async (PizzaDb db, Pizza pizza) =>
{
    await db.Pizzas.AddAsync(pizza);
    await db.SaveChangesAsync();
    return Results.Created($"/pizza/{pizza.Id}", pizza);
});

API 테스트

모든 변경 내용을 저장하고 앱이 다시 실행되는지 확인합니다. 이제 Swagger UI로 돌아가면 POST/pizza가 표시됩니다. 피자 목록에 새 항목을 추가하는 방법:

  1. POST /pizza를 선택합니다.

  2. 사용해 보기를 선택합니다.

  3. 요청 본문을 다음 JSON으로 바꿉니다.

    {
        "name": "Pepperoni",
        "description": "A classic pepperoni pizza"
    }
    
  4. 실행을 선택합니다.

목록에 있는 항목을 읽는 방법:

  1. GET /pizzas를 선택합니다.

  2. 사용해 보기를 선택합니다.

  3. 실행을 선택합니다.

    Response body에는 방금 추가된 항목이 포함됩니다.

    [
      {
        "id": 1,
        "name": "Pepperoni",
        "description": "A classic pepperoni pizza"
      }
    ]
    
  4. 터미널에서 Ctrl+C를 눌러 앱 실행을 중지합니다. 이 연습의 나머지 부분에서는 변경 내용을 테스트하기 위해 원하는 대로 앱을 중지하고 다시 시작합니다. dotnet run하기 전에 모든 변경 내용을 저장해야 합니다.

단일 항목 가져오기

id를 기준으로 항목을 가져오려면 이전에 만든 app.MapPost 경로 아래에 코드를 추가합니다.

app.MapGet("/pizza/{id}", async (PizzaDb db, int id) => await db.Pizzas.FindAsync(id));

ID별 GET 테스트

이 작업을 테스트하려면 https://localhost:{PORT}/pizza/1로 이동하거나 Swagger UI를 사용할 수 있습니다. 메모리 내 데이터베이스를 사용하기 때문에 애플리케이션을 다시 시작한 경우 이전에 만든 피자가 나열되지 않습니다. 따라서 POST 작업을 사용하여 다시 추가해야 합니다.

항목 업데이트

기존 항목을 업데이트하려면 직접 만든 GET /pizza/{id} 경로 아래에 코드를 추가합니다.

app.MapPut("/pizza/{id}", async (PizzaDb db, Pizza updatepizza, int id) =>
{
      var pizza = await db.Pizzas.FindAsync(id);
      if (pizza is null) return Results.NotFound();
      pizza.Name = updatepizza.Name;
      pizza.Description = updatepizza.Description;
      await db.SaveChangesAsync();
      return Results.NoContent();
});

PUT 테스트

  1. Swagger UI에서 PUT /pizza/{id}를 선택합니다.

  2. 사용해 보기를 선택합니다.

  3. id 텍스트 상자에 1을 입력합니다.

  4. 마지막으로 Request body를 업데이트합니다. 아래 JSON을 붙여넣고 namePineapple로 변경합니다.

    {
       "id": 1,
       "name": "Pineapple"
    }
    
  5. 실행을 선택합니다.

코드를 테스트하려면 GET /pizza/{id}까지 다시 스크롤합니다. 이제 피자 이름은 Pineapple입니다.

항목 삭제

기존 항목을 삭제하려면 이전에 만든 PUT /pizza/{id} 아래에 코드를 추가합니다.

app.MapDelete("/pizza/{id}", async (PizzaDb db, int id) =>
{
   var pizza = await db.Pizzas.FindAsync(id);
   if (pizza is null)
   {
      return Results.NotFound();
   }
   db.Pizzas.Remove(pizza);
   await db.SaveChangesAsync();
   return Results.Ok();
});

DELETE 테스트

이제 Swagger 인터페이스를 사용하여 항목을 삭제해 봅니다.

이 단원에서는 EF Core를 기존 최소 API 애플리케이션에 추가하고 메모리 내 데이터베이스를 사용하여 데이터를 저장했습니다. 지금부터는 애플리케이션 종료 사이에 데이터가 지속되도록 실제 데이터베이스를 사용하여 데이터를 저장하는 방법을 알아봅니다.