본문 바로가기
Dev/Backend

GraphQL이란?

by haerr 2025. 7. 3.

정의

GraphQL은 API를 위한 쿼리 언어(query language)이고, 서버에서 이 쿼리를 실행해주는 런타임(runtime)이다.

 

핵심 개념

  • 어떤 데이터를 요청할 수 있을지 “타입 시스템(type system)” 으로 미리 정의해둠
  • 클라이언트는 이 타입에 맞춰 데이터를 정확하게 원하는 만큼만 요청할 수 있음
  • 기존 데이터베이스나 코드 위에서 작동하며, 특정 DB에 종속되지 않음

 

어떻게 쓰는지 보기

GraphQL을 구성하는 방법은 크게 두 가지이다.

1. 타입 정의 (Type Definitions)

예를 들어 사용자(User)의 이름(name)을 가져오고 싶다면

type Query {
  me: User
}

type User {
  name: String
}
  • Query는 데이터의 입구라고 보면 됨
  • me라는 필드는 로그인한 사용자를 나타냄
  • User 타입에는 name이라는 문자열이 있음

 

2. 리졸버 (Resolver): 데이터를 실제로 가져오는 함수

예를 들어 로그인한 사용자의 정보를 가져오는 리졸버

function resolveQueryMe(_, _, context) {
  return context.request.auth.user; // 로그인한 사용자 정보
}

function resolveUserName(user, _, context) {
  return context.db.getUserFullName(user.id); // DB에서 이름 가져오기
}

리졸버는 실제로 어디서 데이터를 가져올지 정의하는 함수라고 생각하면 된다. (예: 데이터베이스, 인증 정보 등)

 

정확히 필요한 데이터만 요청한다!

GraphQL의 핵심 장점은 내가 필요한 데이터만, 정확히 그만큼만 요청할 수 있다는 것이다.

{
  me {
    name
  }
}

응답:

{
  "data": {
    "me": {
      "name": "Luke Skywalker"
    }
  }
}

장점:

  • API 하나로 여러 데이터 요청 가능
  • 필요한 필드만 선택 가능 (오버페칭/언더페칭 방지)
  • 응답 구조도 요청과 동일해서 다루기 쉬움

 

API 버전 관리 없이 진화한다!

기존 REST API는 버전을 여러 개 관리해야 함 (v1, v2 등).

GraphQL은 필드를 점진적으로 추가하거나 제거하면 됨.

예:

type User {
  fullName: String
  nickname: String
  name: String @deprecated(reason: "Use `fullName`.")
}
  • 기존 name 필드는 여전히 쓸 수 있지만, 이제는 fullName을 권장함
  • 이렇게 하면 기존 사용자도 문제 없이 사용 가능

 

직접 써보자!

예를 들어 Star Wars API처럼 이런 쿼리를 써볼 수 있다.

{
  hero {
    name
  }
}

결과:

{
  "data": {
    "hero": {
      "name": "R2-D2"
    }
  }
}

hero에 id나 appearsIn 같은 필드를 추가하면 더 많은 정보를 받을 수 있다.

 

 

아주 도움되는 블로그

https://tech.kakao.com/posts/364