
들어가며
안녕하세요. 보이스루에서 CTO를 맡고 있는 윤승현입니다.
지난 1편에서는 번역 소프트웨어 개발 솔루션의 필요성에서 출발해 보이스루의 TMS 소개와 개발 과정을 소개했습니다.
REST API 기반 개발 플로우에서 한계점을 발견한 보이스루 테크팀은 GraphQL 사용을 시도하고 개발 플로우를 새로 작성하는데요.
‘미디어 로컬라이제이션’이라는 보이스루의 궁극적 목표에 기여하는 테크팀의 API 이야기, 두 번째 시간입니다.
GraphQL
GraphQL은 2012년 Facebook에서 개발하여 Opensource로 운영되는 Data API Query Language입니다.
API 통신을 위한 쿼리 언어라고 생각하시면 되겠습니다.
초심자를 위해 먼저 SQL(Structured Query Language)을 잠깐 짚고 넘어가겠습니다.
구조화된 쿼리 언어(질의어)는 BE에서 사용되며 DB에서 데이터를 저장하거나 호출하기 위해 사용되는 언어입니다.
GraphQL은 SQL과 다릅니다.
GraphQL은 서버에서 데이터를 저장하거나 호출하기 위해 사용되는 데이터 쿼리 언어이면서 Client에서 사용됩니다
기존의 REST API가 Resource에 대한 CRUD를 HTTP Method로 매핑해 운영했다면,
GraphQL은 GraphQL End-point에 Query하여 data를 fetching하기도 하고, data를 수정하는 mutating을 하기도 합니다.
RESTful API로는 다양한 기종(iOS, Android)에서 필요한 정보들을 일일이 구현하는 데 어려움이 있는데요.
이로 인해 정보를 사용하는 입장에서는 원하는 대로 정보를 가져올 수 있는 방법이 필요했습니다.
더 편하게 data를 핸들링하기 위해 새로운 Query language를 만들게 되었는데 이것이 GraphQL입니다.
End-point side
여러 차이점이 있지만 가장 단순하게 이해할 수 있도록 End-point 관점에서 설명하면,
REST API는 Resource 각각에 엔드 포인트를 설정하지만
GraphQL API는 여러 개의 Resource를 묶어 하나의 엔드 포인트로 설정합니다.
GraphQL 기반 개발 플로우
Data fetching 관점에서 GraphQL과 REST API의 가장 큰 차이를 확인할 수 있는데요.
GraphQL API는 data fetching이 BE에서 API를 생성해 data fetching을 제공하는 게 아니라,
FE에서 정해진 범위 안에서 자유롭게 Data fetching한다는 점입니다.
BE는 기준이 되는 Domain에 대한 Query를 시작할 수 있도록 만들고,
해당 Domain에 연관된 다른 Domain에 대한 정보를 엮어서 가져오는 작업은 사용자에게 맡기게 됩니다.

예를 들어, 서점의 결제 Admin System을 만든다고 가정하겠습니다.
서점에서 책을 주문하고, 해당 주문에 대한 총 결제 금액 관리 페이지를 만드는 과정을 설명하겠습니다.
GET /orders
[
{
"orderId" : "1",
"totalAmount" : 100000,
"accountId" : "1"
},
{
"orderId" : "2",
"totalAmount" : 120000,
"accountId" : "1"
},
{
"orderId" : "3",
"totalAmount" : 200000,
"accountId" : "2"
}
]
REST API는 위와 같이 만들 수 있습니다.
초기 요구 사항은 Admin System 결제 관리 페이지에서 결제 금액만 가져오는 것으로 만족할 수 있었지만,
사이트가 고도화되면서 고객이 몇 개의 상품을 구매했는지 알려주는 기능 요구 사항이 발생했다고 가정하겠습니다.
GET /orders/{orderId}/orderItems
[
{
"orderId": "1",
"orderItemId": "1",
"productId": "1"
},
{
"orderId": "1",
"orderItemId": "2",
"productId": "2"
}
]
위 API를 이용해 orderItems의 개수 정보를 만들 수 있기에, 각 order는 orderItems에 대한 API call로 처리 가능할 겁니다.
아니면 Order API에서 orderItem에 대한 정보를 한번에 내려주는것도 가능합니다.
요구 사항을 더 발전시켜 보겠습니다.
사용자의 요구 사항이 발생하고 결제한 상품을 함께 알려줘야하는 케이스가 생겼다고 가정하겠습니다.
해당 요구 사항을 만족시키기 위해선 두 가지 방법이 있습니다.
Product에 대한 REST API를 호출하여 상품 정보를 가져오는 것
그리고 주문 정보를 내려주는 API에서 주문 관련된 정보와 상품에 대한 정보를 한번에 가져오는 방법입니다.
API는 점점 더 많은 데이터를 한번에 전달해야 하는 상황에 놓이고, 여기서 사용자 이름까지 같이 띄워달라고 요청한다면,
Order API는 사용자 정보까지 한번에 조회해서 내려줘야 됩니다.
GraphQL 기반 개발 적용 장점
GraphQL로 해당 케이스를 개발해보겠습니다.
GraphQL의 기본 구조는 field과 resolver로 이루어져 있습니다. Order와 Account의 관계를 설명해보죠.
Order에 Account Field를 추가하고 field 값을 가져오는 resolver를 통해 그리고 Order를 통해 Account의 정보를 가져오도록 만들었습니다.
아래는 GraphQL schema와 데이터 구조입니다.
type Order {
orderId: string;
totalAmount: Int;
orderItems: [OrderItems];
account: Account;
}
type OrderItem {
orderId: string;
orderItemId: string;
productId: string;
product: Product;
}
type Product {
productId: string;
name: string;
price: Int;
leftAmount: Int;
}
type Account {
id: string;
name: string;
email: string;
orders: [Order]
}

GraphQL을 통해 위 케이스를 개발한다면, 각각 schema에 연관되는 schema를 resolver로 연결하는 방식으로 구현됩니다.
query orders(size : 10 , page : 1) {
orderId
totalAmount
orderItems {
orderItemId
product {
name
price
}
}
account {
name
}
}
기존에 API에 기능을 확장하는것과 동일한 패턴입니다.
하지만 GraphQL의 강점은 한번 schema들을 연결해두면 다른 곳에서 재사용이 가능하다는 것입니다.
이번에도 예를 들어보겠습니다.
서비스가 발전해 기업 고객이 발생하였고, 기업 고객은 여러 개의 계정을 통해 서점을 이용한다고 가정하겠습니다.
유저 페이지에서 해당 유저가 어떤 기업의 소속인지 알기 위해, Account에서 Company 정보를 접근 가능하도록
Resolver를 통해 연결했다고 가정하겠습니다.

type Account {
id: string;
name: string;
email: string;
orders: [Order];
company: Company;
}
type Company {
id : string;
name : string;
managerAccountId: string;
accounts: [Account]
}
query accounts(size : 10, page : 1) {
name
email
company {
name
}
}
결제 관리 페이지를 확인해 어느 회사에서 발생한 결제인지에 따라 Admin의 CS 대응 방침이 다르게 수립된다고 가정하겠습니다.
결제 관리 페이지의 결제 정보에서 회사 정보를 노출해야 합니다.
이 부분이 기존의 REST API 방법에서 고민되는 지점인데요.
Order API에서 account 정보를 담아주는 곳에 company 정보까지 담아줘야 하는지
아니면 FE에서 Company 정보를 REST API로 가져와야 하는지 고민이 생깁니다.
Order API에서 Company 정보까지 확장하는 과정은, OrderAPI가 Company 정보까지 의존해야 하는 결과를 만듭니다.
여기에 더해 Company에 새로운 변수가 추가된다면 OrderAPI에서도 Company의 정보를 확장해야 됩니다.
GraphQL이라면 Account와 Company가 이미 연결되어 있기에 Account에 연결된 Company 정보만 가져오면 됩니다.
그리고 Company를 담당하는 resolver는 Order에서 관리하는 것이 아니기에 업데이트 이슈에서도 자유롭습니다.
query orders(size : 10 , page : 1) {
orderId
totalAmount
orderItems {
orderItemId
product {
name
price
}
}
account {
name
company {
name
}
}
}
위처럼 이미 Account와 Company는 연결되어 있기에 query에서 해당 정보까지만 fetching해오면 됩니다.
개발 프로세스 효율화
기존 개발 프로세스에선 ‘요구 사항 발생 → PM 요구 사항 분석 → BE API 개발 → FE View 개발’ 순서로 진행했었죠.
GraphQL을 사용하니 이미 Graph로 연결되어 있는 정보를 추가하는 경우,
개발 프로세스는 ‘요구 사항 발생 → PM 요구 사항 분석 → BE API 개발 → FE View 개발’에서
BE API 개발이 빠지기 때문에 처리하기 더 좋은 요구 사항이 됩니다.

정리하면 GraphQL의 장점은 다음과 같습니다.
- BE에서는 Domain 간 연결만 관리하면 되기에 더 처리하기 좋은 요구 사항이다.
- 개발 플로우를 ‘기획 → FE’로 압축할수 있다.
마치며
지금까지 개발 요구 사항을 가정하여 GraphQL과 이를 이용한 개발 플로우를 설명드렸는데요.
같은 개발 요구 사항에 REST API와 GraphQL 간의 비교 적용을 통해 GraphQL을 알아보았습니다.
하지만 아무리 GraphQL 이라도 장점만 존재하지 않는데요. 단점과 이에 대한 대응은 다음과 같습니다.
1. HTTP Caching 사용 불가
GraphQL는 엔드 포인트가 1개이므로 HTTP 에서 제공되는 Caching은 사용 불가.
그러나 GraphQL은 Apollo의 Apollo Engine에서 자체 캐시를 제공하기에 이를 활용.
2. File 업로드
기존에는 GraphQL에서 Query를 전송하고 Json만 리턴받았기 때문에 파일 업로드가 불가능했었음.
GraphQL 업데이트 후 외부 라이브러리를 사용해 해결.
3. Recursive Query(재귀 쿼리)
GraphQL의 schema를 잘못 짜거나 잘못 요청하면 재귀적으로 쿼리를 요청하게되는 경우가 있음.
이 경우 BE 서버에 부하를 줄 수 있음. 재귀적 쿼리를 막거나 DataLoader 패턴을 이용하여, 재귀적으로 호출 되더라도 부하를 줄일 수 있습니다.
4. Response가 JSON만 지원하는 한계
5. 표준 부재
실질적 표준 부재(REST API는 표준이 존재한다)
Spec은 정의되고 있으나, 아직은 사용에 대한 방법이 자유롭습니다.
그러나 반드시 둘 중 하나를 선택할 필요는 없습니다.
예를 들어 하나의 End-point는 GraphQL용으로 만들고, 다른 하나는 REST API용 End-point를 만들어도 좋습니다.
하지만, 하나의 목표를 위해 2가지 API 구조를 섞는 것은 API의 품질을 떨어트릴 수 있습니다.
(ex. 사용자 정보 등록은 REST API 선택, 사용자 정보 수정은 GraphQL API 선택)
<GraphQL vs REST, 보이스루 API를 고민하다 ②>은 여기서 마치겠습니다.
다음 마지막 3편에서는 GraphQL을 적용한 글로벌 사례를 알아보고 정리하며 보이스루가 얻은 인사이트와 배움을 소개하겠습니다.
감사합니다.
들어가며
안녕하세요. 보이스루에서 CTO를 맡고 있는 윤승현입니다.
지난 1편에서는 번역 소프트웨어 개발 솔루션의 필요성에서 출발해 보이스루의 TMS 소개와 개발 과정을 소개했습니다.
REST API 기반 개발 플로우에서 한계점을 발견한 보이스루 테크팀은 GraphQL 사용을 시도하고 개발 플로우를 새로 작성하는데요.
‘미디어 로컬라이제이션’이라는 보이스루의 궁극적 목표에 기여하는 테크팀의 API 이야기, 두 번째 시간입니다.
GraphQL
GraphQL은 2012년 Facebook에서 개발하여 Opensource로 운영되는 Data API Query Language입니다.
API 통신을 위한 쿼리 언어라고 생각하시면 되겠습니다.
초심자를 위해 먼저 SQL(Structured Query Language)을 잠깐 짚고 넘어가겠습니다.
구조화된 쿼리 언어(질의어)는 BE에서 사용되며 DB에서 데이터를 저장하거나 호출하기 위해 사용되는 언어입니다.
GraphQL은 SQL과 다릅니다.
GraphQL은 서버에서 데이터를 저장하거나 호출하기 위해 사용되는 데이터 쿼리 언어이면서 Client에서 사용됩니다
GraphQL은 왜 만들어졌을까요?
기존의 REST API가 Resource에 대한 CRUD를 HTTP Method로 매핑해 운영했다면,
GraphQL은 GraphQL End-point에 Query하여 data를 fetching하기도 하고, data를 수정하는 mutating을 하기도 합니다.
RESTful API로는 다양한 기종(iOS, Android)에서 필요한 정보들을 일일이 구현하는 데 어려움이 있는데요.
이로 인해 정보를 사용하는 입장에서는 원하는 대로 정보를 가져올 수 있는 방법이 필요했습니다.
더 편하게 data를 핸들링하기 위해 새로운 Query language를 만들게 되었는데 이것이 GraphQL입니다.
여러 차이점이 있지만 가장 단순하게 이해할 수 있도록 End-point 관점에서 설명하면,
REST API는 Resource 각각에 엔드 포인트를 설정하지만
GraphQL API는 여러 개의 Resource를 묶어 하나의 엔드 포인트로 설정합니다.
GraphQL 기반 개발 플로우
Data fetching 관점에서 GraphQL과 REST API의 가장 큰 차이를 확인할 수 있는데요.
GraphQL API는 data fetching이 BE에서 API를 생성해 data fetching을 제공하는 게 아니라,
FE에서 정해진 범위 안에서 자유롭게 Data fetching한다는 점입니다.
BE는 기준이 되는 Domain에 대한 Query를 시작할 수 있도록 만들고,
해당 Domain에 연관된 다른 Domain에 대한 정보를 엮어서 가져오는 작업은 사용자에게 맡기게 됩니다.
예를 들어, 서점의 결제 Admin System을 만든다고 가정하겠습니다.
서점에서 책을 주문하고, 해당 주문에 대한 총 결제 금액 관리 페이지를 만드는 과정을 설명하겠습니다.
REST API는 위와 같이 만들 수 있습니다.
초기 요구 사항은 Admin System 결제 관리 페이지에서 결제 금액만 가져오는 것으로 만족할 수 있었지만,
사이트가 고도화되면서 고객이 몇 개의 상품을 구매했는지 알려주는 기능 요구 사항이 발생했다고 가정하겠습니다.
위 API를 이용해 orderItems의 개수 정보를 만들 수 있기에, 각 order는 orderItems에 대한 API call로 처리 가능할 겁니다.
아니면 Order API에서 orderItem에 대한 정보를 한번에 내려주는것도 가능합니다.
요구 사항을 더 발전시켜 보겠습니다.
사용자의 요구 사항이 발생하고 결제한 상품을 함께 알려줘야하는 케이스가 생겼다고 가정하겠습니다.
해당 요구 사항을 만족시키기 위해선 두 가지 방법이 있습니다.
Product에 대한 REST API를 호출하여 상품 정보를 가져오는 것
그리고 주문 정보를 내려주는 API에서 주문 관련된 정보와 상품에 대한 정보를 한번에 가져오는 방법입니다.
API는 점점 더 많은 데이터를 한번에 전달해야 하는 상황에 놓이고, 여기서 사용자 이름까지 같이 띄워달라고 요청한다면,
Order API는 사용자 정보까지 한번에 조회해서 내려줘야 됩니다.
GraphQL 기반 개발 적용 장점
GraphQL로 해당 케이스를 개발해보겠습니다.
GraphQL의 기본 구조는 field과 resolver로 이루어져 있습니다. Order와 Account의 관계를 설명해보죠.
Order에 Account Field를 추가하고 field 값을 가져오는 resolver를 통해 그리고 Order를 통해 Account의 정보를 가져오도록 만들었습니다.
아래는 GraphQL schema와 데이터 구조입니다.
GraphQL을 통해 위 케이스를 개발한다면, 각각 schema에 연관되는 schema를 resolver로 연결하는 방식으로 구현됩니다.
기존에 API에 기능을 확장하는것과 동일한 패턴입니다.
하지만 GraphQL의 강점은 한번 schema들을 연결해두면 다른 곳에서 재사용이 가능하다는 것입니다.
이번에도 예를 들어보겠습니다.
서비스가 발전해 기업 고객이 발생하였고, 기업 고객은 여러 개의 계정을 통해 서점을 이용한다고 가정하겠습니다.
유저 페이지에서 해당 유저가 어떤 기업의 소속인지 알기 위해, Account에서 Company 정보를 접근 가능하도록
Resolver를 통해 연결했다고 가정하겠습니다.
결제 관리 페이지를 확인해 어느 회사에서 발생한 결제인지에 따라 Admin의 CS 대응 방침이 다르게 수립된다고 가정하겠습니다.
결제 관리 페이지의 결제 정보에서 회사 정보를 노출해야 합니다.
이 부분이 기존의 REST API 방법에서 고민되는 지점인데요.
Order API에서 account 정보를 담아주는 곳에 company 정보까지 담아줘야 하는지
아니면 FE에서 Company 정보를 REST API로 가져와야 하는지 고민이 생깁니다.
Order API에서 Company 정보까지 확장하는 과정은, OrderAPI가 Company 정보까지 의존해야 하는 결과를 만듭니다.
여기에 더해 Company에 새로운 변수가 추가된다면 OrderAPI에서도 Company의 정보를 확장해야 됩니다.
GraphQL이라면 Account와 Company가 이미 연결되어 있기에 Account에 연결된 Company 정보만 가져오면 됩니다.
그리고 Company를 담당하는 resolver는 Order에서 관리하는 것이 아니기에 업데이트 이슈에서도 자유롭습니다.
위처럼 이미 Account와 Company는 연결되어 있기에 query에서 해당 정보까지만 fetching해오면 됩니다.
개발 프로세스 효율화
기존 개발 프로세스에선 ‘요구 사항 발생 → PM 요구 사항 분석 → BE API 개발 → FE View 개발’ 순서로 진행했었죠.
GraphQL을 사용하니 이미 Graph로 연결되어 있는 정보를 추가하는 경우,
개발 프로세스는 ‘요구 사항 발생 → PM 요구 사항 분석 → BE API 개발 → FE View 개발’에서
BE API 개발이 빠지기 때문에 처리하기 더 좋은 요구 사항이 됩니다.
정리하면 GraphQL의 장점은 다음과 같습니다.
마치며
지금까지 개발 요구 사항을 가정하여 GraphQL과 이를 이용한 개발 플로우를 설명드렸는데요.
같은 개발 요구 사항에 REST API와 GraphQL 간의 비교 적용을 통해 GraphQL을 알아보았습니다.
하지만 아무리 GraphQL 이라도 장점만 존재하지 않는데요. 단점과 이에 대한 대응은 다음과 같습니다.
1. HTTP Caching 사용 불가
GraphQL는 엔드 포인트가 1개이므로 HTTP 에서 제공되는 Caching은 사용 불가.
그러나 GraphQL은 Apollo의 Apollo Engine에서 자체 캐시를 제공하기에 이를 활용.
2. File 업로드
기존에는 GraphQL에서 Query를 전송하고 Json만 리턴받았기 때문에 파일 업로드가 불가능했었음.
GraphQL 업데이트 후 외부 라이브러리를 사용해 해결.
3. Recursive Query(재귀 쿼리)
GraphQL의 schema를 잘못 짜거나 잘못 요청하면 재귀적으로 쿼리를 요청하게되는 경우가 있음.
이 경우 BE 서버에 부하를 줄 수 있음. 재귀적 쿼리를 막거나 DataLoader 패턴을 이용하여, 재귀적으로 호출 되더라도 부하를 줄일 수 있습니다.
4. Response가 JSON만 지원하는 한계
5. 표준 부재
실질적 표준 부재(REST API는 표준이 존재한다)
Spec은 정의되고 있으나, 아직은 사용에 대한 방법이 자유롭습니다.
그러나 반드시 둘 중 하나를 선택할 필요는 없습니다.
예를 들어 하나의 End-point는 GraphQL용으로 만들고, 다른 하나는 REST API용 End-point를 만들어도 좋습니다.
하지만, 하나의 목표를 위해 2가지 API 구조를 섞는 것은 API의 품질을 떨어트릴 수 있습니다.
(ex. 사용자 정보 등록은 REST API 선택, 사용자 정보 수정은 GraphQL API 선택)
<GraphQL vs REST, 보이스루 API를 고민하다 ②>은 여기서 마치겠습니다.
다음 마지막 3편에서는 GraphQL을 적용한 글로벌 사례를 알아보고 정리하며 보이스루가 얻은 인사이트와 배움을 소개하겠습니다.
감사합니다.