TIL - 20260223

juni·2026년 2월 23일

TIL

목록 보기
276/316

0223 NestJS 기초 (5/N): GraphQL과의 만남


✅ 1. GraphQL이란 무엇인가? (REST API의 대안)

  • GraphQL은 페이스북(현 메타)에서 개발한, API를 위한 쿼리 언어(Query Language)이자 해당 쿼리를 실행하기 위한 런타임입니다. REST API의 몇 가지 문제점을 해결하기 위해 등장했습니다.

  • REST API의 문제점:

    1. Over-fetching: 특정 엔드포인트가 항상 정해진 데이터 구조 전체를 반환하므로, 클라이언트가 필요하지 않은 데이터까지 받아와야 하는 낭비가 발생합니다. (e.g., 사용자의 이름만 필요한데, 나이, 주소, 가입일까지 모두 받아옴)
    2. Under-fetching: 하나의 화면을 구성하기 위해 여러 번의 API 요청이 필요한 경우가 발생합니다. (e.g., 게시글 정보를 가져온 후, 다시 댓글 정보를 가져오고, 또 사용자 정보를 가져오는 등)
    3. 경직된 엔드포인트: 클라이언트의 요구사항이 변경될 때마다 새로운 엔드포인트를 만들거나 기존 엔드포인트를 수정해야 합니다.
  • GraphQL의 해결책:

    • GraphQL은 단 하나의 엔드포인트(/graphql)를 사용합니다.
    • 클라이언트는 이 엔드포인트에 "내가 필요한 데이터의 구조"쿼리(Query) 형태로 담아 보냅니다.
    • 서버는 이 쿼리를 해석하여, 클라이언트가 요청한 그대로의 구조와 데이터만을 정확하게 반환합니다.
    # 클라이언트가 서버에 보내는 쿼리
    query {
      user(id: "1") {
        name
        email
        posts {
          title
        }
      }
    }
    
    # 서버가 클라이언트에게 보내는 응답 (JSON)
    {
      "data": {
        "user": {
          "name": "Alice",
          "email": "alice@example.com",
          "posts": [
            { "title": "My first post" },
            { "title": "GraphQL is awesome" }
          ]
        }
      }
    }

✅ 2. GraphQL의 3가지 핵심 작업 (Operation)

  1. Query: 데이터를 읽는(Read) 작업. REST의 GET과 유사합니다.
  2. Mutation: 데이터를 생성(Create), 수정(Update), 삭제(Delete)하는 작업. REST의 POST, PUT, DELETE를 합친 것과 유사합니다.
  3. Subscription: 특정 이벤트가 발생했을 때, 서버가 클라이언트에게 실시간으로 데이터를 푸시(Push)하는 작업. (WebSocket 기반)

✅ 3. NestJS에서 GraphQL 서버 구축하기

  • NestJS는 @nestjs/graphql@nestjs/apollo 패키지를 통해 GraphQL 서버를 매우 쉽고 구조적으로 구축할 수 있도록 지원합니다.

➕ 3-1. 필요한 패키지 설치

npm install @nestjs/graphql @nestjs/apollo graphql apollo-server-express

➕ 3-2. 루트 모듈(app.module.ts)에 GraphQLModule 등록

  • GraphQLModule.forRoot()를 사용하여 GraphQL 서버의 기본 설정을 구성합니다.

    • autoSchemaFile: true: 코드(TypeScript 클래스)를 기반으로 GraphQL 스키마 파일(schema.gql)을 자동으로 생성해주는 매우 강력한 옵션입니다. (Code-First 접근 방식)
    • driver: ApolloDriver: GraphQL 쿼리를 실행할 엔진으로 Apollo Server를 사용하도록 지정합니다.
    // app.module.ts
    import { GraphQLModule } from '@nestjs/graphql';
    import { ApolloDriver } from '@nestjs/apollo';
    
    @Module({
      imports: [
        GraphQLModule.forRoot({
          driver: ApolloDriver,
          autoSchemaFile: true,
        }),
      ],
    })
    export class AppModule {}

➕ 3-3. 스키마 정의: DTO와 @ObjectType

  • GraphQL 스키마에서 사용될 데이터 타입을 정의합니다. NestJS에서는 @ObjectType() 데코레이터가 붙은 클래스를 사용하여 이를 정의합니다.

  • @Field(): 외부로 노출될 필드를 명시합니다.

    // movie.dto.ts
    import { ObjectType, Field, Int } from '@nestjs/graphql';
    
    @ObjectType() // 이 클래스가 GraphQL의 타입임을 선언
    export class Movie {
      @Field(() => Int)
      id: number;
    
      @Field()
      title: string;
    
      @Field(() => Int)
      year: number;
    }

➕ 3-4. 리졸버 (Resolver) 구현

  • 리졸버는 특정 GraphQL 쿼리나 뮤테이션에 대한 실제 처리 로직을 담고 있는 클래스입니다. REST의 컨트롤러와 유사한 역할을 합니다.

  • @Resolver(): 이 클래스가 리졸버임을 선언합니다.

  • @Query(): 쿼리 핸들러임을 나타냅니다.

  • @Mutation(): 뮤테이션 핸들러임을 나타냅니다.

  • @Args(): 쿼리나 뮤테이션에 전달된 인자(arguments)를 가져옵니다.

    // movies.resolver.ts
    import { Resolver, Query, Args, Mutation } from '@nestjs/graphql';
    import { Movie } from './dto/movie.dto';
    import { MoviesService } from './movies.service';
    
    @Resolver()
    export class MoviesResolver {
      constructor(private readonly moviesService: MoviesService) {}
    
      @Query(() => [Movie]) // 이 메서드가 [Movie] 타입을 반환하는 쿼리임을 선언
      movies(): Movie[] {
        return this.moviesService.getAll();
      }
    
      @Mutation(() => Boolean)
      createMovie(@Args('title') title: string): boolean {
        // ... 영화 생성 로직 ...
        return true;
      }
    }

📌 요약

  • GraphQL은 클라이언트가 필요한 데이터만, 원하는 구조로, 한 번의 요청으로 가져올 수 있게 해주는 현대적인 API 쿼리 언어입니다.
  • GraphQL의 주요 작업은 Query(읽기), Mutation(쓰기), Subscription(실시간)으로 나뉩니다.
  • NestJS에서는 Code-First 접근 방식을 통해, TypeScript 클래스와 데코레이터(@ObjectType, @Field)로 스키마를 정의하면, GraphQL 스키마 파일이 자동으로 생성됩니다.
  • 리졸버(@Resolver)는 REST의 컨트롤러와 유사한 역할을 하며, @Query@Mutation 데코레이터가 붙은 메서드에서 실제 데이터 처리 로직을 구현합니다.

0개의 댓글