웹앱 api 개발을 위한 graphql

review · 2025-12-8

← 리스트로

웹앱 api 개발을 위한 graphql

1장 개요

Api를 만들기위한 쿼리언어, 실제 필요한 데이터만 받도록 할 수 있다.

사용하려면 데이터에 대한 타입 정의가 필요하다.

Graphql은 클라이언트 와 서버간의 통신명세이다.

장점은 꼭필요한 데이터를 지정해서 가져올수 있다는것이다.(언더패치 문제를 해결 -> 꼭 필요한 데이터만 가져온다)

(오버패치 문제해결 -> 추가 정보를 위해 추가 패치를 할 필요없다)

api 요구 변경에 따른 너무 많은 엔드포인트 분기가 필요없다.

Rest api 와 graphql은 함께 사용 가능하다.

많은 graphql 클라이언트가 있는데 가장 많이 쓰이는건 아폴로와 릴레이다.

2장 그래프 이론

Graphql은 node와 edge로 구성하는 트리구조로 되어있다.

3장 graphql 쿼리어

한번의 명령으로 복수에 레코드에 접근하는 개념은 sql에서 비롯되었다.

Rest의 CRUD 개념은 Sql에서 비롯되었지만. Sql에 실제 쿼리의 개념을 가져올수 없어서 앤드포인트가 정해져 있었다. Graphql로 이를 해결할 수 있다.

graphQL 플레이그라운드로 테스트 해볼수 있다. graphQL 플레이그라운드는 데스크탑 보전도 있는데 맥에서 홈브류로 설치할수 있다.

공용 graphQL api 를 사용하면 연습해보기 편하다. (ex 스타워즈 api)

쿼리를 보내면 정상적인 응답은 data키가 들어있는 json으로 응답하고, 에러일 경우 error키가 들어있는 json을 응답한다.

한번에 하나의 쿼리만 실행 가능하며 2개를 동시에 할수는 없다.

다만 한번에 정보를 다 받아오고 싶으면 한 쿼리안에 다 넣으면 된다.

별칭을 줘서 가져오고 싶다면 :을 이용하면 된다.

필터링해서 가져오고 싶다면 쿼리의 인자를 사용하면 된다.

필드는 스칼라 타입이나 객체타입 둘중에 하나다.

Graphql에서 스칼라는 (정수 실수 문자 불린 식별자)

문자열과 식별자타입은 똑같은 string타입으로 반환하기는 하지만, 아이디 식별자는 반드시 유일한 문자열이어야 한다.

Grpahql은 무방향 그래프 이므로 하나에 방향에서 일대다 관계라면 반대의 방향에서도 쿼리가 성립할수 있어야 한다.

Fragment를 사용하여 필드 그룹을 만들고 스프레드 문법차럼 사용하여 재활용할 수 있다.

인라인 플레그먼트를 사용하면 유니온처럼 사용할 수 있다.

이름 붙은 플레그먼트도 유니온처럼 사용할 수 있다.

Interface: 여러 타입이 “공통 필드”를 공유하도록 하는 추상 타입

뮤테이션

query 키워드는 읽기를 위한 플래그이며, 변경을 위해서는 mutation 플래그를 사용하면 된다.

mutation burnitDown {
  deleteAllData <~~ 잔부 다 지운다
}

서브스크립션

서브스크립션을 사용하면 사버로부터ㅜ실시간 뱐걍 정보를 받을 수 있다.

서브스크립션의 루트 키워드는 subscription이다

import { graphql, useSubscription } from 'react-relay';

const SONG_ADDED_SUBSCRIPTION = graphql`
  subscription SongAddedSubscription {
    songAdded {
      id
      title
      artist
    }
  }
`;

function SongList() {
  const { dispose } = useSubscription({
    subscription: SONG_ADDED_SUBSCRIPTION,
    variables: {},
    onNext: (data) => console.log(data),
  });

  // 구독 해지
  dispose();
}

인트로스팩션

__schema 이나 __type 같은 필드명을 사용해서 api 스키마에 세부사항을 알수있다.

추상구문트리

Graphql은 쿼리 문자열을 추상구문트리 ast로 구문분석하여 실행된다.

4장 스키마 설계하기

스키마정의를 위해 스키마 정의언어 sdl 을 지원.

타입

타입은 graphql의 핵심 단위

스키마는 주로 .graphql 확장자로 정의

타입뒤에 느낌표를 붙이면 null을 허용하지 않는다는 의미다.(타입스크립트랑은 틀림)

ID 스칼라 값은 고유한 식별자가 들어가는 곳에 쓰면 된다.

커스텀 스칼라

스키마 정의시 커스텀 스칼라값 정의 키워드는 scalar이고 리턴값은 json 문자열이다.(raphQL 스펙 상 스칼라는 문자열이어야 하기 때문에)

열거타입

스칼라값에 속하며 반환되는 문자열 세트를 미리 정해놓을 수 있다. 키워드는 enum

연결과 리스트

  • [String] 은 문자열.리스트를 정의한것이다.

  • [String!] 리스트안에오는 값이 null이 될수 없음을 뜻한다.

  • [String]! 후자는 리스트 값 자체가 널이 될수 없음을 뜻한다.

일대일 연결

두객체 사이에 연결은 엣지라고 한다.

두노드를 이어주는 단방향 엣지를 스키마로 표현할수 있음 postedBy: User 와 같이

일대다 연결

graphql은 되도록이면 무방향그래프가 좋다. 아무노드에서나 횡단을 시작할수 있는, 클라이언트 자유도가 늘어나기 때문이다.

유저는 여러개의 사진을 포스트 할수 있으므로 postedPhotos: [Photo!]! 로 표현할수 있다.

다대다 연결

말 그대로 양쪽으로 다중으로 연결되는 타입니다.

여러개의 관계 정보가 필요할 경우 관계객체를 따로 정의하여 관리할 수 있다. 이 책에서는 통과타입이라고 설명하고 있다.

(RDBMS에 조인테이블 같은이다)

여러 타입을 담는 리스트

예를들어 일정에는 여러종류에 이벤트가 있을수 있으며, 이벤트 타입에 따라 필드가 달라질수 있다.

(유니언타입이나 인터페이스를 사용하면 된다)

유니온

파이프 기호를 사용해서 이용가능

인터페이스

인터페이스로 특정 필드가 무조건 특장타입에 오도록 강제가능.

필드에 따라 객체가 완전히 선택적으로 나와야 한다면 유니온이나 인터페이스를 사용하는게 좋다. (유니온과 인터페이스는 사실 완전 틀린개념이다, 책에서는 편의상 두개를 비교 설명하고 있다)

인자

쿼리시 인자를 이용해 쿼리에 필요한 데이터를 전달 가능하다.

데이터 페이징

first 는 페이지 한장당 들어가는 레코드수, start는 시작위치를 지정하는데,

(필드명은 관례일뿐이라서 알아서 네이밍 하면 된다)

정렬

필요하다면 정렬타입과 오름차순 내림차순 같은 인자를 스키마에 설정 가능하다.

뮤테이션

쿼리와 뮤테이션의 스키마 정의는 큰 차이가 없다. 유일한 차이점은 뮤테이션은 동사로서의 역할을 한다.

뮤테이션 변수

변수 없이 (하드코딩):

mutation {
  createUser(name: "김철수", email: "kim@example.com") {
    id
    name
  }
}
  • 변수 사용:
mutation CreateUser($name: String!, $email: String!) {
  createUser(name: $name, email: $email) {
    id
    name
  }
}
  • 변수로 전달:
{
  "name": "김철수",
  "email": "kim@example.com"
}

인풋타입

인풋타입은 인자에서만 쓰이는 타입정의시 사용된다(객체타입과 사용법은 같다).

input 타입 안에서는 스칼라값이나 또 다른 input타입만 사용 가능

리턴타입

그냥 객체타입이랑 똑같이 씀.

서브스크립션

똑같음 특별한건 없음.

스키마 블록

schema {} 블록이 필요한 경우

커스텀 이름을 쓸 때만 필요하다.

type MyCustomQuery {
  users: [User!]!
}

type MyCustomMutation {
  createUser(name: String!): User
}

schema {
  query: MyCustomQuery
  mutation: MyCustomMutation
}

아래처럼 기본 네임 사용할꺼면 필요없음 schema 키워드 필요없음

type Query {
  # 쿼리들...
}

type Mutation {
  # 뮤테이션들...
}

type Subscription {
  # 구독들...
}

스키마 문서화

인스트로픽션 기능으로 사용자들이 확인할 문서를 작성 가능하다.

  • 타입, 필드: “”" 설명 “”" (3개)
  • 인자: “설명” (1개)

이렇게 해놓은 주석은 graphql 툴의 스키마에 나오게 되고, 인스트러픽션을 통해서도 확인 가능하다.

아래처럼

"""
사용자 정보를 나타내는 타입
여러 줄로 설명을 작성할 수 있어요
"""
type User {
  """
  사용자 고유 ID
  """
  id: ID!
  
  """
  사용자 이름
  """
  name: String!
  
  """
  사용자 이메일 주소
  """
  email: String!
}

type Query {
  """
  특정 사용자 조회
  ID로 사용자를 검색합니다
  """
  getUser(
    "조회할 사용자의 ID"
    id: ID!
  ): User
  
  """
  사용자 목록 조회
  """
  users(
    "페이지 번호"
    page: Int
    
    "페이지당 개수"
    limit: Int
  ): [User!]!
}

type Mutation {
  """
  새 사용자 생성
  """
  createUser(
    "사용자 이름"
    name: String!
    
    "이메일 주소"
    email: String!
  ): User
}

5장 GraphQL API만들기

아폴로를 사용한 graphql api 구현예제

apollo-server, graphql, nodemon 설치

리졸버

실제로 데이터를 가져오는건 스키마가 아닌 리졸버의 역할이다.

리졸버는 특정 필드의 결과를 반환하는 함수다.

리졸버와 typedef를 만들어서 아폴로 인스턴스 생성

const { ApolloServer } = require('@apollo/server');
const { startStandaloneServer } = require('@apollo/server/standalone');

// 1. TypeDef (스키마 정의)
const typeDefs = `
  type User {
    id: ID!
    name: String!
    email: String!
  }

  type Query {
    user(id: ID!): User
    users: [User!]!
  }

  type Mutation {
    createUser(name: String!, email: String!): User
  }
`;

// 2. Resolvers (실제 데이터 반환 함수)
const resolvers = {
  Query: {
    user: (parent, args, context) => {
      // args.id로 사용자 찾기
      return { id: args.id, name: "김철수", email: "kim@example.com" };
    },
    users: () => {
      return [
        { id: "1", name: "김철수", email: "kim@example.com" },
        { id: "2", name: "이영희", email: "lee@example.com" }
      ];
    }
  },
  Mutation: {
    createUser: (parent, args) => {
      // args.name, args.email로 사용자 생성
      return { id: "3", name: args.name, email: args.email };
    }
  }
};

// 3. Apollo Server 인스턴스 생성
const server = new ApolloServer({
  typeDefs,
  resolvers
});

// 4. 서버 시작
startStandaloneServer(server, {
  listen: { port: 4000 }
}).then(({ url }) => {
  console.log(`🚀 Server ready at ${url}`);
});

핵심:

  • typeDefs: 스키마 구조 정의
  • resolvers: 각 필드의 데이터 반환 함수
  • ApolloServer: 둘을 합쳐서 서버 생성!

리졸버는 graphql 구현의 핵심.

루트 리졸버

생략

타입 리졸버 (Trivial Resolver)

자동으로 계산되어 반환하는 필드 리졸버

  • 예제로 이해하기
const typeDefs = `
  type User {
    id: ID!
    name: String!
    email: String!
    fullInfo: String!  # 계산 필요
  }

  type Query {
    user(id: ID!): User
  }
`;

const resolvers = {
  Query: {
    user: () => {
      // User 객체 반환
      return {
        id: "1",
        name: "김철수",
        email: "kim@example.com"
        // fullInfo는 없음!
      };
    }
  },
  
  // 타입 리졸버 (User 타입의 필드들)
  User: {
    // ❌ 이런 건 안 써도 됨 (Trivial Resolver - 자동 처리)
    // id: (parent) => parent.id,
    // name: (parent) => parent.name,
    // email: (parent) => parent.email,
    
    // ✅ 계산이 필요한 필드만 명시
    fullInfo: (parent) => {
      return `${parent.name} (${parent.email})`;
    }
  }
};

인풋, 열거타입 사용하기

const typeDefs = `
  input CreateUserInput {
    name: String!
    email: String!
    age: Int
  }
  
  input UpdateUserInput {
    name: String
    email: String
  }

  type User {
    id: ID!
    name: String!
    email: String!
    age: Int
  }

  type Mutation {
    createUser(input: CreateUserInput!): User
    updateUser(id: ID!, input: UpdateUserInput!): User
  }
`;

const resolvers = {
  Mutation: {
    createUser: (_, { input }, { db }) => {
      const newUser = {
        id: Date.now().toString(),
        ...input  // name, email, age 펼치기
      };
      db.users.push(newUser);
      return newUser;
    },

    updateUser: (_, { id, input }, { db }) => {
      const user = db.users.find(u => u.id === id);
      
      // input에 있는 것만 업데이트
      if (input.name) user.name = input.name;
      if (input.email) user.email = input.email;
      
      return user;
    }
  }
};

사용 예시

# 생성
mutation {
  createUser(input: {
    name: "김철수"
    email: "kim@example.com"
    age: 25
  }) {
    id
    name
  }
}

# 수정
mutation {
  updateUser(id: "123", input: {
    name: "이영희"
  }) {
    id
    name
  }
}

핵심: input 객체로 받아서 input.필드명 접근

일대다 관계

다대다 관계

특별한건 없음 앞에 설명했던 것들을 활용해서 일대다 리졸버 만드는 예제 설명됨.

커스텀 스칼라

  • DateTime 커스텀 스칼라 예제!
const { ApolloServer } = require('@apollo/server');
const { GraphQLScalarType, Kind } = require('graphql');

// 1. TypeDef에 스칼라 선언
const typeDefs = `
  scalar DateTime
  
  type Post {
    id: ID!
    title: String!
    createdAt: DateTime!
    updatedAt: DateTime!
  }
  
  type Query {
    post(id: ID!): Post
  }
  
  type Mutation {
    createPost(title: String!): Post
  }
`;

// 2. 커스텀 스칼라 구현
const dateTimeScalar = new GraphQLScalarType({
  name: 'DateTime',
  description: 'Date and time in ISO 8601 format',
  
  // GraphQL → 클라이언트 (응답)
  serialize(value) {
    if (value instanceof Date) {
      return value.toISOString();  // Date → "2025-10-12T10:30:00.000Z"
    }
    throw Error('DateTime must be a Date object');
  },
  
  // 클라이언트 → GraphQL (요청)
  parseValue(value) {
    if (typeof value === 'string') {
      return new Date(value);  // "2025-10-12T10:30:00.000Z" → Date
    }
    throw Error('DateTime must be a string');
  },
  
  // AST → GraphQL (쿼리 리터럴)
  parseLiteral(ast) {
    if (ast.kind === Kind.STRING) {
      return new Date(ast.value);
    }
    return null;
  }
});

// 3. Resolvers에 스칼라 등록
const resolvers = {
  DateTime: dateTimeScalar,  // ⭐ 스칼라 추가!
  
  Query: {
    post: () => {
      return {
        id: "1",
        title: "GraphQL 배우기",
        createdAt: new Date(),  // Date 객체 반환
        updatedAt: new Date()
      };
    }
  },
  
  Mutation: {
    createPost: (_, { title }) => {
      return {
        id: Date.now().toString(),
        title,
        createdAt: new Date(),  // Date 객체
        updatedAt: new Date()
      };
    }
  }
};

// 4. 서버 생성
const server = new ApolloServer({
  typeDefs,
  resolvers
});

사용 예시

# 쿼리
query {
  post(id: "1") {
    title
    createdAt  # "2025-10-12T10:30:00.000Z" 형태로 반환
    updatedAt
  }
}

# 뮤테이션
mutation {
  createPost(title: "새 글") {
    id
    createdAt
  }
}
  • 더 간단한 방법 (라이브러리 사용)
const { DateTimeResolver } = require('graphql-scalars');

const resolvers = {
  DateTime: DateTimeResolver,  // ✅ 바로 사용!
  
  Query: {
    // ...
  }
};

apollo-server-express

apollo-server-express를 쓰면 Express 앱에 GraphQL을 통합할 수 있다. Express 편리한 기능과 graphql을 함께 사용가능. 기존 express 서비스 위에 함께 올릴수 있는 장점이 있음.

특별한건 없음 express로 graphql 서버구동하는 예제임.

컨텍스트

잔역에서 사용할 값을 저장해두면, 리졸버에서 접근하여 사용할 수 있다.

데이터베이스 연결 등을 저장

Graphql은 데이터베이스 종류에 영향을 받지않음

Graphql 서버 생성시 옵션으로 context 객체에 db 접근 객체를 넣어주는 방식으로 사용됨.

깃허브인증

컨텍스트는 객체나 함수로 만들수 있고 , 함수의 경우는 요청이 있을 때마다. 요청으로부터 컨텍스트를 만들어 리턴하는 형태로 구현해야 한다.

Oauth로 엑세스토큰을 유저 세션디비에 저장해 놓고 요청이 올때마다 헤더의 토큰값이 디비에 저장된 값과 맞는지 체크하는 방식으로 인증처리

6장 GraphQL 클라이언트

HTTP 요청을 보낼 수 있는 최소한의 환경만 있으면, graphql을 사용할 수 있다.

graphql-request

Curl 이나 fetch 말고도 데이터를 요청할수 있는 방법이 있는데 그 중 하나가 graphql-request이다.

  • fetch = 만능 도구

    • 모든 HTTP 요청 가능
    • 보일러플레이트 많음
    • 직접 다 작성
  • graphql-request = GraphQL 전용

    • GraphQL만 지원
    • 간결하고 편함
    • 자동 처리 많음
  • Apollo Client = 풀옵션

    • 캐싱, 상태관리
    • 무겁고 복잡
    • 대규모 앱용

아폴로 클라이언트

Rest에 비해 캐싱이 어려운데 아폴로나 릴레이 클라이언트를 이용하면 캐싱 문제에 도움을 받을 수 있다.

릴레이는 리액트와 리액트 네이티브에서만 작동. 그래서 아폴로가 나옴

의존성 설치 graphql apolli-boost react-apollo 설치 필요.

아폴로는 네트워크 요청 외에 응답을 로컬 메모리에 캐싱하는 역할도 하며 client.extract 로 캐시 상태를 확인해볼수도 있다.

케시타임과 같은 변경도 설정을 통해 가능하다.

ApolloProvider 컴포넌트로 클라이언트를 연결하고 , Query컴포넌트로 데이터 패칭 가능.

Query 컴포넌트는 리패치, 폴링, 페이징, 등의 기능을 제공.(예제보면 바로 이해감 쉬움)

뮤테이션 컴포넌트

Mutation 컴포넌트 내에서 mutation 함수 연결가능 . refetchingQuery 프로퍼티를 이용해 뮤테이셔뉴완료 후 다시 불러오기 가능.

인증

Apollo Client 생성 시 request 옵션에 헤더 추가 옵션에 auth token을 넣을 수 있음

캐시작업

요청을 최소화 하기 위한 아폴로 캐시전략

cache-first (기본값)
  • 캐시 있으면 캐시만, 없으면 서버 요청
  • 가장 빠르고 효율적
  • 대부분의 경우 사용
cache-and-network
  • 캐시 먼저 보여주고 + 서버도 요청해서 업데이트
  • 실시간 데이터에 사용 (SNS 피드, 대시보드)
  • 2번 렌더링됨
network-only
  • 항상 서버 요청, 결과는 캐시에 저장
  • 새로고침, 최신 데이터 필요할 때
  • 캐시 혜택도 받을 수 있음
no-cache
  • 항상 서버 요청, 캐시에 저장 안 함
  • 민감한 데이터 (신용카드, 비밀번호)
  • 캐시 완전히 무시
cache-only
  • 캐시만 사용, 서버 요청 절대 안 함
  • 캐시 없으면 에러
클라이언트에 캐시유지

apollo-cache-persist 와 같은 라이브러리로 캐시를 클라이언트에 유지시킬 수 있다. 캐시가 바뀔 때마다 로컬스토리지에 저장하는 방식이다.

캐시 업데이트

Apollo Client의 InMemoryCache에서 캐시를 직접 읽거나 쓸 수 있다. 캐시를 직접 업데이트하면 UI가 자동 반영된다.

7장 실제 제품을위한 graphql

클라이언트와 서버간에 파일공유와 웹소켓을 통한 실시간 연결과 api보안

서브스크립션

웹소켓을 이용해 실시간 통신도 graphql을 통해 할 수 있다.

아폴로 서버에는 기본적으로 서버스크립션 기능이 탑제되어 있다.

graphql-subscription 모듈과 subscription-transport-ws 모둘 설치 필요

apollo-server-express 를 이용해 서브스크립트 를 위해 웹소켓 서비스를 인의의 포트 4000번으로 띄움.

  • 스키마 추가
type Subscription {
  newPhoto: Photo!
}
  • 서버에서 클라이언트로 graphql을 이용해 푸시 보냄
subscription {
  newPhoto {
    url
    category
  }
}

리졸버 구현언 Query와 Mutation과는 다르게 타입안에 subscription 메서드를 구현한다.

클라이언트가 graphql 쿼리를 통해 연결을 하면, 뮤테이션으로 변경이 될 때마다 데이터가 서브스크립션으로 전송된다.

서브스크립션 데이터 사용하기(클라이언트)

클라이언트는 wshttpLink를 연결해놓는다.

Query 와 Mutation 은 http를 이용하고 서브스크립션은 ws를 이용해 처리된다.

ApolloLink를 이용해서 특별한 기능의 헤더를 추가하는 링크를 httpLink와 연동하여 만들 수 있다.

apollo-boostsplit 함수로 쿼리인지 서브스크립션인지 확인하여 ws으로 버낼지 authLink로 보낼지 분기할수 있다.

Mutation 컴포넌트의 사용법과 비슷하게 Subscription 컴폰넌트를 사용하여 서버로 부터 정보를 받을 수 있다.

첫번째 subscription 메서드는 서버로부터 연결 요청을 해서 옵저버 객체를 받고, 두번째 subscription에 등록된 함수로 데이터를 전달 받는다.

GraphQL 스펙은 “subscription은 WebSocket을 써라” 같은 네트워크 규칙을 정의하지 않는다. Apollo Client도 기본적으로 HTTP 기반이라, Subscription을 위한 별도의 네트워크 경로(WebSocket)를 자동으로 선택할 수 없다. 그래서 개발자가 split()으로 직접 “이 Operation은 WebSocket으로 보내라”고 분기해줘야 한다.

파일 업로드

apollo-upload-clientapollo-upload-server 를 이용해 멀티파트 업로드가 가능하더록 한다. apollo-upload-server 는 아폴로 서버에 내장되어 있다.

const { uploadStream } = require('../lib')
const path = require('path')

async postPhoto(root, args, { db, currentUser, pubsub }) {
  
  // 1. 파일 저장 경로 생성
  const toPath = path.join(
    __dirname, 
    '..', 
    'assets', 
    'photos', 
    `${photo.id}.jpg`  // 템플릿 리터럴 수정
  )
  
  // 2. 업로드된 파일 스트림 받기
  const { stream } = await args.input.file
  
  // 3. 파일을 서버에 저장
  await uploadStream(stream, toPath)
  
  // 4. 실시간 구독자들에게 새 사진 알림
  pubsub.publish('photo-added', { newPhoto: photo })
  
  return photo
}

대층 이런식으로 리졸버 구현.

보안

요청 타임아웃

express 에서 요청 타임아웃 설정 가능하며, grpahql 리절버에서도 타임아웃 설정가능

데이터 제한

예를 들면 페이징 기능을 만들어 스키마에 특정 기능이 들어가 있을 경우, 리졸버 에서 한페이지에 너무 많은 데이터를 row를 제한하도록 구현할 수 있다.

쿼리 깊이제한

쿼리의 깊이가 많아지면 데이터의 양도 많아지므로 제한하는게 좋다.

graphql-depth-limit 같은 라이브러리를 사용하면 쿼리의 ast 를 분석하여 쿼리 깊이를 알아내어 제한을 걸 수 있다.

쿼리 복잡도 제한

이것도 깊이제한과 비슷한 방식으로 구현하여 제한 가능하다. 이런 제한을 쉽게 구현하는 라이브러리도 존재한다.

아폴로 엔진

아폴로 엔진으로 서비스 모니터링 가능

아폴로 서버에 이미 모니터링 기능이 내장되어 있으므로, 플래그만 켜서 서버를 구동하면 된다.

점진적 마이그레이션

스키마 주도개발

벡엔드 프런트엔드간의 커뮤니테이션에는 스키마 주도 개발이 효과적이다.

스키마를 먼저 확보하면 프론트엔드와 백엔드가 병행하여 개발할수 있으므로 개발속도를 단축시킬 수 있다.

아폴러 서버는 혁신적인 모킹 툴을 제공한다 (타입에 따라 자동으로 그럴듯 한 값을 채워서 반환해준다).

아마존 서비스(AWS AppSync)를 이용하면 간단하게 graphql 서버를 구축가능 하다.