[회고] 신입 iOS 개발자가 되기까지 feat. 카카오 자세히보기

🛠 기타/WEB

Nest.js - nest.js 환경에서 GraphQL 사용하기

inu 2021. 1. 13. 15:50
반응형

0. 패키지 설치

$ npm i @nestjs/graphql graphql-tools graphql apollo-server-express
  • apollo server를 기반으로하는 @nestjs/graphql을 활용해 nest.js 환경에서 GraphQL을 사용할 수 있다.
  • Apollo server나 기존 GraphQL 라이브러리도 당연히 필요하기 때문에 함께 설치해준다.

1. 모듈 연결하기

import { GraphQLModule } from '@nestjs/graphql';

@Module({
  imports: [
    GraphQLModule.forRoot({
      autoSchemaFile: true,
    })
  ],
  controllers: [],
  providers: [],
})
  • GraphQL 모듈이 정상적으로 돌아가도록 하기 위해, 적용될 범위의 모듈에 GraphQL 모듈을 추가해주어야 한다. (물론 대부분의 경우 최상위 모듈인 app.module이 될 것이다.)
  • GraphQLModule.forRoot로 root 모듈 설정을 해준다.
  • autoSchemaFile는 작성된 typescript 코드를 기반으로 자동으로 스키마를 작성해준다.
  • autoSchemaFile을 true로 설정하면 메모리 상에서 자동으로 스키마가 처리된다.
  • autoSchemaFile에 join(process.cwd(), 'schema.gql')와 같이 경로와 파일명을 입력하면 해당 경로에 파일명의 스키마 파일이 생성된다.
  • 물론, GraphQL이 Apollo server에서 정상적으로 돌아가기 위해선 typeDefs(schema)와 resolvers(query, mutation)의 내용이 명시되어 있어야 한다.

2. Resolver 작성 예시 및 설명

import { Args, Mutation, Query, Resolver } from "@nestjs/graphql";
import { Restaurant } from "./entities/restaurant.entity";

@Resolver(of => Restaurant)
export class RestaurantResolver {
    @Query(returns => [Restaurant])
    restaurant(): Restaurant[] {
        return Restaurants;
    }

    @Mutation(returns => Boolean)
    createRestaurant(
        @Args('name') name: string, @Args('address') address: string): boolean {
        return true;
    }
}
  • @Resolver 데코레이터를 활용해 resolver를 작성한다.
  • of => Restaurant 로 어떤 resolver인지 명시할 수도 있다. (필수는 아님)
  • 내부에서는 @Query, @Mutation 데코레이터를 활용해 GraphQL-Yoga에서 작성한 것처럼 Resolver를 작성한다.
  • 단, @Query, @Mutation 데코레이터에 리턴값의 형식을 typeFunc 형식으로 입력해 알려주어야 한다. (해당 typeFunc는 ()=> Boolean , type => Boolean 등 다양한 형식으로 작성할 수 있다.)
  • argument가 필요한 요청의 경우 @Args 데코레이터를 통해 하나씩 명시 후 작성한다.
  • Query나 Mutation에 대한 typeDefs는 각 데코레이터로 인해 알아서 처리되니 이제 우리는 추가적으로 필요한 형식에 대해서만 처리해주면 된다. (by. autoSchemaFile)
  • 해당 resolver파일은 모듈의 providers에 입력되어야 정상적으로 작동한다.
  • cf. graphql로 해석되는 코드에서 특정 타입의 집합을 표현할 때는 type[]가 아닌, [type]으로 명시해야한다. 그 외에도 타입의 입력형식이 조금씩 다른 경우가 있으므로 주의하자.

3. typeDefs 작성 예시 및 설명

import { Field, ObjectType } from "@nestjs/graphql";

@ObjectType()
export class Restaurant {
    @Field(type => String)
    name: string;

    @Field(type => String)
    address: string;

    @Field(type => String, { nullable: 'items' })
    ownerName?: string;
}
  • @ObjectType 데코레이터와 @Field 데코레이터를 사용하면 entitiy 파일에 작성된 모델을 그대로 활용해 typeDefs로 사용할 수 있다.
  • @ObjectType 데코레이터는 해당 class가 graphql 상에서 typeDefs로 인식되도록 해준다.
  • @Field는 해당 type의 속성이며, typeFuncs로 형식을 입력해주어야한다.
  • @Field 데코레이터는 {nullalbe:true} 등의 옵션 부여도 가능하다.

cf. resolver에서 하나의 object로 전달받는 방법

@InputType()
export class createRestaurantDto {
    @Field(type => String)
    name: string;
    @Field(type => Boolean)
    isVegan: boolean;
    @Field(type => String)
    address: string;
    @Field(type => String)
    ownerName: string;
}
  • 위와 같은 형식으로 dto를 작성해 typeDefs를 해준다.
  • 핵심은 @inputType 데코레이터이다. 해당 데코레이터가 class를 하나의 object로 인식하도록 해준다.
@Mutation(returns => Boolean)
createRestaurant(
    @Args('createRestaurantInput') createRestaurantInput: createRestaurantDto): boolean {
    return true;
}
  • @inputType 데코레이터 덕분에 createRestaurantDto 형식을 createRestaurantInput, 하나의 input object로 받아들일 수 있게된다.

cf2. 하나의 object지만 분리된 형태로 전달받고 싶을 경우

@ArgsType()
export class createRestaurantDto {
    @Field(type => String)
    name: string;
    @Field(type => Boolean)
    isVegan: boolean;
    @Field(type => String)
    address: string;
    @Field(type => String)
    ownerName: string;
}
  • @ArgsTypes()를 활용해 하나의 object를 확인하되, 전달받을 땐 분리된 형태로 받을 수 있다.
  • 보통 create 등의 작업을 할 땐 하나의 object로 만들어서 전달하기보단, 내부 속성을 작성하여 분리된 형태로 받기 때문에 해당 방법이 더 유용하다고 할 수 있다.
@Mutation(returns => Boolean)
createRestaurant(
    @Args() createRestaurantDto: createRestaurantDto): boolean {
    return true;
}
  • @Args 파라미터에 이름을 따로 명시하지 않아도된다.
  • 이는 파라미터에 필요한 Argument들을 모두 하나씩 명시한 것과 같은 효과를 지닌다.

cf3. class validator와 class-transformer로 args 유효성 체크하기

$ npm i class-validator class-transformer
  • class-validator와 class-transformer를 통해 args의 유효성을 체크할 수 있다.
import { ArgsType, Field } from "@nestjs/graphql";
import { IsBoolean, IsString, Length } from "class-validator";

@ArgsType()
export class createRestaurantDto {
    @Field(type => String)
    @IsString()
    @Length(5, 10)
    name: string;

    @Field(type => Boolean)
    @IsBoolean()
    isVegan: boolean;

    @Field(type => String)
    @IsString()
    address: string;

    @Field(type => String)
    @IsString()
    ownerName: string;
}
  • @IsString, @IsBoolean과 같은 tpye 데코레이터로 type을 확인하도록 할 수 있다.
  • 뿐만 아니라 @Length 로 길이도 설정할 수 있다.
  • 단, main.ts에 validationPipe를 설정해야 한다.
import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(
    new ValidationPipe()
  );
  await app.listen(3000);
}
bootstrap();
  • 파이프는 일종의 미들웨어로서 작동해 객체의 유효성을 체크해준다.

GraphQL Playground

  • root url에서 /graphql로 접속하면 GraphQL 개발자도구인 GraphQL Playground에도 접속할 수 있다.
반응형

'🛠 기타 > WEB' 카테고리의 다른 글

Node.js - multer (파일 업로드)  (0) 2021.01.31
Node.js - Sequelize  (0) 2021.01.28
React - GraphQL Client (with Apollo)  (0) 2021.01.12
React - Styled Components  (0) 2021.01.12
React - React Router  (0) 2021.01.11