Meta(Facebook)에서 만든 API를 위한 Query 언어다. 기존 REST API 한계점 을 극복할 수 있다.
URL,METHOD ...조합하기 때문에 다양한 Endpoint가 존재.
클라이언트 구조변경 시 엔드포인트 변경이나 데이터 수정 필요.
서버에서 자원의 크기,형태를 결정하므로 클라이언트에서 필요한 데이터 변경 시 다른 엔드포인트로 변경된 데이터 수정하거나 가져와야 함
Over fetching, Under fetching 발생.
Over fetching
요청영역보다 많은 정보를 받은 것.
Under fetching
모든 정보 얻기 위해 많은 요청해야 함.
각 자원에 따라 엔드포인트 구분하므로 각 엔드포인트마다 요청해야 함
ex) 앱 시작하면 피드,알림,프로필... 요청해야함
REST API | GraphQL | |
---|---|---|
리소스 형태정의와 데이터 요청 방법 | 연결됨 | 분리됨 |
리소스 크기,형태 결정 | 서버가 결정 | 리소스 정보만 정의하고 필요한 크기,형태는 클라이언트 단에서 요청 시 결정 |
리소스 / 작업 유형 | URI가 리소스 나타내고, Method가 작업 유형 나타냄 | Schema가 리소스 나타내고, Query, Mutation 타입이 작업 유형 나타냄 |
요청 횟수 | 리소스 접근할 때 여러번 요청 | 여러 리소스들 한번 요청으로 접근 가능 |
작업 처리 | 각 요청은 엔드 포인트에 정의된 핸들링함수 호출하여 작업 처리 | 요청받은 각 필드에 대한 resolver 호출하여 작업 처리 |
Graph + Query Language
- Graph란?
마인드맵처럼 여러 정점(vertex) 또는 Node가 간선(edge)으로 연결되어 있는 자료구조다. 그래프를 어느입장에서 정렬하는지에 따라 트리구조를 이룰 수 있다.
POST
메소드 사용POST
메소드만으로 요청 보내기 떄문에 각 메소드에 따른 캐싱을 지원받을 수 없다. 이를 보안하기 위해 Apollo 엔진의 캐싱과 영속 쿼리 등이 등장했다.
Query : 데이터 읽기(R) 서버에 요청
Mutation : 데이터 변조(CUD) 한다는 규약 정한 것
schema : 내가 사용자에게 보내거나 받을 data에 대한 설명
resolver : Query를 해결하는 해결사. 서버가 Query나 Mutation 정의 발견하면 resolver를 찾아서 함수 실행한다.
Subscription: 특정 이벤트가 발생 시, 서버가 대응하는 데이터를 실시간으로 클라이언트에게 전송
데이터 조회
# 요청
{
human(id: "1000") { # 인자로 원하는 값만 받아오기
name # 필드
height # 필드
}
}
# 응답결과
{
"data": {
"human": {
"name": "Luke Skywalker",
"height": 1.72
}
}
}
# bad
{
hero(episode: EMPIRE) {
name
}
hero(episode: JEDI) {
name
}
}
# good
{
empireHero: hero(episode: EMPIRE) {
name
}
jediHero: hero(episode: JEDI) {
name
}
}
# 응답
{
"data": {
"empireHero": {
"name": "Luke Skywalker"
},
"jediHero": {
"name": "R2-D2"
}
}
}
오퍼레이션 타입(Operation type)
: query
, mutation
, subscription
, describes
등
오퍼레이션 네임(Operation name)
: 오퍼레이션 타입에 맞는 이름으로 작성
쿼리 keyword(query)와 쿼리 name(HeroNameAndFriends)을 작성해야 한다.
query HeroNameAndFriends {
hero {
name
friends {
name
}
}
}
($변수 이름: 타입 형태)
($변수 이름: 타입 형태!)
: 뒤에 !붙이면 필수여야 한다는 뜻(optional)query HeroNameAndFriends($episode: Episode) {
hero(episode: $episode) {
name
friends {
name
}
}
}
데이터 수정
mutation
키워드를 사용하여 서버 측 데이터 수정
mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
createReview(episode: $ep, review: $review) {
stars
commentary
}
}
사용자에게 보내거나 받을 data에 대한 설명
- 구성요소
서비스에서 가져올 수 있는 객체 종류, 포함하는 필드를 나타내는 객체 유형
type Character {
name: String!
appearsIn: [Episode!]!
}
Character
: GraphQL 객체 타입이며 필드가 있는 타입임을 의미.
스키마에 있는 대부분은 객체 타입.
name
, appearIn
: Character 타입의 필드 field
.
GraphQL 쿼리의 Character 타입 어디서나 사용 가능한 필드.
String
: 내장된 스칼라 타입 중 하나.
단일 스칼라 객체로 확인되는 유형이며 쿼리에서 하위 선택을 가질 수 없다. 스칼라 타입에는 ID, Int도 있다.
!
가 붙으면 이 필드는 nullable하지 않고 반드시 값이 들어온다는 의미. 반드시 값을 받을 수 있다는 예상을 할 수 있다.
[ ]
: 배열을 의미.
배열에도 !가 붙을 수 있다. null 값을 허용안하므로 항상 0개 이상의 요소를 포함한 배열을 예상을 할 수 있다.
Query를 해결하는 것.
- 서버가 Query, Mutation, Subscription 타입의 스키마 정의를 발견하면 스키마 필드에 해당하는 resolver 함수 찾아서 실행한다.
const db = require("./../db")
const resolvers = {
Query: { // **Query :** 저장된 데이터 가져오기 (REST 에 GET 과 비슷합니다.)
getUser: async (_, { email, pw }) => {
db.findOne({
where: { email, pw }
}) ... // 실제 디비에서 데이터를 가져오는 로직을 작성합니다.
...
}
},
Mutation: { // **Mutation :** 저장된 데이터 수정하기 ( Create , Update , Delete )
createUser: async (_, { email, pw, name }) => {
...
}
}
Subscription: { // **Subscription :** 실시간 업데이트
newUser: async () => {
...
}
}
};