eatthefrog
GraphQL: A query language for your API 공식문서 읽기 본문
GraphQL | A query language for your API
Evolve your API without versions Add new fields and types to your GraphQL API without impacting existing queries. Aging fields can be deprecated and hidden from tools. By using a single evolving version, GraphQL APIs give apps continuous access to new feat
graphql.org
A query(데이터 요청 방식) language for your API
GraphQL is a query language for APIs and a runtime(엔진) for fulfilling(데이터 가져오기) those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.
Ask for what you need, get exactly that
Send a GraphQL query to your API and get exactly what you need, nothing more and nothing less. GraphQL queries always return predictable results. Apps using GraphQL are fast and stable because they control the data they get, not the server. (클라이언트가 데이터를 제어한다.)
전통적인 REST API 방식: 서버가 응답 데이터를 결정한다.
// REST 응답 예시 - 서버가 모든 데이터를 결정
//✅ /api/users/123 요청 시, 서버가 미리 정의한 모든 사용자 정보를 반환
//✅ 클라이언트가 name과 email만 필요해도 id, address,phone,created_at등 모든 필들르 받음
//✅ 서버 개발자가 엔드포인트와 응답 구조를 결정
{
"id": "123",
"name": "김철수",
"email": "kim@example.com",
"phone": "010-1234-5678",
"address": "서울시 강남구...",
"created_at": "2023-01-15",
"last_login": "2024-06-18"
}
새로운 GraphQL 방식: 클라이언트가 필요한 데이터를 정확히 명시한다.
# 클라이언트가 필요한 데이터만 요청
// ✅ 클라이언트가 쿼리에서 원하는 필드만 요청 => 클라이언트가 데이터의 모양(shape)를 결정
query {
user(id: "123") {
name
email
}
}
// GraphQL 응답 - 클라이언트가 요청한 데이터만
// ✅ 서버는 요청된 필드만 응답으로 반환
{
"data": {
"user": {
"name": "김철수",
"email": "kim@example.com"
}
}
}
Get many resources in a single request
GraphQL queries access not just the properties of one resource(하나의 리소스 속성) but also smoothly follow references between them(리소스 간 참조를 매끄럽게 따라가기) While typical REST APIs require loading from multiple URLs, GraphQL APIs get all the data your app needs in a single request. Apps using GraphQL can be quick even on slow mobile network connections.
Resouce는 API에서 하나의 개체(entity)를 의미하고, Properties는 그 개체의 속성들이다.
# GraphQL Type (틀)
type User {
id: ID!
name: String!
email: String!
}
# User 리소스의(Entity)의 Properties
{
"id": "123",
"name": "김철수",
"email": "kim@example.com"
}
References는 한 리소스가 다른 리소스를 참조하는 관계를 의미한다. GraphQL은 이런 관계를 하나의 쿼리로 매끄럽게 탐색할 수 있다.
REST API 방식 : 여러 개의 URL에 각각 요청 -> 네트워크 왕복 여러 번
# 1단계: 사용자 정보 가져오기
GET /api/users/123
# 응답: { "id": "123", "name": "김철수", "postIds": [1, 2, 3] }
# 2단계: 사용자의 게시글들 가져오기
GET /api/posts?userId=123
# 응답: [{ "id": 1, "title": "첫 번째 글", "authorId": "123" }, ...]
# 3단계: 각 게시글의 댓글 가져오기
GET /api/posts/1/comments
GET /api/posts/2/comments
GET /api/posts/3/comments
GraphQL 방식 : 하나의 쿼리로 연관 데이터 모두 가져오기 -> 네트워크 왕복 1번
# 한 번의 쿼리로 연관된 모든 데이터 가져오기
query {
user(id: "123") {
name # user의 property
email # user의 property
posts { # ✅ user → posts 참조 따라가기
title # post의 property
content # post의 property
comments { # ✅ post → comments 참조 따라가기
author { # ✅ comment → author 참조 따라가기
name # author의 property
}
content # comment의 property
}
}
}
}
# 실제 응답 예시
{
"data": {
"user": {
"name": "김철수",
"email": "kim@example.com",
"posts": [
{
"title": "첫 번째 글",
"content": "안녕하세요...",
"comments": [
{
"author": { "name": "이영희" },
"content": "좋은 글이네요!"
}
]
}
]
}
}
}

Describe what's possible with a type system
GraphQL APIs are organized in terms of types and fields(타입과 필드로 구성), not endpoints(URL경로). Access the full capabilities of your data(데이터의 모든 기능) from a single endpoint(하나의 URL). GraphQL uses types to ensure Apps(타입으로 앱 보장) only ask for what's possible and provide clear and helpful errors. Apps can use types to avoid writing manual parsing code.(수동 파싱 코드)
1. 타입과 필드로 구성
REST API - Endpoint 중심
# 엔드포인트별로 구성
GET /api/users # 사용자 목록
GET /api/users/123 # 특정 사용자
GET /api/posts # 게시글 목록
GET /api/users/123/posts # 특정 사용자의 게시글
GraphQL - Types와 Fileds 중심
# 타입과 필드로 구성된 스키마
type User {
id: ID!
name: String!
email: String!
posts: [Post!]! # User 타입의 posts 필드
}
type Post {
id: ID!
title: String!
content: String!
author: User! # Post 타입의 author 필드
}
2. 타입 시스템이 앱이 올바른 데이터만 요청하도록 보장한다.
type User {
id: ID!
name: String!
age: Int!
}
# ✅ 올바른 쿼리
query {
user(id: "123") {
name # String 타입
age # Int 타입
}
}
# ❌ 잘못된 쿼리 - 컴파일 시점에 에러
query {
user(id: "123") {
invalidField # 존재하지 않는 필드
name { # String인데 객체처럼 접근
firstName
}
}
}
3. REST에서는 수동 파싱 VS GraphQL에서는 타입 시스템으로 자동화
// REST API 응답 수동 파싱
const response = await fetch('/api/users/123');
const data = await response.json();
// 수동으로 데이터 구조 확인하고 파싱
if (data && data.user) {
const name = data.user.name || 'Unknown';
const email = data.user.email || '';
// 필드 존재 여부를 수동으로 체크
}
// GraphQL + TypeScript - 자동 타입 생성
interface User {
id: string;
name: string;
email: string;
}
// 타입이 보장되므로 안전하게 접근
const user: User = await graphqlClient.query(GET_USER);
console.log(user.name); // 타입 안전성 보장
전체적인 차이점 요약
| 구분 | REST API | GraphQL |
| 구성 방식 | URL 엔드포인트 중심 | 타입과 필드 중심 |
| 접근점 | 여러 엔드포인트 | 단일 엔드포인트 |
| 데이터 접근 | 여러 요청 필요 | 한 번의 쿼리로 모든 관계 탐색 |
| 타입 안전성 | 런타임에 확인 | 컴파일 시점에 확인 |
| 파싱 | 수동 파싱 필요 | 타입 시스템으로 자동화 |
Move faster with powerful developer tools
Know exactly what data you can request from your API without leaving your editor, highlight potential issues before sending a query, and take advantage of improved code intelligence. GraphQL makes it easy to build powerful tools like GraphiQL by leveraging your API’s type system.
https://github.com/graphql/graphiql
GitHub - graphql/graphiql: GraphiQL & the GraphQL LSP Reference Ecosystem for building browser & IDE tools.
GraphiQL & the GraphQL LSP Reference Ecosystem for building browser & IDE tools. - graphql/graphiql
github.com
Evolve your API without versions
Add new fields and types to your GraphQL API without impacting existing queries(기존 쿼리에 영향주기). Aging fields can be deprecated(오래된 필드 지원 중단) and hidden from tools(도구에서 숨기기). By using a single evolving version(단일 진화 버전), GraphQL APIs give apps continuous access to new features(점진적 기능 채택으로 클라이언트가 원하는 속도로 업데이트 가능) and encourage cleaner, more maintainable server code.
1. REST API 문제점 - 기존 쿼리에 영향 VS GraphQL - 기존 쿼리에 영향 없음
# v1 API
GET /api/v1/users
# 응답: { "id": 1, "name": "김철수", "email": "kim@example.com" }
# v2 API - 필드명 변경으로 기존 클라이언트 영향
GET /api/v2/users
# 응답: { "id": 1, "fullName": "김철수", "emailAddress": "kim@example.com" }
# 기존 클라이언트가 "name" 필드를 찾지 못함 → 에러 발생
# 기존 쿼리 (계속 작동)
query {
user(id: "123") {
name # 기존 필드 유지
email # 기존 필드 유지
}
}
# 새 기능 추가 후에도 위 쿼리는 여전히 작동
type User {
id: ID!
name: String! # 기존 필드 유지
email: String! # 기존 필드 유지
fullName: String! # 새 필드 추가
profileImage: String # 새 필드 추가
socialLinks: [Link!] # 새 타입과 필드 추가
}
2. GraphQL 오래된 필드 지원 중단 - Deperacted 표시로 마이그레이션 가이드 제공, 클라이언트에 경고 보여줌
=> 추후 단계적 제거 과정을 거치거나 도구에서 숨기기 가능하다.
type User {
id: ID!
name: String! @deprecated(reason: "Use 'fullName' instead")
fullName: String!
email: String! @deprecated(reason: "Use 'primaryEmail' instead")
primaryEmail: String!
}
// GraphQL 도구들이 deprecated 필드 사용 시 경고 표시
query {
user(id: "123") {
name # ⚠️ Warning: Field 'name' is deprecated. Use 'fullName' instead
fullName # ✅ 권장되는 새 필드
}
}
3. REST의 여러 버전 관리 문제 VS GraphQ의 단일 진화 버전으로 버전 관리 부담 없이 하나의 스키마만 관리하면 된다.
# 여러 버전을 동시에 유지해야 함
/api/v1/users # 버전 1
/api/v2/users # 버전 2
/api/v3/users # 버전 3
# 서버에서 3개 버전 모두 유지
// v1 컨트롤러
@GetMapping("/api/v1/users")
public UserV1 getUserV1() { ... }
// v2 컨트롤러
@GetMapping("/api/v2/users")
public UserV2 getUserV2() { ... }
// v3 컨트롤러
@GetMapping("/api/v3/users")
public UserV3 getUserV3() { ... }
# 항상 하나의 스키마만 유지
# /graphql (버전 표시 없음)
type User {
id: ID!
# 진화하는 필드들
name: String! @deprecated(reason: "Use 'fullName'")
fullName: String!
email: String! @deprecated(reason: "Use 'primaryEmail'")
primaryEmail: String!
# 새로 추가된 필드들
avatar: String
preferences: UserPreferences
}
Bring your own data and code
GraphQL creates a uniform API(통일된 API) across your entire application without being limited by a specific storage engine(데이터를 실제로 저장하고 관리하는 시스템:MySQL, MogoDB, Redis, 외부API). Write GraphQL APIs that leverage(활용하다) your existing data and code with GraphQL engines available in many languages. You provide functions for each field in the type system, and GraphQL calls them with optimal concurrency(자동으로 쿼리를 최적화하고 효율적으로 동시에 처리한다).
애플리케이션 전체에 걸쳐 통일된 API
기존 방식 - 여러 API들이 각각 다른 형태
// 다양한 데이터 소스들이 각각 다른 API 형태
const userService = {
getUser: (id) => fetch(`/rest/users/${id}`), // REST
updateUser: (data) => fetch('/rest/users', {...})
};
const paymentService = {
charge: (amount) => stripe.charges.create({...}), // Third-party API
refund: (chargeId) => stripe.refunds.create({...})
};
const analyticsService = {
trackEvent: (event) => analytics.track(event), // Analytics API
getMetrics: () => mixpanel.query({...})
};
GraphQL-모든 것을 하나의 통일된 API로 관리 가능
# 모든 데이터 소스가 하나의 통일된 스키마로 표현
type Query {
user(id: ID!): User # 사용자 데이터 (DB)
order(id: ID!): Order # 주문 데이터 (DB)
weather: Weather # 외부 API
analytics: Analytics # 분석 데이터
}
type Mutation {
updateUser(input: UserInput!): User # 사용자 업데이트
createPayment(input: PaymentInput!): Payment # 결제 처리
trackEvent(event: EventInput!): Boolean # 이벤트 추적
}'백엔드 노트' 카테고리의 다른 글
| CI/CD 개발 프로세스 (0) | 2025.06.24 |
|---|---|
| GraphQL 핵심 요약 (2) | 2025.06.18 |
| Apollo Server로 GraphQL API 만들기 (0) | 2025.06.16 |
| REST API의 한계와 GraphQL (2) | 2025.06.16 |
| 백엔드 개발자들이 실제로 회사에서 하는 일 (3) | 2024.12.16 |