BackEnd/GraphQL

[GraphQL] NestJS 프로젝트에 적용하기 1 (Query, Mutation)

Cune 2022. 11. 6. 16:54


NestJS 공식문서를 참고하여 작성했습니다

 

Documentation | NestJS - A progressive Node.js framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Progamming), FP (Functional Programming), and FRP (Functional Reac

docs.nestjs.com

 

 

1. 터미널 CLI로 GraphQL 사용을 위한 npm을 설치

> npm i @nestjs/graphql @nestjs/apollo graphql apollo-server-express

 

2. AppModule에서 GraphQLModule 설정

import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';

@Module({
  imports: [
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
      playground: true,	// 'http://localhost:3000/graphql' 플레이그라운드 사용
      autoSchemaFile: 'schema.gql',	// Code first 방법시 추가
      typePaths: ['./**/*.graphql'], // Schema first 방법시 추가
      cors: {	// 프론트 cors 설정관련
      	orgin: 'http:localhost:8080',
        credentials: true,
    }),
  ],
})
export class AppModule {}

 

* Schema First vs Code First

- 방법이 두가지로 나뉘는데 무슨 방법을 선택하느냐에 따라서 추후 방법이 조금씩 다릅니다

검색을 통해 찾은 차이점과 제가 느낀부분들을 합쳐서 비교정리했습니다

  Schema First Code First
SDL 파일 비교 SDL파일 직접 생성 (.graphql) 스키마 타입을 위한 타입스크립트 클래스를 생성
-> 클래스를 참고해서 SDL파일 자동생성
작업적 비교 서로다른 플랫폼 간 스키마 공유 가능 타입스크립트 단독 작업에만 사용 가능

-> Code First 방법으로 프로젝트를 진행했습니다

 

3.  SDL 생성을 위한 Type Class 작성

A. 기본 객체 타입

import { Field, ID, ObjectType } from '@nestjs/graphql';
import { Order } from '../../order/models/order';

@ObjectType()
export class Product {
  @Field(() => ID)
  id: number;

  @Field()
  name: string;

  @Field()
  price: number;

  @Field()
  stock: number;

  @Field(() => [Order!])
  orderList: Order[];
}

 

B. 인풋 타입 (데이터 입력받을때 사용)

import { Field, ID, InputType, ObjectType } from '@nestjs/graphql';

@InputType()
export class ProductInput {
  @Field()
  name: string;

  @Field()
  price: number;

  @Field()
  stock: number;
}

 

4. 프로젝트 실행해서 자동생성된 스키마 파일 확인

-> npm run start로 실행하면 프로젝트 최상단 위치에 'schema.gql' 파일 생성

(자동 생성되기 때문에 직접 수정은 안됩니다. 수정이 필요하다면 3번에서 만든 파일에서 해야합니다.)

# ------------------------------------------------------
# THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)
# ------------------------------------------------------

type Order {
  id: ID!
  shopName: String!
  date: DateTime!
  productId: Float!
  content: String!
  cost: Float!
}

type Product {
  id: ID!
  name: String!
  price: Float!
  stock: Float!
  orderList: [Order!]!
}

input ProductInput {
  name: String!
  price: Float!
  stock: Float!
}

 

5. Resolver 파일 작성

- Controller의 역할을 Resolver에서 한다고 생각하면 됩니다.

 

A. Query - 데이터 변경없이 조회만 하는 경우 사용

B. Mutation - 데이터의 변경이 필요한 경우 사용

import {
  Args,
  ID,
  Mutation,
  Parent,
  Query,
  ResolveField,
  Resolver,
} from '@nestjs/graphql';
import { Product } from './model/product';
import { ProductInput } from './model/product.input';

@Resolver(() => Product)
export class ProductResolver {
  constructor(
    private productService: ProductService,
  ) {}

  @Mutation(() => Product, { name: 'product' })	// 리턴타입과 쿼리타입이름 (부가설명)
  async createProduct(@Args('productInput') productInput: ProductInput) {	// 파라미터
    return await this.productService.createProduct(productInput);
  }

  @Query(() => Product, { name: 'product' })
  async getProduct(@Args('id', { type: () => ID }) id: number) {	// ID 타입을 number타입으로
    return await this.productService.getProduct(id);
  }
}

 

* 부가설명

@Mutation(()=> Product, {name:'product'}) 
async createProduct(){}

메소드명인 'createProduct'가 아닌 다른이름을 원한다면 'product'로 설정해준 이름으로 요청하면 된다.

 

 

 

6. 해당 모듈 클래스파일 providers에 Resolver 추가하기

맘이 급해서 이걸 까먹고 실행시키면 에러가 납니다ㅠㅠ 꼭 추가해줍시다!

import { Module } from '@nestjs/common';
import { ProductService } from './product.service';
import { ProductResolver } from './product.resolver';

@Module({
  providers: [ProductService, ProductResolver],
})
export class ProductModule {}

 

 

7. Playground로 테스트 확인

mutation - 인풋타입으로 데이터를 넣어주고 조회할 필드명을 쿼리타입 product{} 안에 작성합니다

query - product의 아이디를 파라미터로 찾습니다

 

+ 최종 shcema.gql

->mutation, query가 생겼을 것이다.

# ------------------------------------------------------
# THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)
# ------------------------------------------------------

type Product {
  id: ID!
  name: String!
  price: Float!
  stock: Float!
  orderList: [Order!]!
}

input ProductInput {
  name: String!
  price: Float!
  stock: Float!
}

type Query {
  product(id: ID!): Product!
}

type Mutation {
 createProduct(productInput: ProductInput!): Product!
}

 

 

+ 프로젝트 파일 구조