GraphQL 쿼리 포매터
GraphQL 쿼리, 뮤테이션, 서브스크립션, 프래그먼트를 정리 — 오퍼레이션 전용, 스키마 SDL은 대상 아님
입력
출력
GraphQL 쿼리 포매터란?
손으로 적은 GraphQL 요청은 늘 한 줄짜리 중괄호 벽으로 시작합니다. 이걸 정리도 안 한 채 코드 리뷰에 붙여 넣으면 첫 코멘트가 "포맷팅 좀" 이 되는 건 거의 확정입니다. 프론트엔드 빌드에서 떨어진 쿼리, 서버가 로그에 찍은 쿼리, 동료가 "왜 이게 null로 오지?" 하고 던진 슬랙 스레드의 쿼리도 사정은 같습니다. 이 페이지는 쿼리, 뮤테이션, 서브스크립션, 프래그먼트를 받아서 보기 좋게 만듭니다 — 두 칸 들여쓰기, 한 줄에 한 필드, 들어갈 만하면 인자는 인라인, 변수는 깔끔하게, 그리고 GraphQL 스펙의 오퍼레이션 문법을 끝까지 지킵니다.
이 페이지는 GraphQL Formatter의 오퍼레이션 짝꿍입니다. 그쪽 도구는 스키마 정의 언어를 정리합니다 — type Order, interface Node, enum Status 같은 것들이죠. 이 도구는 클라이언트가 보내고 서버가 받는 것을 정리합니다 — query OrderDetails($id: ID!) { order(id: $id) { ... } }, 뮤테이션, 서브스크립션, 프래그먼트 정의. 두 문법은 토큰은 공유하지만 구조 규칙이 다릅니다 — selection set, alias, fragment spread, inline fragment, 디렉티브 적용은 오퍼레이션 전용입니다. 실수로 SDL을 붙였다면 스키마 포매터로 가세요.
포매팅은 TypeScript로 직접 짰습니다 — 페이지에 graphql-js 번들이 실리지 않으니 첫 페인트가 가볍게 유지됩니다. 출력은 일반적인 케이스에서 Prettier의 GraphQL 플러그인이 만들어내는 결과와 같으므로, 이미 Prettier를 쓰는 코드베이스에 정리된 쿼리를 떨어뜨려도 diff가 생기지 않습니다. 모든 작업은 로컬에서 일어납니다 — 쿼리는 브라우저 밖으로 나가지 않습니다.
GraphQL 쿼리 포매터 사용법
세 단계입니다. Convert 버튼은 없습니다 — 입력을 멈춘 직후 자동으로 포매팅이 실행됩니다.
붙여넣기, 업로드, 또는 샘플 불러오기
왼쪽 입력 패널에 GraphQL 오퍼레이션을 붙여넣으세요. .graphql이나 .gql 파일을 가져오려면 업로드를 누르고, 현실적인 이커머스 OrderDetails 쿼리와 작은 프래그먼트를 보고 싶으면 샘플을 누르세요. 흔한 지저분한 붙여넣기는 이런 모양입니다:
query OrderDetails($id:ID!,$includeItems:Boolean=true){order(id:$id){id placedAt status customer{id name email}items @include(if:$includeItems){sku quantity unitPrice{amountCents currency}}total{amountCents currency}}}포매터는 실제 클라이언트 코드에 등장하는 모든 오퍼레이션 문법을 다룹니다 — 기본값을 가진 변수 정의, 리스트 타입 기본값, @include / @skip / 커스텀 디렉티브, alias, fragment spread (...Money), inline fragment (... on PaidOrder { ... }). 한 도큐먼트에 여러 오퍼레이션이나 프래그먼트가 있으면 사이에 빈 줄을 두고 분리합니다 — Apollo Client를 비롯한 대부분의 GraphQL 도구가 기대하는 형태입니다.
정리된 출력 보기
오른쪽 출력 패널에 정리된 오퍼레이션이 표시됩니다. 모든 필드는 자기 줄을 가집니다. 인자는 필드가 80자 안에 들어가면 인라인으로 남고, 안 들어가면 여러 줄로 나뉩니다 — Prettier의 GraphQL 플러그인이 쓰는 것과 같은 규칙입니다. 변수 정의도 오퍼레이션 헤더에서 같은 규칙을 따릅니다. alias는 콜론 뒤에 한 칸 공백을 유지합니다 (aliasedAs: fieldName). 주석 (# ...)은 원래 붙어 있던 줄의 들여쓰기로 보존됩니다. 입력이 망가진 경우 — 짝 안 맞는 중괄호, 떠 있는 $, 빠진 : — 포매터는 예외를 던지지 않고 친절한 오류 메시지를 인라인으로 적어 줍니다.
복사 또는 다운로드
복사를 누르면 정리된 쿼리를 PR, 문서, 채팅 메시지로 가져갈 수 있습니다. 다운로드를 누르면 query.graphql로 저장됩니다. Clear는 입력을 초기화합니다. 전체 파이프라인이 클라이언트 사이드라서 — 사내 API에 대해 쿼리를 디버깅 중인데 외부 도구에는 붙이고 싶지 않을 때 유용합니다.
실제로 쓰게 되는 순간
코드 리뷰와 PR 위생
프론트엔드 PR이 새 뮤테이션을 추가했는데, 쿼리 문자열은 빌드 단계에서 공백이 다 날아간 상태라 diff가 400자짜리 벽이 되어 있습니다. 뮤테이션을 포매터에 통과시키고 정리된 버전을 PR 설명에 붙여 넣으면, 리뷰어가 어떤 필드를 읽고 있는지 진짜로 볼 수 있게 됩니다. 같은 트릭이 graphql-react, urql, Relay, 그리고 쿼리를 템플릿 리터럴로 인라인하는 모든 클라이언트에서 통합니다.
프로덕션 쿼리 디버깅
프로덕션의 어떤 쿼리가 기대했던 필드에 null을 돌려줍니다. 네트워크 탭에서 요청 본문을 가져와 여기에 붙이면 변수 값, 어떤 필드가 @include를 쓰는지, fragment spread가 어디에 붙는지가 한 번에 보입니다. 긴 한 줄을 째려보는 것보다 낫죠. curl이나 Postman으로 요청을 수동 재현해야 한다면 HTTP로 GraphQL을 제공하는 공식 가이드와 함께 사용하세요.
학습과 온보딩
GraphQL 오퍼레이션이 처음이라면? 튜토리얼에서 본 쿼리를 붙여넣고 정리해 보세요. 구조가 한눈에 들어옵니다 — 오퍼레이션 헤더, selection set, 중첩된 selection set, 맨 아래 프래그먼트 정의. 출력은 graphql.org의 쿼리 가이드에서 보게 될 레이아웃을 그대로 따라가므로, 학습 중에 다시 문서로 돌아가 매핑하기도 쉽습니다.
pre-commit과 CI 게이트
포매터는 결정적이라서 — 이미 정리된 쿼리는 그대로 왕복합니다 — 커밋 전에 "내 쿼리 이미 예뻐?" 라는 빠른 체크용으로 이 페이지를 쓸 수 있습니다. 본격 자동 파이프라인이라면 같은 소스를 Prettier의 GraphQL 플러그인에 통과시키고 diff가 0이 아니면 빌드를 실패시키세요. 똑같은 아이디어, 다만 규모만 다를 뿐입니다.
자주 묻는 질문
GraphQL Formatter 페이지와 어떻게 다른가요?
GraphQL Formatter 페이지는 스키마 정의 언어를 정리합니다 — type, interface, enum, union, scalar, directive 선언 같은 것들이죠. 이 페이지는 오퍼레이션을 정리합니다 — query, mutation, subscription, fragment. 두 문법은 토큰을 공유하지만 구조 규칙이 매우 다르므로, 오퍼레이션을 스키마 페이지에서 정리하려고 하면(혹은 그 반대) 결과가 엉망이 됩니다. 붙여 넣은 내용에 맞는 도구를 고르세요.
스키마와 비교해서 쿼리를 검증해 주나요?
아니요. 포매터는 pretty-print에 필요한 만큼만 중괄호, 괄호, 대괄호 짝을 확인하고 스키마는 모릅니다. 그래서 order가 id: Int!가 아니라 id: ID!를 받는다고 알려주지는 못합니다. 진짜 검증이 필요하면 서버의 시작 검사나 위 GitHub 링크의 graphql-js 레퍼런스 검증기를 통하세요.
제 쿼리가 서버로 전송되나요?
아니요. 포매팅은 순수한 클라이언트 사이드 자바스크립트입니다 — 아무것도 업로드되지 않고, 아무것도 로깅되지 않습니다. 사내 쿼리, 민감한 변수 값을 포함한 쿼리, 비공개 API에 대한 쿼리에 모두 안전합니다.
제 변수 값이나 인자를 건드리나요?
아니요. 인자 값, 기본값, 리스트 타입 기본값은 :, =, , 주변의 공백만 일관되게 다듬고, 그 외엔 적힌 그대로 출력됩니다. 포매터는 절대로 필드, 인자, 변수를 새로 만들지도, 빼지도, 순서를 바꾸지도 않습니다 — 붙여넣은 그대로 깔끔하게 펼쳐져서 나옵니다.
inline fragment와 fragment spread도 처리하나요?
네. inline fragment (... on PaidOrder { ... })는 두 칸 들여쓰기로 일반 selection set처럼 처리됩니다. fragment spread (...Money)는 필드 들여쓰기에 한 줄로 놓이고, 디렉티브가 있으면 같은 줄에 유지됩니다. 한 도큐먼트에 여러 프래그먼트 정의가 있으면 각각을 별도의 최상위 정의로 두고 사이에 빈 줄을 둡니다.
익명 쿼리 — <code>{ field }</code> — 는 <code>query { field }</code>로 펼쳐 주나요?
아니요. 단축형은 스펙의 일부이고 포매터는 그대로 보존합니다. 이름 있는 쿼리를 원한다면 직접 이름을 붙이세요 — 포매터가 조용히 오퍼레이션을 다시 쓰는 일은 없습니다.
다른 GraphQL 도구
쿼리 포매터는 GraphQL 작업의 한 조각일 뿐입니다. 사이트의 다른 GraphQL 도구들: