한양과학기술고등학교

에듀테크 프로젝트 대시보드

GraphQL vs REST

🔵 REST 방식 엔드포인트 여러 개
"사용자 1명 + 그 사람 글 목록 + 각 글의 댓글"을 가져오려면 여러 번 왕복해야 합니다.
GET/users/1사용자 정보
GET/users/1/posts글 목록
GET/posts/101/comments댓글(글1)
GET/posts/102/comments댓글(글2)
🩷 GraphQL 방식 엔드포인트 1개
똑같은 요구사항을 쿼리 하나로 표현해서 단일 엔드포인트 POST /graphql 에 보냅니다.
query { user(id: 1) { name posts { title comments { text } } } }
📋 네트워크 로그 실시간
// 버튼을 눌러 요청을 보내보세요...
📊 왕복(round-trip) 횟수
REST 요청 수 0
GraphQL 요청 수 0
🎯 필드 선택으로 보는 오버페칭 vs 언더페칭
체크박스로 화면에 실제로 필요한 필드만 골라보세요. REST는 서버가 정해둔 고정 응답을 그대로 주지만(과다·부족 발생), GraphQL은 요청한 필드만 정확히 돌려줍니다.
REST 응답 고정 스키마
응답 크기(추정) —
GraphQL 응답 선택한 필드만
응답 크기(추정) —
⚠️ N+1 문제 리졸버 함정
글 목록을 가져온 뒤 각 글마다 작성자를 따로 조회하면, 글이 N개일 때 쿼리는 1(글 목록) + N(작성자)번 실행됩니다. GraphQL 자체의 문제가 아니라 리졸버를 순진하게 짤 때 생기는 함정이며, DataLoader로 배치 처리해 해결합니다.
DataLoader 배치 적용 OFF
// 실행 버튼을 눌러보세요...
실행된 DB 쿼리 수 0
🐍 서버 쪽 코드 예시 (Strawberry + FastAPI)
@strawberry.type class User: id: int name: str email: str @strawberry.field def posts(self) -> list["Post"]: # ❌ 이렇게 짜면 글마다 DB를 또 조회 → N+1 return db.query(Post).filter(Post.user_id == self.id).all() @strawberry.type class Query: @strawberry.field def user(self, id: int) -> User: return db.query(User).get(id) schema = strawberry.Schema(query=Query) graphql_app = GraphQLRouter(schema) app.include_router(graphql_app, prefix="/graphql") # 엔드포인트는 이거 하나뿐!
📐 한눈에 비교
기준RESTGraphQL
엔드포인트자원마다 여러 개 (/users, /posts, ...)단일 엔드포인트 (/graphql)
응답 모양서버가 정한 고정 스키마클라이언트가 쿼리로 지정
흔한 문제오버/언더페칭, 화면마다 새 엔드포인트N+1 쿼리, 캐싱이 더 복잡함
HTTP 캐싱GET + URL 기반 캐싱 쉬움대부분 POST라 표준 캐싱 어려움
대표 사용처공개 API, 단순 CRUD 서비스GitHub API v4, Shopify, 복잡한 화면 다수