❓GraphQL이란?
❗️GraphQL 특징
- 하나의 EndPoint에 여러 API 요청 가능
- hero, villain 두가지 API를 한번에 요청 가능
- 필요한 정보만 요청할 수 있음
- villain 객체에 name, movie 등 여러 Field가 있는데, 그 중 필요한 name만 요청할 수 있다
- Depth있어도 해당 객체의 필요한 필드만 요청 가능. 반복문으로 DTO 파싱 및 필터링 없음
- hero.friends의 field 중에서 필요한 name만 요청할 수 있다.
- Overfetching 방지
- 원하는 데이터 이상의 정보를 요청받는것. data 정제에 리소스 낭비
- Underfetching 방지
- 원하는 data의 정보를 요청받기 위해 여러번 요청을 보내는것.
- REST API에서는 프론트엔드 개발자는 백앤드 개발자가 작성하여 전달하는 API의 request / response의 형식에 의존하게 된다. 그러나, GraphQL을 사용한 방식에 서는 이러한 의존도가 많이 사라진다. 다만 여전히 데이터 schema에 대한 협업 의존성은 존재한다.
Request
- query: REST API에서 GET과 비슷한 개념
- Request 부분(hero, villain처럼 API 이름 등)과 Response에서 요청할 데이터(name, friends와 같은 필드명)을 모두 명시한다
query{
hero {
name
friends {
name
}
}
villain {
name
}
}
Response
- request에서 요청한 데이터만 Response에 담아서 리턴됨
{
"data": {
"hero": {
"name": "R2-D2",
"friends": [
{
"name": "Luke Skywalker"
},
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
}
]
}
"hero": {
"name": "Thanos"
}
}
}
응답 객체
- Backend, Frontend 모두 스키마를 가지고 있어야하고, 그 스키마에는 모든 객체와 각각의 필드가 정확하게 정의되어야 한다.
type Hero {
name: String,
friends: [Friend],
power: Int
}
type Friend {
name: String,
relation: String
}
type Villain {
name : String
movie : String,
age: Int
}
🔆 GraphQL 핵심 개념
Query/Mutation
- Query
- 데이터를 단순히 받아올 때 주로 사용. CRUD 에서 Read에 해당하는 기능
- HTTP의 GET과 비슷
- 여러개의 Query를 요청했을 때 쿼리가 병렬로 실행됨
- Mutation
- 데이터 조작하는 쿼리에 주로 사용. CRUD에서 Create, Update, Delete에 해당하는 기능
- HTTP의 POST와 비슷
- 여러개의 Mutation을 요청했을 때 쿼리가 순차적으로 실행됨 (한 요청에 두개의 Mutation이 있는경우 순차적 실행)
오퍼레이션
- 일반 쿼리
- 변수를 직접 입력
- 특징란에서 예시로 든것이 일반 쿼리
- 오퍼레이션
- 쿼리용 함수 라고 생각하면 됨
- 프로그래밍으로 변수에 값을 할당 할 수 있는 함수 인터페이스가 존재
- 이 개념 덕분에 REST API를 호출할때와 다르게, 한번의 인터넷 네트워크 왕복으로 원하는 모든 데이터를 가져 올 수 있다.
Operation 을 사용한 Request
![](https://velog.velcdn.com/images/mdy0102/post/0b989139-0a9f-4312-a684-b499c90f2573/image.png)
query HeroNameAndFriends {
hero {
name
friends {
name
}
}
}
Response
{
"data": {
"hero": {
"name": "R2-D2",
"friends": [
{
"name": "Luke Skywalker"
},
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
}
]
}
}
}
🙃 기존 REST API 통신의 한계
- 특정 기능을 위해 여러번 API가 호출됨
- 특정 요청에 Fit한 응답을 돌려주기 위해 API를 새로 만들어야함
- API 유지보수의 어려움 (iOS, Android에 따라 일일이 API 따로 구현해야함)
🙂 장점
- 하나의 Endpoint로 한번의 요청으로 여러 API의 정보를 가져올 수 있다
- 필요한 데이터만 요청할 수 있다
- DTO 여러개 불필요
- 응답 Size를 줄일 수 있다
- 기종에 상관없이 표준화된 API 개발 가능
- 응답 객체의 Depth가 깊은 경우에도 원하는 데이터만 요청할 수 있다.
🙁 단점
- GraphQL 스키마에서 필드를 정확하게 모두 명시해줘야하므로 번거로운 상황이 생긴다
- DTO는 상속을 통해 필드 생략이 가능한데, GraphQL 스키마에서 필드 상속 또는 필드 생략할 수 없어서 필드를 모두 다 적어줘야한다
- Map, Object를 사용하지 못한다
- 하나의 필드만 담겨있어도 모든 응답을 객체로 만들어야 한다.
- REST API는 ResponseEntity, HashMap<String,Any>로 유연하게 리턴 가능한데, GraphQL은 [Friend]
List<Friend>라는 의미
이런식으로 정확히 정의해야한다.
- DTO의 필드명이 변경되면 GraphQL 스키마 필드를 수정해줘야한다
- 파일업로드
- GraphQL은 원칙적으로 multipart/from-data 형식을 받을 수 없고 application/json 형식만 받을 수 있음
- GraphQL에서는 multipart -> json으로 바꿔 전달해주는 미들웨어나 패키지를 사용해야하기 때문에 까다로움
- Client에서도 모든 필드를 작성해야한다
- Client에서 스키마를 가지고 있어야 요청할 수 있다.
- Backend에서 필드 수정이 일어나면 Client도 다시 배포해야한다
- 즉, 장점에서 백엔드/프론트엔드간 커플링 감소되어 유연성 증가한다고 써놨지만, 둘 다 동일한 스키마를 가지고 있어야 한다는 점에서는 여전히 커플링 되어있다고 할 수 있다.
- 필드 타입(스칼라 타입)이 한정적이다
- BackEnd 입장에서 설정해줄게 너무 많다.
- Query/Mutation 파일에 작성한 메서드 및 리턴타입과 스키마 파일을 무조건 동기화 시켜야하기 때문에 REST API 보다 작성할 파일이 더 많다.
👆장단점 총평
GraphQL은 프론트엔드 입장에서 개발하기 편한 통신방식인 것 같다.
보통 REST API로 개발하게 될 경우 API 리턴값 형식(DTO)을 바꾸기 위해서는 백엔드 개발자가 코드를 변경해줘야한다. 하지만 GraphQL은 원하는 데이터만 쿼리 조회를 하듯 받아올 수 있기 때문에 응답 사이즈를 최소화 한 채로 요청할 수 있다. (프론트엔드, 백엔드 커플링 감소)
특히, 응답 객체의 Depth가 깊은 경우 반복문으로 파싱 및 필터링 해주는 과정을 생략할 수 있어 장점이 크게 체감된다. (이건 백엔드 개발자에게도 큰 장점이다)
하지만 백엔드 개발자로서는 REST API보다 좀 더 설정할게 많고, 스키마 파일도 작성해야해서 조금 번거로운 부분이 있었다. 또한 파일업로드 구현이 좀 번거롭고, 필드 타입이 한정적이여서 겪은 어려움도 있었다.
하지만 Depth가 깊은(4~5개의 깊이를 객체가 있었다)객체를 구현할 때에는 편리했다. 이걸 일일이 프론트엔드 요청에 맞게 DTO를 만들어 각각 다른 API를 만들었으면 번거로웠을 것 같다.
정리 감사합니다:)