새소식

반응형
CS 지식

[CS 지식] GraphQL이 뜨는 이유(feat. RESTful API 와 다른 점은?)

2024.11.07
  • -
반응형

https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTRAt3c3IyQQ4ciJLsNIGKKouvF00KoDbXTAg&s

 

 

이 글은 최근 다양한 기업들의 기술 스택을 보면서 GraphQL이 많이 보이는 현상에 대한 궁금증으로부터 비롯되어 왜 요즘 많이 사용되고 있는 기술이며 어떻게 발전되었는지 그 과정들을 함께 살펴보려고 합니다.

 

1. "API를 위한 쿼리 언어"

"API를 위한 쿼리 언어" GraphQL 공식문서에 들어가보면 첫 페이지에 대문짝만하게 박혀있어서 가장 먼저 볼 수 있는 문장입니다.

GraphQL은 API를 위한 쿼리 언어이며 이미 존재하는 데이터로 쿼리를 수행하기 위한 런타임입니다. GraphQL은 API에 있는 데이터에 대한 완벽하고 이해하기 쉬운 설명을 제공하고 클라이언트에게 필요한 것을 정확하게 요청할 수 있는 기능을 제공하며 시간이 지남에 따라 API를 쉽게 진화시키고 강력한 개발자 도구를 지원합니다.
- GraphQL 공식문서 중

 

 

2. 진짜 요즘 많이 쓰나?

 

GraphQL을 잘 모르고 들어오신 분들은 제목을 보고 정말 요즘 많이 사용되는지에 대해 궁금해 하실 수 있습니다. 여기에서 GraphQL을 사용하는 기업들 리스트를 확인하실 수 있는데 메인에 내 건 회사들 로고만 봐도 내로라 하는 기업들도 이 기술을 사용하고 있음을 알 수 있고 국내에서도 많은 빅테크 기업 기술 스택 중 하나로 자리잡고 있는 것을 보실 수도 있습니다.

 

언어가 발전함에 따라 수많은 기업들에서 클라이언트와 서버 간 통신의 수단으로 GraphQL을 채택하는 사례가 늘고 있는 것인데요. 위와 같이 대표적으로 페이스북(현 Meta), 깃허브, 그리고 핀터레스트 등과 같은 외국 기업과 더불어 국내에서는 당근, 카카오, 네이버 웹툰 등의 기업들에서 사용 중이라고 합니다.

 

3. 2015년 페이스북에 발표한 GraphQL

https://medium.com/apollo-stack/graphql-at-facebook-by-dan-schafer-38d65ef075af

GraphQL과 관련된 유명한 정보 중 하나는 페이스북이 만들었다는 사실입니다. (현재는 메타로 불리지만 지금은 편한 설명을 위해 페이스북으로 표현하도록 하겠습니다.)

 

공식 문서에서 이 기술을 사용하는 기업 중에 페이스북이 가장 첫번째로 있었던 이유가 있던 것입니다.

 

페이스북이 이 기술을 만들었던 이유는 당연히 자신들이 필요했기 때문이었겠죠? 

 

페이스북은 2004년, 그들의 서비스 첫 출시 이후 어마어마한 파장을 일으키며 단 몇 년 만에 수백만명의 사용자를 모으는 데에 성공합니다. 그러던 중 2007년 모바일의 혁신을 불러온 애플의 아이폰이 출시되고, 이어서 구글의 안드로이드 발표도 나오게 됩니다. 이러한 모바일 혁신으로 인해 사람들은 컴퓨터 사용보다 스마트폰 사용이 점점 많아지기 시작하였고 웹 서비스 기반에 힘을 주던 그들에게 도전적인 문제가 생기게 된 것이었습니다.

 

 

Mark Zuckerberg: Our Biggest Mistake Was Betting Too Much On HTML5 | TechCrunch

Today, Mark Zuckerberg revealed that Facebook's mobile strategy relied too much on HTML5, rather than native applications. Not only was this a big mistake with mobile, but Zuckerberg says that its biggest mistake period was the focus on HTML5. This is the

techcrunch.com

2012년 TechCrunch에서 진행한 마크 주커버그의 인터뷰에서는 "우리가 HTML5에 너무 많이 기회비용을 투자한 건 가장 큰 실수이다."라는 말을 하여 화제가 되기도 했었습니다. 그 이유 중 하나로 모바일의 혁신적인 발전을 꼽았는데, 단순히 사용자가 모바일에 많다는 건 그 자체 만으로도 모바일에 집중을 해야한다는 이유가 될 수도 있지만 기업에게 매우 중요한 것은 '돈'인만큼, 사용자가 많다는 현상이 미래 광고 수익 측면에서도 데스크탑을 훨씬 넘어설 것임을 시사하는 것이기 때문에 더 이상 무시할 수 없는 부분이 되기 때문입니다.

 

그래서 페이스북이 React와 React Native 개발에 힘을 썼던 이유도 비슷하지 않을까 싶습니다.

 

이 당시에 모바일 시장으로 진입하기 위해서는 먼저 기존에 존재하던 REST API의 문제들을 해결할 필요가 있었는데요. 아래와 같은 것들이 대표적으로 페이스북이 마주했던 문제들이라고 할 수 있습니다.

  1. 한 번의 API 호출에 불필요한 데이터들이 달려오는 Over-fetching의 문제
  2. 한 화면에 필요한 데이터를 위해 각각의 데이터를 포함하는 독립된 다수의 API를 호출해야 하는 Under-fetching의 문제
  3. 백엔드 쪽에서 API를 수정할 때마다 프론트엔드에서도 같이 수정해 주어야 하는 문제
  4. API가 변할 때마다 API 명세서를 수정해야 하는 문제

 

이러한 문제들을 해결하기 위해선 서로 다른 데이터의 관점으로 결합된 클라이언트와 서버간의 의존성을 느슨하게 만들어 주어야 합니다.

 

그래서 페이스북은 실질적으로 데이터를 사용하는 곳에서 데이터 확장에 더 힘을 쓸 수 있도록 하는 방식을 고안하였고 이에 2012년, GraphQL을 적용한 새로운 iOS 앱을 출시하게 됩니다.

 

4. REST API와 뭐가 다른 건데?

위에서 언급한 4가지의 문제를 안고 있던 REST API와 어떠한 점이 다를길래 그러한 문제를 해결할 수 있었던 것일까요?

 

REST API가 처음 만들어진 때인 2000년으로 돌아가 보면, 로이 필딩(Roy Fielding)이 게재한 논문에서 그 이름이 처음 등장하게 됩니다. REST API가 내세웠던 점은 일관된 결과를 제공한다는 것이었는데요. 이 말인 즉슨, 클라이언트 쪽에서 서버의 특정 엔드포인트에 요청을 날리면 항상 똑같은 구조로만 그 응답을 받는다는 것을 의미합니다.

 

어떻게 보면 클라이언트-서버 관계에서는 그러한 방식이 너무나 당연하고 만약 그렇지 않다면 같은 요청에 대해 다른 응답이 온다는 것이기 때문에 여러 원칙에 위배되었다고도 볼 수 있는 것이죠.

 

REST API와 GraphQL을 비교하면서 든 비유 중에 가장 인상 깊었던 비유는 'GraphQL은 마치 뷔페와도 같다.'라는 것이었습니다. 그렇다면 REST API는 일반 식당에서 제공하는 메뉴와도 같은 것이죠.

 

식당에서 메뉴를 주문하면 (물론 장사가 잘되는) 누가 언제 시키든지 간에 항상 동일한 수준의 음식을 내고 싶은 것은 아마 대부분의 요리를 하는 사람들의 목표이지 않을까 싶습니다.

 

특히, 예를 들어 냉면과 같이 특정 메뉴를 요청했을 때 해당 메뉴를 곧바로 가져다 줄 수 있는 음식도 있는 반면, 해당 메뉴를 요청하기 위해 부수적인 요청사항과 함께 보내야 하는 경우도 존재합니다. 가령 '서브웨이'에서 '이탈리안 비엠티'를 시키는 경우 필수적으로 골라야 하는 것들(빵, 치즈, ...)과 선택적으로 골라야 하는 경우와 같이 말이죠.

서브웨이는 누가 뭐래도 이탈리안 비엠티입니다...

 

마찬가지로 REST API에서도 특정 리소스를 요청하기 위해 필수적으로(혹은 선택적으로) 제공해야 하는 쿼리 매개 변수(query parameter)를 포함해야 하며, 서브웨이 메뉴 중 '이탈리안 비엠티'를 특정지어 주문을 하듯이 그러한 정보를 넣는 경우 사용하는 경로 변수(path variable)가 존재합니다.

 

만약 서브웨이에 컴퓨터가 이탈리안 비엠티를 주문한다면 아래와 같은 메세지를 보낼 수 있겠네요.

POST /order/sandwich/italian_bmt?bread=whole_wheat&cheese=american HTTP/1.1
Host: subway.com
Content-Type: application/json

{
  "additionalIngredients": ["egg_mayo"]
}

 

 

반면 GraphQL은 앞서 말했듯 뷔페식입니다.

 

뷔페가 무엇이죠? 위키백과에 따르면 뷔페는 "여러 가지 음식을 늘어놓고 먹는 사람이 먹을만큼 덜어 먹게끔 되어 있는 자유로운 식사 방식"이라고 합니다. 물론 다른 뷔페도 있겠지만 대부분의 뷔페에서는 식당쪽에서 손님에게 음식을 '서빙'하는 과정이 없습니다. 요리사들이 음식을 만들면 바로 앞에 음식을 배치해두거나 종업원이 특정 위치로 옮겨 놓으면 손님들이 자신들의 접시를 들고 원하는 음식을 담는 구조인 것이죠.

 

마찬가지로 GraphQL에서는 클라이언트가 자신이 필요한 데이터만 골라 집어 요청할 수가 있습니다. 즉, 원하는 종류의 음식을 원하는 양만 가져갈 수 있는 뷔페처럼, 클라이언트가 서버로부터 필요한 데이터만 골라 가져갈 수 있는 것이죠.

 

GraphQL의 구체적인 예시는 이후에 보여드리겠지만 GraphQL에서는 다음과 같은 쿼리를 한 번에 보내는 것이 가능합니다.

  • "상품의 기본 정보와 판매자 정보, 그리고 해당 상품에 달린 리뷰들, 그 리뷰에 남겨진 담글들"

위와 같은 질의에 대해 일반적인 REST API였다면 얼마나 많은 양의 쿼리를 반복해야 할까요?

 

또 식당은 메뉴를 추가하거나 없애거나 금액을 바꾸는 경우에 메뉴판을 다시 만들거나 그 위에 덧대서 다시 작성해 주어야 합니다.

어떻게 식당 음식 가격이 시가?

 

https://cm.asiae.co.kr/article/2022062215463201346

 

 

5. 자 이제 본론 - GraphQL 코드 예시

자 그럼 이제 GraphQL이 어떻게 생겨먹었길래 앞서 말했던 페이스북이 마주했던 4가지의 문제들을 해결할 수 있었는지 살펴보겠습니다.

 

REST API와 GraphQL의 각각의 예시를 통해 "상품(Product)"정보를 가져오는 경우를 생각해 봅시다.

 

REST API

{
    "id": "1",
    "name": "후드티",
    "description": "따뜻한 후드티, 겨울철 필수 아이템",
    "price": 35000,
    "category": "의류",
    "stock": 120
}

 

REST API의 경우 위와 같은 데이터를 항상 제공해주는 URI 엔드포인트를 따로 마련해두어야 합니다.

 

GET /product/{productId}
ex) GET /product/1

 

이와 같은 방식은 OPEN API Specification(OAS)를 따르도록 한 방식이며 해당 엔드포인트가 그 자체로 응답의 내용을 명세해주게 됩니다.

  • 이러한 명세는 보통 Swagger나 REST Docs 등의 시각화 툴을 사용하여 팀원들 간의 명세를 수시로 확인할 수 있도록 합니다.

왼쪽: Spring REST Docs / 오른쪽: Swagger

 

 

이 부분이 REST API가 GraphQL과 가장 다른 부분입니다. REST는 OAS로 명세하는 것이 일반적이지만 실제 구현체가 문서와 다르다고 해서 직접적인 오류가 발생하지 않습니다. 실제로 문서가 오래되어 업데이트가 이루어지지 않았거나, 개발자의 실수로 구현과 명세가 일치하지 않는 경우가 다반사이기도 하죠. 실제 로이 필딩의 REST를 설명하는 논문에서도 문서화에 대한 내용은 존재하지 않고 다른 REST API 스펙에서 역시 권장 사항 정도로 표현하고 있습니다.

 

GraphQL - Over Fetching을 해결할 수 있는 이유

그렇지만 GraphQL은 일명 "스키마 정의 언어(Schema Definition Language)"로 취급되기 때문에 API의 상세 구조를 정확하게 정의를 해두어야 동작이 되기 때문에 명세하는 과정이 반드시 동반되어야 합니다.

 

즉, API 설계 단계에서부터 데이터 조회 방법과 조작 방법을 명확하게 규정하며 클라이언트와 서버 사이의 통신에서 일종의 엄격한 규약을 형성하여 일관성과 안정성을 보장하게 되는 것입니다.

 

그렇다면 OAS에서 제공하는 방식으로 GraphQL 스키마를 정의한 모습을 보도록 하겠습니다.

type Product {
    id: ID!
    name: String!
    description: String
    price: Int!
    category: String!
    stock: Int!
}

 

그 다음 해야 할 일은 마치 REST의 엔드포인트를 정의하는 역할을 하는 "쿼리 타입"을 정의하는 일입니다.

type Query {
    product(id: ID!): Product
}

 

이러한 방식의 요청은 쿼리를 통해 딱 필요한 필드만을 불러올 수가 있기 때문에 앞선 문제 중 하나인 Over-fetching 문제가 해결되게 됩니다.

 

 

GraphQL - Under Fetching을 해결할 수 있는 이유

Under Fetching의 경우는 조금 문제가 다릅니다. 

 

일반적인 쇼핑몰에서 상품에 대한 페이지에서 상품 정보 뿐만 아니라 리뷰, 리뷰에 대한 댓글 등도 존재합니다. GraphQL을 사용해서 이러한 정보들을 어떻게 전부 불러올 수 있을까요?

 

우선 만약 REST API였다면 다음과 같이 복잡한 프로세스를 거쳐야 할 것입니다.

 

  1. GET /product/1 요청
  2. 응답에서 review에 대한 id 획득
  3. GET /product/1/review/1
  4. 2에서 얻은 리뷰의 길이만큼 3을 반복

여기서 만약 해당 상품이 N개의 리뷰를 가지고 있다면 각 리뷰의 댓글을 얻기 위해 N+1번의 요청이 필요해지게 됩니다.(1을 위해 +N)

 

하지만 GraphQL은 아래와 같은 방식을 사용합니다.

query GetProductWithReviewsAndComments($productId: ID!) {
    product(id: $productId) {
        id
        name
        description
        price
        category
        stock
        reviews {
            id
            user
            rating
            comment
            replies {
                id
                user
                text
            }
        }
    }
}

 

이 때 reviews는 다른 것과 마찬가지로 필수 요청 사항이 아니기 때문에 필요하지 않은 경우 가져오지 않는 것도 가능하기 때문에 Under Fetching 문제를 해결할 수 있는 것입니다.

 

REST API를 사용해서도 위 상황과 동일한 데이터를 제공하는 엔드포인트를 만드는 것이 불가능한 것은 아니지만 리소스를 기준으로 엔드포인트를 나누는 REST API의 철학과 어긋나기 때문에 다소 RESTful 하지 않다고 할 수 있죠.

넌 전혀 REST 하고 있지 않아

 

6. 언제 사용해야 할까?

이렇듯 GraphQL에 대해서 알아보았지만 과연 GraphQL이 모든 경우에 Best Practice라고 할 수 있을까요?

 

GraphQL은 REST의 단점을 보완하기 위해서 나온 기술이지만 오히려 GraphQL의 단점을 REST가 보완하는 경우도 존재합니다.

 

한 화면에 많은 데이터를 필요로 할 때

GraphQL은 독립적인 UI 컴포넌트에서 사용되는 데이터를 효율적으로 받아올 수 있는 기술임에는 확실합니다. SNS 서비스의 메인 페이지를 생각해보면, 해당 페이지에서 필요한 데이터는 사용자 프로필, 최근 게시물, 친구 목록, 알림 등 굉장히 다양하고 방대한 데이터가 필요하게 될 것입니다.

제가 그 동안 REST API로 개발을 했을 때는 각각의 정보를 위한 각 엔드포인트에 요청을 날려 데이터를 받아오기 때문에 다수의 요청이 이루어지지만 GraphQL로는 단일 쿼리만으로 필요한 모든 데이터를 한 번에 가져올 수 있기 때문에 만약 한 화면에 많은 데이터를 필요로 하는 경우에 사용하면 좋습니다.

 

코드 수정 시 기존 코드와 호환성을 유지해야 할 때

GraphQL을 사용하면 API를 점진적으로(gradually) 유지보수하는 것이 굉장히 쉽습니다. 새로운 필드를 추가하는 경우나 이미 있던 필드를 deprecated(미사용) 처리해야 하는 경우에, 기존 클라이언트에 영향을 주지 않고 API가 제공하는 데이터를 바꾸는 것이 가능하기 때문입니다. API의 버전을 관리할 때의 복잡성도 줄일 수 있으며, 클라이언트와 서버 간 주고 받는 데이터 구조의 호환성을 유지시키는 데에도 도움이 됩니다.

 

백엔드와 프론트엔드가 동시에 개발되는 경우 

프론트엔드 개발자가 자신이 개발을 하면서 직접 필요한 데이터 구조가 있으면 데이터 구조를 정의하고 그에 맞는 쿼리를 작성하기만 하면 되기 때문에 굉장히 효율적으로 개발 진행이 가능합니다. 물론 백엔드 개발자는 이에 맞추어 resolver를 구현할 수 있습니다,

 

다양한 내장 개발자 도구를 사용하고 싶은 경우

GraphQL에는 굉장히 강력한 개발자 도구를 제공하는데요. 이것을 사용하면 API 개발 및 테스트 시에 굉장히 효율적인 도구로 사용될 수 있습니다. 실시간으로 쿼리를 작성하고 테스트할 수 있는 환경을 제공함으로써 간편한 스키마 탐색과 강력한 자동 완성 기능을 통해 손쉽게 개발이 가능하기 때문에 이를 원하는 경우에도 GraphQL은 적합한 기술이라고 할 수 있습니다.

 

 

7.  정리하며

그 동안 REST API만을 사용하며 개발을 해왔고 GraphQL이 좋다 좋다 얘기만 들었지 제대로 알아본적은 많이 없었는데 확실히 때에 따라서 REST API가 줄 수 없는 가치를 주는 기술임에는 틀림이 없는 것다고 느끼게 되었습니다. 

 

실제로 REST API로 개발하면서 '이런 경우에는 어떻게 해야하지?'와 같은 고민을 한 적이 굉장히 많은데 사실 그러한 것들이 전부 Over-Fetching, Under-Fetching과 관련된 내용이었으며, GraphQL을 사용한다면 이러한 걱정을 하지 않을 수 있다는 사실을 알게 되었습니다.

 

개발을 수 년간 해오면서 가장 크게 와닿는 말은 "Silver Bullet은 없다"라는 말입니다. 그만큼 다양한 기술들이 존재하고 프로젝트의 크기 역시 편차가 매우 크기 때문에 만능 열쇠는 없는 것이죠.

 

하지만 빠른 변화에 발맞춰 다양한 기술들을 배우고 습득하는 과정은 반드시 있어야 내가 처한 상황에 맞는 무기를 꺼낼 수 있을 것입니다.

  • 총으로 모기를 잡을 수 없고 파리채로 곰을 잡을 수 없듯이 말입니다.

 

'확장성'과 'API에 대한 메타 정보 관리'에 대해 관심이 있는 분들이라면 GraphQL을 써보는 것을 고려해보면 어떨까 조심스럽게 추천드립니다.

 

 

 

 

반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.