GraphQL의 장점은?
Overfetching, UnderFetching의 문제를 해결할 수 있음.
하나의 endpoint에서 모든 요청을 처리
GraphQL은 명세, 형식일 뿐. GraphQL을 구현할 솔루션이 필요하다.
ex. GraphQL.js / GraphQL Yoga 등.
대표적인 솔루션 - Apollo (서버/프론트) 모두 제공 및 간편하고 쉬운 설정과 다양한 기능.
GraphQL의 개념을 공부하면서 처음에 헷갈렸던 부분이 GraphQL이 무엇인지 알겠는데 어떻게 구현하는거지? 라는 생각이었다. 쉽게 생각해보면 하나의 endpoint를 만들어두고 해당 endpoint에서 모든 분기를 공통적으로 처리할 수 있도록 해야하는데, 생각보다 복잡한 구현이 될 것 같았다.
역시 GraphQL을 구현해주는 솔루션이 있었는데 Apollo가 대표적인 솔루션 중에 하나이다.
Node.js Apollo서버 예시 코드를 보면서 이해해보자.
* 참고: GraphQL은 5개의 기본 타입이 있는데 ID, String, Int, Float, Boolean이 있다. 열거 타입 enum / 객체타입 type / union타입 : 한 배열안에 다른 타입을 넣고 싶을 때
//db가 있다고 생각해본다.
const seedDB = require('./someseedDB')
//npm install로 apollo server를 설치한다.
const { Apollo, gql } = require('apollo-server')
//일종의 스키마
const schema = gql`
//Item들 가져오기, Item 단수 하나 가져오기에 해당하는 쿼리 정의
type Query{
getItems : [Item]
getItem : Item
}
//Item 생성, 삭제, 업데이트
//일반적으로 graphQL에서는 생성, 삭제와 업데이트에 해당하는 것은 Mutation으로 정의한다.
type Mutation {
insertItem(
id: Int
name: String
stocks: Int
price: Int
): Item
//id에해당하는 Item을 삭제하고 삭제된 item을 반환하는 resolver를 구현한다.
deleteItem(id: Int): item
editItem(
id: Int
name: String
stocks: Int
price: Int
): Item
}
type Item {
id: Int
name : String
stocks: Int
price : Int
}
`
//쿼리를 해결해줄 핸들러로 생각하면 이해가 잘 된다.
const resolver = {
Query: {
getItems: () => seedDB.items,
getItem: (parent, args, context, info) => {},
editItem: (parent, args, context, info) => {
//수정에 관련된 db로직이 들어가면 된다.
},
insertItem: (parent, args, context, info) => {
//args에 item이 들어올테니 args를 활용해 db에 추가 로직이 들어간다.
},
deleteItem: (parent, args, context, info) => {
//args를 통해 query나 mutation의 argument를 가져올 수 있다.
/*
args.id를 활용해 DB에서 삭제로직이 들어갈 것이다.
*/
},
}
}
//Schema와 resolver를 함께 넣으며 서버를 생성한다.
const server = new ApolloServer({schema, resolver})
server.listen().then(()=>console.log("running at ~~"))
근데 여기까지만 보면 사실 resolver가 그동안 했던 핸들링을 모두 해주는거 아닌가 생각이 든다. 우선 이런형태다.
GraphQL을 흔히 REST API와 비교하곤 하는데, 그럼 REST처럼 CRUD 각각 graphQL로 어떤 쿼리를 날려야 하는지 확인 해보고, REST에서 해결하기 힘든 상황을 통해 graphQL의 장점을 확인해보자.
REST getItems에 해당하는 쿼리.
//REST에서 /api/items 로 item전부를 가져오는 쿼리는 graphQL에서는 이렇게 만든다.
query{
getitems {
id
name
price
stock
}
}
REST API에서 getItem (단수) 에 해당하는 쿼리.
//id가 1에 해당하는 item을 주세요.
query {
item(id: 1) {
id
name
price
stock
}
}
REST API에서 createItem (addItem)에 해당하는 쿼리(graphQL에서는 Mutation)
mutation {
//추가할 item의 명세를 인자로 적어 전달한다. 이는 args에 들어갈 것이다.
//추가하면 resolver를 통해 생성된 item을 받아올 것이기 때문에 뒤에 item을 받아온다.
insertItem (
id: 23939
name: "nike shoes"
price: 99900
stocks: 291
) {
id
name
price
stocks
}
}
REST API에서 updateItem에 해당하는 쿼리(mutation) 위에서 생성한 nike shoes의 stocks를 변경해준다.
mutation {
//수정할 item의 명세를 인자로 적어 전달한다. 이는 args에 들어갈 것이다.
//수정하면 resolver를 통해 생성된 item을 받아올 것이기 때문에 뒤에 item을 받아온다.
editItem (
id: 23939
name: "nike shoes"
price: 99900
stocks: 120
) {
id
name
price
stocks
}
}
REST API에서 deleteItem에 해당하는 쿼리
mutation {
//삭제할 Item의 id를 적어서 보내준다. 삭제한 Item을 리턴값을 받아온다.
deleteItem (
id: 23939
) {
id
name
price
stocks
}
}
여기까지만 보면 graphQL의 장점이 무엇인지 정확히 이해하기 힘들 것이다. 이제 다음 상황을 생각해보자.
1. Overfetching 상황
위의 예시에서는 Item이 오직 네개의 필드만을 가지는 간단한 데이터였다. 근데 만일 Item이 엄청나게 많은 필드를 가진 데이터라면 어떤 불편함이 있을까?
type Item struct{
Name
Stock
Stars
like
dislike
Price
isTrend
isHot
wholike
...(등등 200개의 필드가 더 있다고 가정해보자)
created_at
updated_at
deleted_at
}
만일 여기서 Item들이 현재 트렌드이고 인기상품인지 알기 위해 (isTrend와 isHot)필드만 알고 싶다고 가정하면, REST에서는 getItems를 통해 전체 필드를 다 가져온 후 확인해야 한다. 결국 필요하지 않은 필드 200여개를 함께 가져오게 되는 것이다. 이게 바로 overfetching이다.
그럼 graphQL에서는 어떻게 하면될까?
//이렇게 원하는 필드만 가져옴으로써 overfetching을 해결할 수 있다.
query{
getitems {
isHot
isTrend
}
}
이렇게 원하는 필드만 가져오면 된다.
2. Underfetching 상황
또 다른 예시를 생각해보자. 만일 Item 자원만 필요한 것이 아니라, 구매자들 (Buyer) 자원도 함께 필요하다고 생각해보자. 그럼 REST API를 활용한다면 이런 형태로 활용할 것이다. (Pseudo Code)
//의사 코드로 표현하면 다음과 같을 것이다.
function getItems() {
return axios.get('/api/items');
}
function getBuyers() {
return axios.get('/api/buyers');
}
axios.all([getItems(), getBuyers()]).then(....)
이렇게 두 번에 걸쳐서 데이터를 가져오게 된다. 한 번으로는 원하는 값들을 전부 가져오지 못한다 (= undefetching). 이게 underfetching 상황이다.
그럼 GraphQL에서는 이를 어떻게 할까? 한번에 쿼리로 원하는값만 딱 가져올 수 있다.
query{
//심지어 원하는것만 가져올 수 있다.
getItems{
id
isHot
isTrend
}
getBuyers{
id
name
gender
}
}
이정도만 봐도 GraphQL이 어떤 장점이 있는지 캐치하기 쉬울 것이다. 더 다룰 내용이 남았는데 다음에 정리해야 겠다.
*다음에 정리할 것
또한 GraphQL은 이름에서부터 알 수 있듯이 여러 자원들간의 연결을 쉽게 해주는 장점이 있다.
이렇게 GraphQL의 장점을 알 수 있는데 이건 기능적인 측면이고, 생산적인 측면에서도 장점을 갖는다.
생산성
기존의 REST방식이라면 다른 API가 필요할 때 백엔드 개발자에게 이를 요청해야 한다. 하지만 GraphQL은 이를 좀 더 유연하게 대처할 수 있도록 해준다. 이는 같은 자원을 요구할 때 서로 다른 플랫폼에서는 다른 필드들만 필요할 수 있는데 이와 같은 상황도 쉽게 대처할 수 있게 해준다.
* graphQL한번에 이해하기 쉬운 두개의 영상
참조 1: www.youtube.com/watch?v=1p-s99REAus
참조 2: www.youtube.com/watch?v=9BIXcXHsj0A