GraphQL
도구
부르는 쪽이 필요한 항목만 골라 적어 보내면 서버가 딱 그만큼만 돌려주는 방식의 데이터 창구 설계입니다.
등장 배경
서버가 데이터를 내주는 창구는 오랫동안 주소 하나에 응답 하나로 짜여 있었습니다. 문서 목록을 주는 주소가 있고 사용자 정보를 주는 주소가 따로 있는 식입니다. 서버를 만들 때 무엇을 담아 보낼지 정해 두면 부르는 쪽은 그 묶음을 통째로 받습니다.
화면이 단순할 때는 문제가 없습니다. 어긋나기 시작하는 건 한 화면이 여러 곳의 데이터를 섞어 보여 주면서부터입니다. 문서 목록 하나를 그리는데 목록을 부르고, 작성자 이름을 부르고, 댓글 수를 부르느라 서버를 네댓 번 다녀와야 합니다. 회선이 느린 휴대폰에서는 이 왕복이 그대로 대기 시간으로 쌓입니다. 반대 방향의 낭비도 같이 일어납니다. 목록에 이름 하나만 필요한데 사용자 정보 창구는 가입일과 설정값까지 스무 개 넘는 항목을 함께 보냅니다.
페이지덱에서는 이 문제가 일정 문제로 나타났습니다. 민서가 문서 목록 화면에 작성자 프로필 사진과 최근 댓글 수를 더하자고 했을 때, 태오는 화면 코드만 고쳐서는 안 된다고 답했습니다. 기존 창구가 그 두 항목을 주지 않으니 서버를 고치고 배포해야 하고, 그러면 화면 작업이 그 배포를 기다려야 했습니다. 화면을 조금 바꿀 때마다 서버 일정이 끼어드는 구조였습니다.
이 방식은 순서를 뒤집어 그 구조를 없앴습니다. 서버가 무엇을 줄지 정해 두는 대신, 무엇을 줄 수 있는지 목록만 공개하고 실제로 무엇을 받을지는 부르는 쪽이 매번 적어 보내게 했습니다.
해결하는 문제
화면이 필요한 데이터와 서버가 주는 데이터가 어긋나는 문제를 다룹니다. 어긋남은 두 방향으로 나타나고, 둘 다 같은 장치로 풀립니다.
- 너무 많이 받는 경우입니다. 이름만 필요한 자리에서 항목 스무 개가 딸려 옵니다. 이 방식에서는 요청서에 이름 항목만 적어 보내고 그것만 받습니다.
- 너무 적게 받아 여러 번 다녀오는 경우입니다. 목록과 작성자와 댓글 수를 각각 부르는 대신, 세 가지를 한 요청서에 중첩해 적어 한 번에 받습니다.
가능한 이유는 서버가 스키마를 미리 공개하기 때문입니다. 스키마는 이 창구에서 꺼낼 수 있는 항목 전부와 각 항목의 자료형을 적어 둔 목록입니다. 문서에는 제목과 작성자가 있고 작성자에게는 이름과 사진이 있다는 식으로 관계까지 적혀 있어서, 부르는 쪽은 그 목록을 보고 필요한 가지만 골라 요청서를 씁니다.
주소가 하나뿐인 것도 특징입니다. 기능마다 새 주소를 여는 대신 창구 하나를 열어 두고 요청서 내용으로 구분합니다. 그래서 새 화면이 필요로 하는 조합이 생겨도 스키마에 이미 있는 항목이라면 서버를 고치지 않습니다. 앞의 일정 문제가 여기서 사라집니다.
받는 쪽 코드도 단순해집니다. 요청서에 적은 모양 그대로 응답이 돌아오기 때문에 무엇이 올지 미리 알 수 있고, 항목 이름과 자료형이 스키마에 못 박혀 있어 오타나 자료형 착각은 서버에 닿기 전에 걸립니다. 스키마가 OpenAPI 같은 별도 문서 없이 그 자체로 설명서 노릇을 한다는 뜻이기도 합니다.
대안
대부분의 팀은 REST에서 시작합니다. 주소마다 응답이 정해져 있어 이해하기 쉽고, 같은 주소는 같은 결과를 주니 캐싱이 쉽습니다. 한 번 만든 응답을 중간 서버에 저장해 두고 재사용하는 일이 요청서마다 내용이 달라지는 쪽에서는 훨씬 까다로워집니다.
회사 안 서비스끼리 주고받는 자리에는 gRPC가 자주 쓰입니다. 사람이 읽는 형식 대신 기계가 읽는 형식을 써서 속도를 얻는 규격이라, 바깥에 공개하는 창구보다 내부 통신에 맞습니다.
방향이 다른 문제에는 다른 도구가 필요합니다. 결제 승인처럼 사건이 생긴 순간을 알아야 하면 웹훅이 맞고, 같은 문서를 둘이 동시에 고치는 자리에는 연결을 열어 두는 웹소켓이 맞습니다.
고를 때 보는 것은 셋입니다. 같은 서버를 부르는 화면의 종류가 여러 가지인지, 화면 요구가 자주 바뀌는지, 창구를 여는 쪽에 그만한 준비를 할 여력이 있는지입니다. 앞의 둘이 크고 뒤가 받쳐 주면 이쪽이 이득입니다. 셋 다 작으면 주소마다 응답이 고정된 쪽이 낫습니다. 요청서를 아무나 쓸 수 있다는 말은 무거운 요청도 쓸 수 있다는 뜻이라, 깊이와 복잡도를 제한하고 요청 제한을 거는 일이 따라붙습니다.
실무 용례
"이건 스키마에 이미 있으니까 서버 배포 없이 화면에서 바로 가져오면 됩니다."
필요한 항목이 이미 공개돼 있어 백엔드 작업을 기다릴 필요가 없다는 뜻입니다.
"쿼리가 너무 깊게 들어가요. 한 번에 이만큼 부르면 서버가 버티기 어렵습니다."
요청서 하나가 데이터를 지나치게 많이 끌어오고 있으니 나눠 부르자는 제안입니다.
"외부에 공개할 창구는 REST로 갑시다. 여긴 캐싱이 더 중요해요."
연동하는 쪽이 다양하고 같은 응답이 반복되는 자리에서는 옛 방식이 유리하다는 판단입니다.
페이지덱에서는 웹과 모바일 앱이 같은 서버를 부릅니다. 두 화면이 필요로 하는 항목이 달라서 예전에는 창구를 따로 두거나 한쪽에 맞춘 응답을 다른 쪽이 억지로 쓰고 있었습니다. 스키마를 열어 둔 뒤로는 태오가 항목을 추가하고 민서와 앱 쪽이 각자 필요한 조합을 적어 갑니다. 대신 태오의 일이 늘었습니다. 새 항목을 더할 때마다 그 항목을 꺼내는 비용이 얼마인지, 목록 안에서 반복 호출되지는 않는지 확인해야 합니다.
흔한 오해
이름 때문에 데이터베이스 기술로 아는 경우가 많습니다. 질의를 적어 보낸다는 점이 데이터베이스를 다루는 언어와 닮아 보이기 때문입니다. 실제로는 프로그램끼리 데이터를 주고받는 창구 쪽의 약속일 뿐이고, 뒤에 어떤 저장소가 있는지와는 무관합니다. 이걸 혼동하면 도입 논의가 엉뚱한 곳으로 갑니다. 저장소를 바꾸는 일로 오해해 몸을 사리거나, 반대로 저장소 성능 문제가 이걸로 풀릴 것처럼 기대하게 됩니다.
항상 더 빠르다고 아는 것도 흔합니다. 왕복이 줄고 받는 양이 줄어드니 자연스러운 기대입니다. 그런데 한 요청서가 여러 항목을 중첩해 부르면 서버 안에서는 저장소 조회가 오히려 늘어날 수 있습니다. 목록 20건마다 작성자를 조회하면 21번을 다녀오는 식입니다. 대비 없이 얹으면 화면은 한 번만 불렀는데 서버는 예전보다 느려지고, 원인이 화면 코드에 안 보여서 찾는 데 오래 걸립니다. 묶어서 한 번에 조회하는 장치를 서버에 함께 깔아야 기대한 만큼 이득이 납니다.
자주 헷갈리는 용어
| 용어 | 응답을 누가 정하는가 | GraphQL과의 차이 |
|---|---|---|
| REST | 창구를 여는 서버 | 주소마다 돌려줄 내용이 고정돼 있습니다. 이해와 캐싱이 쉬운 대신 화면이 바뀌면 서버도 같이 바뀌어야 합니다 |
같이 보면 좋은 페이지
마지막 업데이트 2026-09-16