[프롬프트] GraphQL 쿼리 설계 프롬프트 - 최적 프롬프트 레시피
💡 한 줄 요약: "GraphQL 쿼리 짜줘"라는 단순 질의 시 발생하는 무한 중첩 N+1 쿼리 폭탄, 프래그먼트 결여로 인한 코드 중복, 비표준 오프셋 페이징 문제를 차단하고, Principal GraphQL Architect 및 Staff API Tech Lead 관점에서 Relay 커서 페이지네이션(Connection/Edge), DataLoader 배치 최적화, 쿼리 복잡도/깊이 제한, 실시간 웹소켓 구독(Subscription) 및 낙관적 UI 뮤테이션까지 완벽히 설계하는 최적 프롬프트 레시피입니다.
1. 페인포인트 & 작업 목표
user -> posts -> comments -> author -> posts... 형태로 이어지는 무한 중첩 쿼리를 그대로 생성하여 데이터베이스 Connection Pool을 고갈시키고 백엔드 장애를 유발함.limit/offset 방식의 레거시 페이징을 작성하여 데이터 실시간 추가/삭제 시 중복 노출 문제를 유발하고, 글로벌 클라이언트 캐시 정규화(id 기반 캐시)를 무력화함.errors 배열에 비즈니스 예외 코드(extensions.code)를 정의하지 않거나, Mutation 결과로 변경된 객체 대신 단순 불리언({ success: true })만 반환하여 Apollo/Relay 클라이언트 캐시 자동 갱신을 차단함.id/__typename 포함 규칙, GraphQL Subscriptions 및 낙관적 업데이트(Optimistic Updates) 페이로드 설계.2. 프롬프트 레시피 비교
❌ 레시피 A: 기본형 (단순 질의 초안)
역할 정의, 스키마 제약, 페이지네이션 표준, N+1 방지 규칙 없이 단순 쿼리 작성만 요청하는 초안입니다.
[영문 프롬프트 (복사용)]
Write a GraphQL query for: [feature][한글 프롬프트 (1:1 매칭 복사용)]
다음 기능에 대한 GraphQL 쿼리를 작성해줘: [기능명]limit/offset 기반의 비효율적 쿼리를 내놓습니다.⚡ 레시피 B: Principal GraphQL Architect 실무 종결형 GraphQL 쿼리 & 스키마 설계 프롬프트
Relay 커서 페이지네이션, DataLoader N+1 방지 지침, 쿼리 복잡도/깊이 제한, 컴포넌트 프래그먼트화, 에러 익스텐션 규격을 완벽히 명시하여 대규모 B2B 프로덕션 환경에 최적화된 쿼리와 리졸버 스키마를 도출하는 레시피입니다.
[영문 프롬프트 (복사용)]
You are a Principal GraphQL Architect and Staff API Tech Lead.
Design a robust, enterprise-grade GraphQL query, mutation schema, and resolver architecture for the target feature described below.
### Target Feature & Domain Context:
- Domain Service: [e.g., B2B Enterprise Workspace Dashboard & Audit Activity Feed]
- Core Entities: [e.g., Workspace, Project, Member, ActivityLog, Comment]
- Performance Constraints: [e.g., 50,000 active members, high-frequency updates, SLA < 150ms]
### GraphQL Engineering Directives:
1. PAGINATION & SCHEMA SPECIFICATION:
- Adhere strictly to the Relay Cursor Connections Specification (Connection, Edge, Node, PageInfo with hasNextPage, hasPreviousPage, startCursor, endCursor).
- Require `first`/`after` or `last`/`before` cursor arguments; strictly forbid offset-based parameters.
2. N+1 PREVENTION & DATALOADER MAPPING:
- Specify DataLoader batch loading keys for all relational fields (e.g., authors, project references).
- Include batching mechanism logic and schema directive hints (@complexity, @depth).
3. FRAGMENT MODULARITY & CLIENT COLOCATION:
- Deconstruct complex queries into cohesive, UI-component-driven fragments (e.g., MemberAvatarFragment, ActivityCardFragment).
- Ensure globally unique `id` and `__typename` are explicitly queried for client cache normalization.
4. QUERY COMPLEXITY & DEFENSE-IN-DEPTH:
- Enforce query depth limits (max depth: 4) and complexity calculation rules (assign field weights).
5. STRUCTURED ERROR HANDLING:
- Define GraphQL error responses adhering to RFC/Apollo error extensions: `extensions.code`, `extensions.timestamp`, and field-level validation errors.[한글 프롬프트 (1:1 매칭 복사용)]
당신은 수석 GraphQL 아키텍트(Principal GraphQL Architect)이자 스태프 API 테크 리드(Staff API Tech Lead)입니다.
아래 설명된 대상 기능에 대해 견고하고 엔터프라이즈급인 GraphQL 쿼리, 뮤테이션 스키마, 리졸버 아키텍처를 설계하십시오.
### 대상 기능 및 도메인 컨텍스트:
- 도메인 서비스: [예: B2B 엔터프라이즈 워크스페이스 대시보드 및 감사 활동 피드]
- 핵심 엔티티: [예: 워크스페이스(Workspace), 프로젝트(Project), 멤버(Member), 활동로그(ActivityLog), 댓글(Comment)]
- 성능 제약: [예: 50,000 활성 사용자, 고빈도 활동 업데이트, 엄격한 SLA 응답시간 150ms 미만]
### GraphQL 엔지니어링 필수 지침:
1. 페이지네이션 및 스키마 규격:
- Relay 커서 연결 규격(Relay Cursor Connections Specification: Connection, Edge, Node, PageInfo)을 엄격히 준수하십시오.
- `first`/`after` 또는 `last`/`before` 커서 인자를 필수로 요구하고, 오프셋 기반 인자를 전면 금지하십시오.
2. N+1 방지 및 DataLoader 매핑:
- 모든 연관 필드(예: 작성자, 프로젝트 참조)에 대한 DataLoader 배치 로딩 키를 명시하십시오.
- 배치 처리 메커니즘 로직과 스키마 지시어 힌트(@complexity, @depth)를 포함하십시오.
3. 프래그먼트 모듈화 및 클라이언트 컴포넌트 연계:
- 복합 쿼리를 응집도 높은 UI 컴포넌트 중심 프래그먼트(예: MemberAvatarFragment, ActivityCardFragment)로 분해하십시오.
- 클라이언트 캐시 정규화를 위해 전역 고유 식별자 `id`와 `__typename`을 반드시 쿼리에 포함하십시오.
4. 쿼리 복잡도 및 심층 방어:
- 최대 쿼리 깊이(최대 4단계)와 필드별 가중치 기반 복잡도 계산 규칙을 명시하십시오.
5. 구조화된 에러 처리 규격:
- Apollo/RFC 에러 익스텐션 표준(`extensions.code`, `extensions.timestamp`, 필드 단위 유효성 검증 오류)을 따르는 에러 형식을 정의하십시오.🚀 레시피 C: 실시간 구독 & 낙관적 UI 뮤테이션 특화 (WebSocket Subscriptions & Optimistic Mutations)
실시간 데이터 동기화(GraphQL Subscription), 웹소켓 연결 수명주기, 클라이언트 정규화 캐시 즉시 갱신을 위한 낙관적 뮤테이션(Optimistic Mutation) 응답 페이로드를 설계하는 특화 레시피입니다.
[영문 프롬프트 (복사용)]
You are a Staff Real-Time Distributed Systems & GraphQL Engineer.
Design an end-to-end real-time GraphQL architecture covering GraphQL Subscriptions, optimistic mutations, and client cache normalization for the interactive application below.
### Collaborative Feature & Scope:
- Target Application: [e.g., Real-time Multi-tenant Kanban Board & Document Collaboration]
- Real-time Events: [e.g., TaskMoved, TaskContentUpdated, UserTypingIndicator, CommentAdded]
- Client Stack: [e.g., Apollo Client / Relay with React 19]
### Technical Directives:
1. SUBSCRIPTION SCHEMA & TRANSPORT:
- Define GraphQL Subscription types using `graphql-ws` subprotocol conventions.
- Implement event filtering and authorization at subscription boundary (e.g., tenantId, boardId).
2. OPTIMISTIC MUTATION PAYLOAD:
- Structure mutation inputs and return payloads containing comprehensive entity state, optimistic client IDs, and revision/version vectors for conflict resolution.
3. CLIENT CACHE NORMALIZATION & IDEMPOTENCY:
- Provide Apollo Client `cache.modify` or Relay store updater instructions matching returned payload.
- Include rollback strategy upon network failure or server rejection.[한글 프롬프트 (1:1 매칭 복사용)]
당신은 스태프 실시간 분산 시스템 및 GraphQL 엔지니어(Staff Real-Time Distributed Systems & GraphQL Engineer)입니다.
아래 대화형 애플리케이션을 위한 GraphQL 구독(Subscription), 낙관적 뮤테이션(Optimistic Mutation), 클라이언트 캐시 정규화 엔드투엔드 아키텍처를 설계하십시오.
### 협업 기능 및 범위:
- 대상 애플리케이션: [예: 실시간 멀티테넌트 칸반 보드 및 문서 협업 도구]
- 실시간 이벤트: [예: 작업이동(TaskMoved), 내용수정(TaskContentUpdated), 입력중표시(UserTypingIndicator), 댓글추가(CommentAdded)]
- 클라이언트 기술 스택: [예: Apollo Client / Relay 기반 React 19]
### 기술 필수 지침:
1. 구독 스키마 및 전송 계층:
- `graphql-ws` 서브프로토콜 규칙을 준수하는 GraphQL Subscription 타입을 정의하십시오.
- 구독 경계에서 테넌트 및 보드 단위 권한 검증 및 이벤트 필터링 파라미터를 구현하십시오.
2. 낙관적 뮤테이션 페이로드 구조:
- 뮤테이션 입력과 반환 페이로드에 전체 엔티티 상태, 임시 클라이언트 ID, 충돌 해결을 위한 버전 벡터(`version` 또는 `updatedAt`)를 포함하십시오.
3. 클라이언트 캐시 정규화 및 멱등성:
- 반환 페이로드와 매칭되는 Apollo Client `cache.modify` 또는 Relay store updater 코드를 작성하십시오.
- 네트워크 실패 또는 서버 거절 시의 캐시 롤백(Rollback) 전략을 수립하십시오.graphql-ws 서브프로토콜 준수: 레거시 subscriptions-transport-ws의 연결 누수 문제를 해결하고 최신 웹소켓 표준을 적용합니다.3. 실행 결과 비교: 레시피 A vs B vs C 실전 대조
❌ 레시피 A 실행 결과: [단순 질의의 한계] N+1 유발하는 무한 중첩 쿼리 및 프래그먼트 부재
워크스페이스 활동 피드에 대해 레시피 A를 실행했을 때 도출되는 전형적인 안티패턴 결과입니다.
# 안티패턴: 깊이 제어 없음, 오프셋 페이징, 프래그먼트 미사용, N+1 유발
query GetWorkspaceData($workspaceId: String!, $limit: Int, $offset: Int) {
workspace(id: $workspaceId) {
name
projects(limit: $limit, offset: $offset) {
id
title
activities {
id
action
comment {
id
body
author {
id
name
posts {
id
title # 5단계 무한 중첩: DB Connection 고갈 및 N+1 쿼리 폭탄
}
}
}
}
}
}
}projects -> activities -> comment -> author -> posts로 이어지는 5단계 중첩으로 인해 서비스 거부 공격(DoS)에 취약합니다.limit/offset 방식을 사용하여 활동이 실시간 추가되는 피드에서 항목이 중복되거나 누락되는 페이징 버그가 발생합니다.__typename, 글로벌 고유 id)가 누락되어 있습니다.⚡ 레시피 B 실행 결과: [실전 사례 1] B2B 대시보드 복합 피드 쿼리 (Relay 커서 페이지네이션 Connection/Edge, DataLoader 배치, 프래그먼트 재사용, 후속 체이닝 2종, 4단계 워크플로우)
레시피 B를 통해 도출된 프로덕션급 대규모 B2B 워크스페이스 피드 쿼리 및 스키마 명세입니다.
1. 프래그먼트 기반 Relay 커서 쿼리 명세
# 1. UI 컴포넌트 프래그먼트 분리 (Colocation)
fragment UserAvatarFragment on User {
__typename
id
name
avatarUrl
role
}
fragment ActivityItemFragment on ActivityLog {
__typename
id
actionType
targetResource
createdAt
actor {
...UserAvatarFragment
}
}
# 2. 최상위 피드 쿼리 (Relay Connection 규격 준수, 최대 깊이 3단계 제한)
query GetWorkspaceActivityFeed($workspaceId: ID!, $first: Int = 20, $after: String) {
workspace(id: $workspaceId) {
__typename
id
name
activityFeed(first: $first, after: $after) {
totalCount
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
edges {
cursor
node {
...ActivityItemFragment
}
}
}
}
}2. DataLoader 기반 백엔드 리졸버 아키텍처 (Node.js/TypeScript)
import DataLoader from 'dataloader';
// N+1 문제를 방지하는 사용자 일괄 조회 DataLoader
export const createUserDataLoader = (userRepository: UserRepository) => {
return new DataLoader<string, User>(async (userIds: readonly string[]) => {
const users = await userRepository.findManyByIds([...userIds]);
const userMap = new Map(users.map((u) => [u.id, u]));
return userIds.map((id) => userMap.get(id) || new Error(`User not found: ${id}`));
});
};
export const resolvers = {
ActivityLog: {
actor: async (parent: ActivityLog, _args: unknown, { loaders }: GraphQLContext) => {
// 100개의 피드 아이템이 있어도 단 1번의 'WHERE id IN (...)' 배치 쿼리로 수렴
return loaders.userLoader.load(parent.actorId);
},
},
};후속 체이닝 2종
maxDepth({ n: 4 }))과 필드 복잡도 비용 분석(costLimit({ maxCost: 200 }))을 적용하는 Apollo Server 미들웨어 설정 코드를 작성해줘."ActivityItemFragment 및 GetWorkspaceActivityFeed 쿼리를 기반으로 relay-compiler가 빌드할 수 있는 React용 useFragment 및 usePaginationFragment 훅 코드를 생성해줘."4단계 워크플로우
Connection/Edge/PageInfo를 통한 무한 스크롤 및 불투명 커서 처리.🚀 레시피 C 실행 결과: [실전 사례 2] 실시간 협업 문서 편집/채팅 구독 & 낙관적 뮤테이션 (GraphQL Subscription, 멱등성 클라이언트 캐시 정규화, 후속 체이닝, 3단계 워크플로우)
실시간 멀티테넌트 문서 협업 시스템에서 문서 수정 이벤트 수신 및 낙관적 UI 갱신을 완벽하게 처리하는 스펙입니다.
1. 웹소켓 실시간 구독 스키마 (graphql-ws)
# 특정 문서에 대한 실시간 변경 구독
subscription OnDocumentUpdated($documentId: ID!, $clientRevision: Int!) {
documentUpdated(documentId: $documentId, sinceRevision: $clientRevision) {
__typename
documentId
patchOperations
revision
lastModifiedBy {
id
name
}
serverTimestamp
}
}2. 낙관적 UI 뮤테이션 쿼리 및 Apollo Client 캐시 갱신 코드
import { gql, useMutation } from '@apollo/client';
const UPDATE_TASK_MUTATION = gql`
mutation UpdateTaskContent($input: UpdateTaskInput!) {
updateTaskContent(input: $input) {
__typename
task { id content version updatedAt }
}
}
`;
export function useOptimisticTaskUpdate() {
const [updateTask] = useMutation(UPDATE_TASK_MUTATION);
const handleUpdate = (taskId: string, newContent: string, currentVersion: number) => {
updateTask({
variables: { input: { taskId, content: newContent, clientMutationId: crypto.randomUUID() } },
optimisticResponse: {
updateTaskContent: {
__typename: 'UpdateTaskPayload',
task: { __typename: 'Task', id: taskId, content: newContent, version: currentVersion + 1, updatedAt: new Date().toISOString() },
},
},
update: (cache, { data }) => {
if (!data?.updateTaskContent?.task) return;
cache.modify({
id: cache.identify(data.updateTaskContent.task),
fields: {
content() { return data.updateTaskContent.task.content; },
version() { return data.updateTaskContent.task.version; },
},
});
},
});
};
return { handleUpdate };
}후속 체이닝: 충돌 해결 및 웹소켓 재연결 전략
ConflictVersionError)을 감지하여 3-way 머지를 수행하고, graphql-ws 클라이언트에서 자동 재연결 및 지수 백오프를 수행하는 리커넥션 핸들러 코드를 작성해줘."3단계 워크플로우
4. GraphQL 쿼리 설계를 위한 4대 엔지니어링 원칙
offset 방식은 실시간 데이터 삽입 시 아이템 건너뜀 및 중복을 유발합니다. 커서 기반 연결(first, after, edges, node, pageInfo)을 기본 표준으로 채택해야 합니다.IN (...) 배치 질의로 치환해야 합니다.5. 실전 투입용 플레이스홀더 템플릿
[역할 정의]
당신은 엔터프라이즈 GraphQL 인프라를 총괄하는 Principal GraphQL Architect입니다.
[대상 비즈니스 도메인]
- 서비스 도메인: [예: 전자상거래 고객 주문 및 실시간 배송 트래킹 시스템]
- 핵심 엔티티: [예: Order, OrderItem, TrackingEvent, Courier, Customer]
- 트래픽 및 SLA: [예: 피크타임 초당 8,000 req/s, P99 지연시간 200ms 이하]
[GraphQL 설계 요구사항]
1. 쿼리 및 페이지네이션: Relay Cursor Connections 규격을 따르는 first/after 기반 페이징 쿼리를 작성할 것.
2. 프래그먼트 구성: UI 단위로 재사용 가능한 핵심 엔티티 프래그먼트를 분리하고 __typename과 id를 포함할 것.
3. DataLoader 설계: OrderItem -> Product, TrackingEvent -> Courier 연관 관계에 대한 DataLoader 배치 로직을 명시할 것.
4. 방어 정책: 최대 쿼리 깊이(Max Depth 4) 및 필드 복잡도 가중치 산정 기준을 제시할 것.
5. 에러 처리: extensions.code와 extensions.timestamp를 포함하는 RFC 호환 에러 명세를 작성할 것.6. 프롬프트 활용 팁 & 주의사항
Global Object Identification) 부여:Node 인터페이스를 구현하여 base64(Type:ID) 형태의 전역 고유 ID를 부여하십시오. 이를 통해 Apollo와 Relay 클라이언트가 전역 캐시 맵에서 중복 없이 엔티티를 정규화할 수 있습니다.mutation UpdateOrder(id: ID!, status: String!)처럼 인자를 개별 나열하지 말고, 반드시 mutation UpdateOrder(input: UpdateOrderInput!) 형태의 단일 입력 객체(Input Type)를 사용하십시오. 반환값 또한 페이로드 타입(UpdateOrderPayload)으로 감싸 향후 필드 확장에 유연하게 대처하십시오.errors 구분:errors 배열 대신 Union 타입을 활용한 결과 타입(예: union OrderResult = OrderSuccess | InsufficientInventoryError)으로 모델링하여 프론트엔드가 컴파일 타임에 분기 처리를 강제하도록 유도하십시오.