Relay Specification이란?
Relay Specification은 Facebook이 GraphQL 클라이언트 라이브러리 Relay를 위해 정의한 서버 규격이다. 페이지네이션, 객체 식별, 뮤테이션 응답에 대한 표준 패턴을 제공한다.
Relay 전용이 아니라 GraphQL 생태계 전반에서 사실상 표준(de facto standard)으로 채택되었다. GitHub API, Shopify API, Saleor 등 대규모 GraphQL API가 이 규격을 따른다.
세 가지 핵심 규격
1. Connection (Cursor 기반 페이지네이션)
목록 데이터를 edges + node + pageInfo 구조로 반환하는 패턴이다. offset 기반 페이지네이션의 한계(데이터 삽입/삭제 시 중복·누락)를 해결한다.
query {
users(first: 10, after: "cursor_abc") {
edges {
cursor
node {
id
name
}
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
totalCount
}
}| 구성 요소 | 역할 |
|---|---|
edges | 각 항목을 cursor + node로 감싼 배열 |
node | 실제 데이터 객체 |
cursor | 해당 항목의 위치를 나타내는 불투명(opaque) 문자열 |
pageInfo | 페이지 탐색 메타데이터 |
페이지네이션 인자:
first/after— 앞에서부터 N개, cursor 이후last/before— 뒤에서부터 N개, cursor 이전
2. Global Object Identification (Node Interface)
모든 객체가 Node 인터페이스를 구현하고, 전역적으로 유일한 id를 가진다. 루트에 node(id: ID!) 쿼리를 두어 타입에 관계없이 아무 객체나 ID 하나로 조회할 수 있다.
interface Node {
id: ID!
}
type Query {
node(id: ID!): Node
}이를 통해 클라이언트는 캐시 키로 id를 사용하고, 객체를 정규화하여 저장할 수 있다.
3. Mutation Convention
뮤테이션의 입력과 출력을 일관된 구조로 정의한다:
- 입력: 단일
input인자로 묶음 - 출력: 변경된 객체와 관련 연결을 포함하는 전용 Payload 타입
mutation {
createUser(input: { name: "Kim", email: "kim@example.com" }) {
user {
id
name
}
errors {
field
message
}
}
}Offset vs Cursor 페이지네이션
| 항목 | Offset (skip/limit) | Cursor (Relay) |
|---|---|---|
| 데이터 변동 시 | 중복·누락 발생 가능 | cursor 기준으로 안정적 |
| 임의 페이지 접근 | 가능 (page=5) | 불가 (순차 탐색만) |
| 성능 | 큰 offset에서 느려짐 | cursor 인덱스로 일정한 성능 |
| 실시간 피드 | 부적합 | 적합 |
관련 문서
- GraphQL — Relay Specification이 적용되는 API 쿼리 언어