2 분 소요

GraphQL의 핵심 요소? 👀

Query

Query란 데이터베이스로부터 데이터를 얻어오기 위해 사용하는 것으로,

type Query {

         (쿼리명): (반환 타입) (!)

}

의 형태로 선언합니다.

만약 반환 타입 뒤 !(느낌표)를 붙일 시, 해당 요청이 들어오면 명시한 타입의 데이터를 반드시 반환해야만 하며, 사용자 정의 반환 타입을 생성하여 Query의 반환 타입에 적용이 가능하므로 임의의 객체를 반환하고자 할 때 반환 타입을 새로 만들어 타입 지정을 한다.

type Person {
  name: String!
  age: Int!
}

type Query {
  getName: String
  getAge: Int!
  getInfo: Person!
}


Mutation

Mutation이란 서버, 데이터베이스 혹은 메모리에서 ‘데이터를 변경할 때 사용’하며,

CRUD(Create, Read, Update, Delete) 중 CUD 요청을 담당합니다.

만약, GraphQL을 데이터베이스와 연동하여 사용하지 않는다면,

Mutation을 하더라도 메모리에 변경사항이 적용되어 서버 재실행 시 초기화가 되므로 주의해야 하며, 선언은 Query의 방식과 같다.

type Mutation {
  changeName: (age: Int!): Boolean!
  changeAge(name: String!): Boolean!
}


Subscription

GraphQL에서 수행할 수 있는 Query, Mutation에 이은 세 번째 작업 타입이다.

데이터 조회에 Query를 사용하고 데이터 조작에 Mutation을 사용하면 Subscription은 어디에 사용할까? 바로 실시간 통신에 사용한다.

Subscription은 이름 그대로 구독/발행 모델을 기반으로 WebSocket을 통해 실시간 양방향 통신 기능을 제공한다.

구독을 통해 특정한 이벤트가 발생했을 때 서버에서 클라이언트로 데이터를 실시간으로 통신하게 된다.


graphql-1


Subscription은 다음과 같은 과정으로 진행된다.

처음에 사용자가 Mutation요청을 보내면 해당 Mutation의 Resolver 내부에서 Publish Event가 실행되며 Event Bus에게 알려준다.

그러면 Event Bus는 해당 이벤트를 구독하고 있는 Subscriber에게 이벤트가 발생되었다고 알려주게 된다.

Subscription을 사용하지 않고 서버의 상태 변화를 감지하기 위해서는 주기적으로 HTTP요청을 서버로 보내 변경된 상태가 있는지 지속적으로 확인하는 방법 또한 있다.

하지만 아무리 자주 호출하더라도 완벽하게 실시간으로 통신하기는 어렵고 클라이언트에서 주기적으로 요청을 보내줘야 하기 때문에 자원의 낭비가 심할 수 있다.


graphql-2
구독과정


구독 과정은 다음과 같이 진행된다.

  1. 클라이언트가 서버로 Subscribe 요청(쿼리와 변수 포함)을 보낸다.
  2. 서버는 해당 쿼리가 올바른 쿼리인지 확인한다.
  3. 단일 PubSub객체를 통해 Event Bus에 이벤트 발생을 감지
  4. 클라이언트가 요청한 Subscription 활성화

여기서 PubSub이란 Publish-Subscribe의 줄임말로 구독 이벤트 발생 및 감지를 위해 사용하는 객체이다. 그런데 여기서 Single PubSub을 사용하는 이유는 서버를 클러스터 모드(Node.js의 pm2 기준)로 실행하는 경우 각 인스턴스에 PubSub이 존재하게 된다. (서버를 여러 인스턴스로 실행하는 경우)

클라이언트에서 요청을 보낼 때 해당 인스턴스로 구독 이벤트가 발생이 되야 업데이트가 되는데 어떤 PubSub을 가진 인스턴스에게 요청을 보낼 지 모르기 때문에 이벤트 발생 감지를 불안정하게 할 수 있다.

그렇기 때문에 redis등을 사용해 단일 PubSub을 사용하면 해당 문제가 발생하지 않는다.


graphql-3
구독취소과정


구독 취소 과정은 좀 더 간단하다.

  1. 클라이언트가 서버로 구독 취소 요청을 보낸다. (양방향 연결 해제)
  2. PubSub은 Event Bus의 이벤트 발생 감지를 취소한다.

이벤트 발생 과정 그렇다면 마지막으로 구독한 Subscription에 이벤트가 발생했을 경우 데이터를 받아오는 과정에 대해 살펴보자!


graphql-4
이벤트발생과정


다음은 이벤트가 발생하고 클라이언트에게 구독 중인 데이터를 전송하는 과정이다.

  1. 익명의 클라이언트가 서버로 Mutation 요청을 보낸다.
  2. 해당 Mutation에서 PubSub객체를 통해 Event Bus로 이벤트가 발생했다고 알려준다.
  3. Event Bus에서 이벤트 발생을 감지하고 있던 PubSub에게 이벤트 발생을 알려준다.
  4. PubSub은 서버에서 해당 구독 이벤트의 반환값을 받는다.
  5. 받은 반환값을 Client에게 전송해준다.


Resolver

Resolver란 클라이언트로부터 요청된 Query 혹은 Mutation에 대해 반환할 결과를 생성하는 로직으로,

GraphQL 서버가 Resolver를 찾아 Query와 Mutation에 해당하는 함수를 실행한다.

또한, Resolver를 통해 데이터베이스, 메모리, 다른 API 등과 연결해 자유자재로 프로그래밍이 가능해지며,

실행 함수의 첫 번째 인자로는 현재 Object가 넘어오고, 두 번째부터 요청된 Query나 Mutation에서 넘어온 인자가 객체의 형태로 전달되기 때문에

( _, { arg1, arg2, … } )의 형태로 인자를 넘겨받아 사용합니다.

const resolvers = {
  Query: {
    getName: () => {
      함수로직;
    },
        getAge: () => {
      함수로직;
    },
        getInfo: () => {
      함수로직;
    }
  },
  Mutation: {
    changeName: (_, { age }) => {
      함수로직;
    },
    changeAge: (_, { name }) => {
      함수로직;
    }
  }
}

업데이트: