Hun's Blog

Nexus GraphQL tutorials (1) - GraphQL이란? / setup and first query 본문

Backend/GraphQL

Nexus GraphQL tutorials (1) - GraphQL이란? / setup and first query

jhk-im 2020. 11. 29. 12:06

GraphQL을 개인 프로젝트에 적용하기위해 제대로 학습해보기 시리즈

해당 글은 Nexus 를 개인 프로젝트에 적용하고자 제대로 학습하기 위해 Nexus tutorial의 내용을 정리한 것입니다.

Nexus tutorial에도 상세하게 나와있음을 알려드립니다. 

GraphQL

 페이스북이 2012년에 개발하여 2015년에 공개적으로 발표된 데이터 쿼리 언어이다. REST 및 웹서비스 아키텍쳐를 대체할 수 있다. 클라이언트가 필요한 데이터의 구조를 지정할 수 있으며, 서버는 정확히 동일한 구조로 데이터를 반환한다. 사용자가 어떤 데이터가 필요한 지 명시할 수 있게 해주는 언어이다. 이러한 구조를 통해 불필요한 데이터를 받게 되거나 필요한 데이터를 받지 못하는 문제를 피할 수 있다.  주요 클라이언트로는 아폴로와 Relay 등이 있다. GrapqhQL 서버는 여러 언어로 구현되어 있는데, 자바스크립트, 파이썬, 루비, 자바, C#, 스칼라, 고, 엘릭서, 얼랭, php, 클로져 등의 언어로 구현되어 있다.

- 위키백과 -  

 

 GraphQL에 대한 자료들을 검색해보고 수많은 블로그에서 공통적으로 설명하는 부분들을 파악한 후 위키백과에서 중요한 부분이 밑줄을 그어 보았다. 주요부분들을 정리해보자면 다음과 같다. 

 

1. REST를 대체한다. 

2. 클라이언트가 데이터 구조를 지정하고 서버에서 정확히 동일한 구조로 데이터 반환 

3. 어떤 데이터가 필요한지 명시하여서 불필요한 데이터를 걸러내고 필요한 데이터의 손실을 방지한다.

...

 

더보기

수많은 글을 읽어 본 결과 처음부터 모든 것을 다 이해하고 GraphQL을 독파할 수 없다고 판단하였다. 다른것은 일단 뒤로 미뤄두고 우선 공통적으로 설명하고 있는 위에 3가지의 내용을 파악하는것이 우선인것 같다. GraphQL 예제를 진행해보면서 위에 3가지의 내용을 캐치해보도록 하자. 

 

GraphQL을 구현하기 위한 조합은 매우 다양하다. 해당 글은 Nexus 튜토리얼을 따라 진행된다. GraphQL을 구현하기위한 수많은 보일러 플레이트 코드를 줄여주고 조금더 쉽게 구현할 수 있게 도와주는 툴이다. 이러한 툴 또한 다양하지만 이전 회사에서 사용해본 경험이 있기 때문에 결정하였다. 먼저 Nexus에 대해 알아보자. 

 

 

Nexus

 

GraphQL Nexus · Declarative, Code-First GraphQL Schemas for JavaScript/TypeScript

Declarative, Code-First GraphQL Schemas for JavaScript/TypeScript

nexusjs.org

JavaScript/TypeScript용 선언적 GraphQL 스키마. 

 

Type-Safe by Default 

-> Nexus API는 type-safe를 염두해두고 설계되었다. 

-> 개발시 타입 정의를 자동 생성하고 코드에서 유추하여 IDE를 완성하고 박스를 통해 포착된 오류를 보여준다. 

 

Works With The Ecosystem

-> 스키마를 구성할 때 기존 graphql-js 타입과 연동할 수 있다. 

-> 생성 된 스키마를 아폴로 서버 혹은 GraphQL 미들웨어와 같은 선호하는 툴과 함께 구현할 수 있다.

 

Data-Agnostic

-> graphql-js 라이브러리에서 계층화된 선언적 구문이다. 

-> graphql-js와 apollo-tools로 하는 모든 것을 nexus로 할 수있다. 

 

Automatic Type Inference (even in JS!)

-> 스키마를 기반으로 타입을 자동으로 생성하고 입력한다. 

-> 수동으로 주석을 추가할 필요가 없다. 

 

Autocompletion on Type Names

->  스키마에 있는 타입 이름을 추적하여 타입 시스템에 제공 

-> 스키마의 다양한 위치에서 무엇을 사용할 수 있는지 알 수 있다. 

 

SDL -> Nexus Converter

SDL 컨버터를 사용하여 기존 스키마를 Nexus 코드로 변환할 수 있다. 

 

더보기

여기서도 모든것을 전부 다 이해하려 하지말고 간략하게 정리한 후 예제를 진행하면서 해당 내용들을 캐치해보도록 하자. 

 

1. 기본적으로 type-safe 제공

2. graphql-js 라이브러리 타입과 연동하여 스키마 구성 

3. graphql-js와 apollo-tools 라이브러리를 대체

4. 스키마를 기반으로 타입과 주석을 자동 생성 

5. 타입 이름 자동 완성 

6. SDL 컨버터로 스키마를 Nexus 코드로 변환

 

Why Nexus?

 

Why Nexus?

Why Nexus?

nexusjs.org

더보기

-> Nexus는 다른 언어와 프레임워크로 GraphQL API를 만든 경험에서 탄생하였다.  (vanilla graphql-js, graph.ql, graphql-tools, graphene-python, graphql-ruby) 

스키마 우선 개발 (Schema first development)

-> 스키마를 GraphQL Schema Definition Languege(SDL)로 표현하여 필요에 따라 타입에 맞는 Resolver를 제공하고 빠르게 실행한다.

-> GraphQL 서버를 실행하기 위한 많은 요구사항이나 오버헤드가 필요하지 않다. 

-> 만약 스키마가 수백, 수천가지의 타입으로 늘어남에 따라 SDL 파편을 수동으로 작성하는 것은 힘든 반복작업이 되고 문서 변경이 힘들어진다. 

-> 인터페이스 필드를 수정하려면 수많은 구현 타입을 수동으로 변경해야 할 수 있으며, 이러한 프로세스는 오류가 발생하기 쉽다. 

 

스키마 우선 개발의 단순성 + 우선 접근법을 장기 유지 하는 방법이 있으면 좋을 것이다.

-> Nexus는 아직없는 이 방법을 메우는 것을 목표로 하며, 프로세스를 최대한 단순화하는 동시에 런타임을 활용하여 강력한 타입 구성방법, 타입 이나 스키마의 변경 방법 등을 소개한다. 

-> SDL을 기반으로 하여 선언적이고 이해하기 쉽게 설계되어있다. 

-> 참조 타입으로 가져오는 것 보다는 타입이름을 문자열로 참조할 수 있다. 

-> 자동 타입생성과 TypeScript의 몇가지 강력한 기능을 결합 (타입 병합, 조건부 및 타입 추론, 코드 전반에 걸쳐 사용할 수 있는 타입이름을 정확히 할 수 있음)

-> 어떠한 타입 annotation을 제공하지 않아도 Resolver의 매개변수와 리턴타입을 모두 알 수 있다. 

 

Setup and first query 

 

1. Setup and first query

1. Setup and first query

nexusjs.org

CLI 부분은 생략한다. 위 링크에 자세하게 설명되어있다. 

 

Creating our app layout

import { makeSchema } from '@nexus/schema'
import { join } from 'path'

export const schema = makeSchema({
  types: [], // 1.
  outputs: {
    typegen: join(__dirname, '..', 'nexus-typegen.ts'), // 2.
    schema: join(__dirname, '..', 'schema.graphql'), // 3.
  },
})

1. GraphQL 스키마를 구성하는 데 사용할 GraphQL type

2. @nexus/schema가 스키마로 부터 생성된 TypeScript definition 타입의 생성된 값을 기록해야하는 위치 출력경로 

3. @nexus/schema가 GraphQL 스키마의 SDL 버전을 기록해야하는 위치 출력경로 

 

// api/server.ts
import { ApolloServer } from 'apollo-server'
import { schema } from './schema'
export const server = new ApolloServer({ schema })
// api/app.ts
import { server } from './server'
server.listen().then(({ url }) => {
  console.log(`🚀 Server ready at ${url}`)
})

마지막으로 GraphQL 서버를 설정한다. 

나중에 테스트를 쉽게하기 위해 의도적으로 서버 instantiation을 서버 수신과 분리한다. 

api/app.ts 에서 서버가 수신하도록 한다.