본문 바로가기

# GraphQL/TypeGraphQL

ApolloServer + TypeScript + TypeGraphQL 조합으로 GraphQL 서버 시작하기

TypeGraphQL

TypeScriptGraphQL을 함께 사용하려고 한다면 TypeScript가 생산성을 감소시키는 복병이 될 수 있습니다. 편하게 작업하려고 도입한 TypeScript가 오히려 개발을 어렵게 만들다니. 이게 어떻게 된 걸까요?


타입 불일치

문제는 SDLActual Type이 일치하지 않을 때 발생합니다. Int라고 써놓고 String으로 읽는다거나 nullable을 빼먹는다거나... 문제는 이런 상황이 의외로 흔하고, 에러가 발생하기 전까지는 눈치채기도 어렵다는 것 입니다.

// SDL
type book {
    title : String!
    price : Int
}

// TypeScript
class book {
    title : string; 
    price : number; //< type mismatch. (must be nullable)
}

이것은 당연히 스키마를 수정하는 비용도 증가시키는데, SDL이 변경되면 TypeScript도 수정해야 한다는 것이죠. 잘못 수정하는 날에는 고난이도의 틀린 그림 찾기가 펼쳐질 수 있습니다. 🥶


어디서 본 것 같은데?

슬슬 어디서 익숙한 느낌이 드실 겁니다. 사실 이것은 이미 겪었고 이미 해결했던 문제이기 때문이죠. 바로 database에서 말이지요. 데이터베이스의 tableclass로 표현하려고 할 때 겪은 문제들이며 객체-관계 매핑(ORM)을 통해서 해결한 문제이기도 합니다.

import {Entity, Column} from "typeorm"

@Entity()
class Book extends BaseEntity{
    @Column()
    title !: string

    @Column({ default: null, nullable: true })
    price ?: number
}

이것을 GraphQL로 가져오면 편할 것 같지 않나요? TypeGraphQL이 바로 이러한 기능을 제공합니다. class만 정확하게 작성한다면 SDL은 더 이상 신경쓰지 않아도 됩니다. 😄

@ObjectType()
class Book {
    @Field()
    title !: string; 

    @Field({nullable: true})
    price ?: number;
}

Getting Start

TypeScript 프로젝트 생성

새로운 타입스크립트 프로젝트를 생성합니다. 소스 코드는 src/에 작성하겠습니다.

mkdir new_project
cd new_project

npm init -y
npm install @types/node typescript -D

npx tsc --init
mkdir src

tsconfig.json에서 소스파일 루트를 수정합니다.

//
// tsconfig.json
{
    "compilerOptions": {
        "rootDir": "./src"
    }
}

라이브러리 설치

Apollo, TypeGraphQL과 각각의 필수 라이브러리를 설치합니다.

npm install apollo-server graphql
npm install type-graphql class-validator reflect-metadata

type-graphqles2018 이상의 문법, decorator, decorator-metadata를 사용하기 때문에 tsconfig.json에서 해당 기능을 활성화시켜줍니다.

{
    "compilerOptions": {
        "target": "es2018",
        "module": "commonjs",
        "lib": ["es2018", "esnext.asynciterable"],

        "experimentalDecorators": true,
        "emitDecoratorMetadata": true
    }
}

Hello World!

다음 소스코드를 ./src/index.ts로 저장합니다.

//
// reflect-metadata는 프로그램 진입점 최상단에 적어야 한다.
import "reflect-metadata";

import { Resolver, Query, buildSchemaSync } from "type-graphql";
import { ApolloServer } from "apollo-server";

@Resolver()
class MyFirstResolver {
    @Query(() => String)
    hello(): string {
        return "world!";
    }
}

//
// 클래스 형태의 리졸버로 스키마를 생성한다.
const schema = buildSchemaSync({
    resolvers: [MyFirstResolver],
});

//
// 만들어진 스키마를 아폴로에 넘긴다.
const server = new ApolloServer({ schema });
server.listen().then(({ url }) => {
    console.log(`Server ready at ${url}`);
});

컴파일 없이 소스코드를 실행하기 위해 ts-node를 사용합니다.

npm install ts-node -D
npx ts-node ./src/index.ts

[output]
Server ready at http://localhost:4000/

첫번째 서버가 실행되었습니다! 출력된 주소에서 hello를 가져오는 쿼리를 작성하면 world! 문자열이 반환됩니다.

'# GraphQL > TypeGraphQL' 카테고리의 다른 글

[TypeGraphQL] 상속, Inheritance  (0) 2020.07.04
[TypeGraphQL] @EnumType  (0) 2020.06.18
[TypeGraphQL] Scalar  (0) 2020.06.14
[TypeGraphQL] @InputType, @ArgsType  (0) 2020.06.13
[TypeGraphQL] 기본 자료형과 @ObjectType  (0) 2020.06.08