재우니의 블로그

https://code-maze.com/graphql-aspnetcore-basics/

 

Getting Started with GraphQL in ASP.NET Core - Code Maze

In this article we are going to learn about GraphQL in ASP.NET Core integration, how to start with the project and how to create a first GraphQL query.

code-maze.com

ASP.NET Core application 에서 GraphQL을 설정하는 방법을 배웁니다. 이 통합을 보다 쉽게 하기 위해 다른 타사 라이브러리를 사용하고 GraphQL elements  (Type, QuerySchema)를 사용하여 ASP.NET Core에서 GraphQL의 통합 process를 완성하는 방법을 자세히 설명 할 것입니다.

 

소스 코드를 다운로드하려면 해당 링크를 선택해 주세요.

 

GraphQL in ASP.NET Core Project Source Code.

 

CodeMazeBlog/graphql-series

This repository contains the code for the GraphQL series on Code Maze - CodeMazeBlog/graphql-series

github.com

 

이 튜토리얼의 전체 탐색을 보려면 해당 링크를 선택해 주세요.

 

GraphQL ASP.NET Core Tutorial.

 

GraphQL ASP.NET Core Tutorial - Code Maze Blog

Learn to work with GraphQL ASP.NET Core integration, write querires and mutations and how to create ASP.NET Core and Angular app to consume GrphQL API.

code-maze.com

 

 

다음과 같은 섹션으로 나누었습니다:

1. REST 와 GraphQL 의 차이점에 대해 알아보자.
2. ASP.NET Core Web API 프로젝트를 처음 시작하시는 분들에게 소개하기.
3. GraphQL 을 .NET Core 에 통합하기
4. 결론

 

 

REST 와 GraphQL 의 차이점에 대해 알아보자.

 

 

GraphQl 은 query language 입니다. data 에 대해 정의한 type systems 을 사용하여 queries 를 실행합니다. GraphQL은 특정 언어나 데이터베이스와 관련이 없으며 코드와 데이터에도 적용 할 수 있습니다.

 

 

GraphQL이 REST와 어떻게 다른지 이야기 해 봅시다.

  • GraphQL 은 server 간의 roundtrip 을 최소화 하며, view 또는 template page 에서 요청한 모든 데이터를 가져오기 위해 다시 되돌아 갑니다. 반면 REST 는 페이지에서 필요로 한 모든 데이터를 여러번 endpoint 를 통해 방문 해야 합니다. 즉, api/subject, api/professors, api/students ... 이런식 으로 말이죠. 하지만 GraphQL 경우에는 그러하지 않습니다. GraphQL 을 사용할 때, server 측에서 여러 함수들을 호출하고 단일 요청으로 다른 리소스의 모든 데이터를 반환하는 하나의 쿼리만 생성합니다.
  • 반면 REST를 사용하면 애플리케이션이 커질수록 endpoints 수도 늘어나고 유지 관리에 더 많은 시간이 필요합니다. 그러나 GraphQL을 사용하면 endpoints 가 오직 하나뿐입니다. api/graphql 이런식으로 말이죠.

 

 

GraphQL을 사용함으로써 Response 에 너무 많은 데이터를 가져오는 이슈가 없습니다. 이는 필요한 것을 나타내는 필드를 쿼리로 정의하기 때문입니다. 따라서 다음과 같은 쿼리를 보내면...

 

query OwnersQuery {
  owners {
    name
    account {
      type
    }
  } 
}

아래와 같은 결과값을 제공해 줍니다.

{
  "data": {
    "owners": [
     {
      "name": "John Doe",
      "accounts": [
        {
          "type": "Cash"
        },
        {
          "type": "Savings"
        }
      ]
     }
    ]
  }
}


REST 에서는 그렇지 않습니다. 때때로 우리는 필요한 것보다 더 많이 얻거나 더 적은 것을 얻습니다. 그것은 특정 endpoint 의 조치가 어떻게 구현되는지에 달려 있습니다.

이것이 REST와 GraphQL의 가장 중요한 차이점입니다. 이제 우리는 GraphQL을 설정하는 방법을 보여주는 기본 프로젝트를 만들어 봅시다.

 

Starter ASP.NET Core Web API Project 소개

 

여기에서 GraphQL ASP.NET Core Starter Project를 다운로드 할 수있는 starter ASP.NET Core 프로젝트를 준비했습니다 . 이 프로젝트를 다운로드하는 것이 좋지만 원하는 경우 직접 만들 수도 있습니다. starter 프로젝트의 구조는 다음과 같습니다.

 

 Contracts 폴더에는 repository 로직에 필요한 interface 가 포함되어 있습니다.

 

namespace GraphQLDotNetCore.Contracts
{
    public interface IOwnerRepository
    {
    }
}
namespace GraphQLDotNetCore.Contracts
{
    public interface IAccountRepository
    {
    }
}

 

Entities 폴더에서 context class 와 seed configuration class 를 가지고 model classes 들이 존재합니다.

public class Owner
{
    [Key]
    public Guid Id { get; set; }
    [Required(ErrorMessage = "Name is required")]
    public string Name { get; set; }
    public string Address { get; set; }

    public ICollection<Account> Accounts { get; set; }
}

 

 

public class Account
{
    [Key]
    public Guid Id { get; set; }
    [Required(ErrorMessage = "Type is required")]
    public TypeOfAccount Type { get; set; }
    public string Description { get; set; }

    [ForeignKey("OwnerId")]
    public Guid OwnerId { get; set; }
    public Owner Owner { get; set; }
}

 

 

public enum TypeOfAccount
{
    Cash,
    Savings,
    Expense,
    Income
}

 

 

public class ApplicationContext : DbContext
{
    public ApplicationContext(DbContextOptions options)
        :base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        var ids = new Guid[] { Guid.NewGuid(), Guid.NewGuid() };

        modelBuilder.ApplyConfiguration(new OwnerContextConfiguration(ids));
        modelBuilder.ApplyConfiguration(new AccountContextConfiguration(ids));
    }

    public DbSet<Owner> Owners { get; set; }
    public DbSet<Account> Accounts { get; set; }
}

 

 

그리고 Repository 폴더에는 데이터 가져오는 로직과 관련된 클래스가 있습니다.

public class OwnerRepository : IOwnerRepository
{
    private readonly ApplicationContext _context;

    public OwnerRepository(ApplicationContext context)
    {
        _context = context;
    }
}

 

 

public class AccountRepository : IAccountRepository
{
    private readonly ApplicationContext _context;

    public AccountRepository(ApplicationContext context)
    {
        _context = context;
    }
}

 

repository logic 에는 별도의 추가적인 layter 없이 기본 setup 을 가지고 있습니다. 그러나 ASP.NET Core의 리포지토리 패턴에 대한 자세한 내용을 보려면 ASP.NET 코어 웹 API – 리포지토리 패턴 을 읽으십시오 .


context classrepository classes Startup.cs class 내부에 등록됩니다.

 

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationContext>(opt =>
        opt.UseSqlServer(Configuration.GetConnectionString("sqlConString")));

    services.AddScoped<IOwnerRepository, OwnerRepository>();
    services.AddScoped<IAccountRepository, AccountRepository>();

    services.AddControllers()
        .AddNewtonsoftJson(o => o.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
}

 

 

따라서 이 시점에서 appsettings.json 파일에서 연결 문자열을 본인의 database 에 맞게 수정하고 패키지 관리자 콘솔 로 이동하여 update-database 명령을 실행하면 해당 database 에 테이블이 자동 생성되어 집니다. (이를 Code-First 접근법 이라고 합니다.)

 

 

ASP.NET Core 에서 GraphQL 통합하기

 

 

GraphQL 지원은 ASP.NET Core applications 자체 내에서 제공되지 않으므로 몇 가지 라이브러리를 설치해야합 니다. 따라서 설치할 첫 번째 라이브러리는 GraphQL을 NuGet 패키지 관리자를 통해 설치할 수 있습니다.

 

또한 패키지 관리자 콘솔을 사용할 수 있습니다. PM> Install-Package GraphQL -Version 2.4.0

우리가 설치하려는 두 번째 라이브러리는 GraphQL.Server.Transports.AspNetCoreGraphQL.NET 이며, 종속성으로 얻는 데 도움이 됩니다.

패키지 관리자 명령 : PM> Install-Package GraphQL.Server.Transports.AspNetCore -Version 3.4.0

마지막으로, 우리는 GraphQL.Server.Ui.Playground 를  쿼리를 서버로 보내는데 도움이 되는 libraryGraphQL 을 설치 합니다.

 

패키지 관리자 명령 : PM> Install-Package GraphQL.Server.Ui.Playground -Version 3.4.0

 

 

GraphQL 특정 객체 만들기 (Type, Query, Schema)

 

 

GraphQL 이라는 새로운 폴더를 생성하고, GraphQLSchema 안에 AppSchema.cs클래스를 추가합니다.

public class AppSchema : Schema
{
    public AppSchema(IDependencyResolver resolver)
        :base(resolver)
    {
 
    }
}

 

이 클래스는 GraphQL.Types 네임 스페이스에있는 Schema 클래스에서 상속해야합니다. 생성자 내부에 IdependencyResolver를 삽입하면 Query, Mutation 또는 Subscription 객체를 해결하는 데 도움이됩니다. 알아야 할 중요한 것은 각 스키마 속성 (Query, Mutation 또는 Subscription)이 IObjectGraphType을 구현한다는 것입니다. 즉, 해결하려는 객체도 동일한 유형을 구현해야합니다. 또한 GraphQL API는 모델을 결과로 직접 반환 할 수 없지만 대신 IObjectGraphType을 구현하는 GraphQL 유형을 반환 할 수 있습니다. 이제이 클래스를 잠시두고 GraphQL 폴더 안에 단일 클래스 OwnerType.cs가있는 새 폴더 GraphQLTypes를 만듭니다.

 

public class OwnerType : ObjectGraphType<Owner>
{
    public OwnerType()
    {
        Field(x => x.Id, type: typeof(IdGraphType)).Description("Id property from the owner object.");
        Field(x => x.Name).Description("Name property from the owner object.");
        Field(x => x.Address).Description("Address property from the owner object.");
    }
}

 

이것은 GraphQL API 내부의 Owner 모델을 대체하기 위해 사용하는 OwnerType 클래스입니다. 이 클래스는 일반적인 ObjectGraphType <Owner> 클래스에서 상속하며,이 클래스는 어느 시점에서 (계층 구조에서) IObjectGraphType 인터페이스를 구현합니다.

 

Field 메소드를 사용하여 Owner 모델 클래스의 속성을 나타내는 필드를 지정합니다. 계속 진행하려면 GraphQL 폴더 안에 AppQuery 클래스를 사용하여 다른 폴더 GraphQLQueries를 만들어 보겠습니다. 이 클래스를 수정하기 전에 IOwnerRepository 인터페이스를 수정 해 보겠습니다.

 

public interface IOwnerRepository
{
    IEnumerable<Owner> GetAll();
}

 

OwnerRepository class

public class OwnerRepository : IOwnerRepository
{
    private readonly ApplicationContext _context;

    public OwnerRepository(ApplicationContext context)
    {
        _context = context;
    }

    public IEnumerable<Owner> GetAll() => _context.Owners.ToList();
}

 

이제 변경 사항을 반영하도록 AppQuery 클래스를 수정할 수 있습니다.

public class AppQuery : ObjectGraphType
{
    public AppQuery(IOwnerRepository repository)
    {
        Field<ListGraphType<OwnerType>>(
           "owners",
           resolve: context => repository.GetAll()
       );
    }
}

 


AppQuery 설명

 

 

보시다시피이 클래스는 ObjectGraphType에서도 상속받지 않습니다. 또한 생성자 내에 리포지토리 개체를 주입하고 특정 쿼리에 대한 결과를 반환하는 필드를 만듭니다. 이 클래스에서는 "strange"유형을 일반 매개 변수로 허용하는 Field 메소드의 일반 버전을 사용합니다. 이것은 일반적인 .NET 타입에 대한 GraphQL.NET 표현입니다. 따라서 ListGraphType은 List 유형의 표현이며, 물론 IntGraphType 또는 StringGraphType 등이 있습니다. 전체 목록을 보려면 GraphQL .NET의 SchemaTypes를 방문하십시오. "소유자"매개 변수는 필드 이름 (클라이언트의 조회는이 이름과 일치해야 함)이며 두 번째 매개 변수는 결과 자체입니다. 준비를 마쳤으므로 이제 AppSchema 클래스를 수정할 수 있습니다.

 

public class AppSchema : Schema
{
    public AppSchema(IDependencyResolver resolver)
        :base(resolver)
    {
        Query = resolver.Resolve<AppQuery>();
    }
} 

그 다음, 스키마 등록을 진행하겠습니다.

 

 

라이브러리 및 스키마 등록

 

 

Startup 클래스에서는 설치된 라이브러리와 생성 된 스키마 클래스도 등록해야합니다. 따라서 ConfigureServices 및 Configure 메소드를 수정하여 이를 수행하십시오.

 

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationContext>(opt =>
        opt.UseSqlServer(Configuration.GetConnectionString("sqlConString")));

    services.AddScoped<IOwnerRepository, OwnerRepository>();
    services.AddScoped<IAccountRepository, AccountRepository>();

    services.AddScoped<IDependencyResolver>(s => new FuncDependencyResolver(s.GetRequiredService));
    services.AddScoped<AppSchema>();

    services.AddGraphQL(o => { o.ExposeExceptions = false; })
        .AddGraphTypes(ServiceLifetime.Scoped);

    services.AddControllers()
        .AddNewtonsoftJson(o => o.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);

    services.Configure<KestrelServerOptions>(options =>
    {
        options.AllowSynchronousIO = true;
    });
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    
    app.UseHttpsRedirection();

    app.UseRouting();

    app.UseAuthorization();

    app.UseGraphQL<AppSchema>();
    app.UseGraphQLPlayground(options: new GraphQLPlaygroundOptions());

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

ConfigureServices 메소드에서 DependencyResolver (조회 용)와 스키마 클래스도 등록합니다. 또한 AddGraphQL 메소드에 GraphQL을 등록하고 AddGraphTypes 메소드에 모든 GraphQL 유형 (Query 및 Type 클래스)을 등록합니다. 이 방법이 없으면 모든 유형과 쿼리를 API에 수동으로 등록해야 합니다. 마지막으로, Configure 메소드에서 우리는 스키마를 요청의 파이프 라인과 우리가 사용하려는 Playground UI 도구에 추가합니다.

 

 

첫 번째 쿼리 보내기

 

 

GraphQL API를 테스트하기 위해 GraphQL.UI.Playground 도구를 사용할 것입니다. 먼저 서버 응용 프로그램을 시작한 다음 https://localhost:5001/ui/playground 주소로 이동하십시오.

 

훌륭합니다. 모든 것이 예상대로 작동한다는 것을 알았습니다. “소유자”(AppQuery 파일에서 생성 한 쿼리 이름과 일치해야 함)라는 이름으로 쿼리를 보내자 마자 필요한 결과를 얻습니다.

 

 

결론

 

 

완료되었습니다. 우리는 GrapnQL 을 ASP.NET Core에 통합하는 몇 가지 쉬운 단계와 쿼리로 필요한 결과를 검색하는 방법을 보았습니다. 다음 기사에서는 고급 GraphQL 쿼리, 쿼리 중 오류를 처리하는 방법 및 데이터 로더를 사용하여 결과를 캐시하는 방법에 대해 설명합니다.

https://code-maze.com/advanced-graphql-queries/

 

Advanced GraphQL Queries, Error Handling, Data Loader - Code Maze

In this article we are going to learn how to write advanced GraphQL Queries, how to handle erros and optimize queries by using data loader.

code-maze.com