API를 위한 Query Language.
REST API는 여러 엔드포인트에 액세스해서 데이터를 수집해야한다. (다중 엔드포인트)
GraphQL은 구체적인 데이터 요구 사항이 포함된 단일 쿼리로 요청이 가능하다.
REST API는 overfetching과 underfetching을 유발시킨다.
사용자 이름만 알고 싶은데, 모든 데이터를 가져와야한다. (overfetching)
사용자 정보랑 팔로워를 알고 싶은데, 둘다 호출해야한다. (underfetching)
GraphQL은 둘다 유발하지 않는다. 필요한 데이터만 요청하고 (overfetching 해결) 한번의 요청으로 원하는 데이터를 가져올 수 있다. (underfetching 해결)
clone 해서 npm install
url/graphiql
을 명시해주면 개발자 도구로 들어갈 수 있다.
{
__schema {
types {
name
kind
}
}
}
schema.graphql
query는 데이터를 가지고 오는 것(fetch)
쿼리와 결과는 형태가 동일하다. (결과는 JSON 형태)
* tip! ctrl+space bar
누르면 자동완성 될 키워드 목록 보여줌
쿼리는 객체를 참조할 수 있어서 여러 값을 한번에 가져올 수 있다.
쿼리에 # 으로 주석 처리도 가능하다.
쿼리의 필드 이름이 같은데 인자를 다르게 조회하고 싶은 경우에는 별칭(alias) 를 지정해주어야한다.
지정해주지 않아 오류가 난 모습
지정해주니 잘 나온다.
{
p1: person (personID: 1) {
...personInfo
}
p2: person (personID: 2) {
...personInfo
}
}
fragment personInfo on Person {
name
homeworld {
name
}
filmConnection {
pageInfo {
startCursor
endCursor
}
}
}
fragment를 사용할 수 있다.
fragment 내에서 변수 사용도 가능하다.
query pInfo($first: Int = 3) {
p1: person (personID: 1) {
...personInfo
}
p2: person (personID: 2) {
...personInfo
}
}
fragment personInfo on Person {
name
homeworld {
name
}
filmConnection(first: $first) {
edges {
node{
title
}
}
}
}
$ 표시로 변수를 선언할 수 있다.
query에서 변수를 사용하기 위해서는 앞에 query
라고 명시해주어야 한다.
우리는 여태껏 익명함수를 써왔다고 생각하면 된다.
query에 이름을 지정해줄 수도 있다.
인자를 동적으로 조작하기 위한 방법으로 변수를 사용한다.
변수의 기본값을 명시할 수도 있다.
필드나 프래그먼트에 삽입할 수 있고 서버가 원하는 방식으로 쿼리 실행에 영향을 준다.
@include(if: Boolean): 인자가 true 인 경우에만 이 필드를 결과에 포함
@skip(if: Boolean) 인자가 true 이면 이 필드를 건너뜀
완전한 데이터 플랫폼은 서버 측 데이터를 수정할 수도 있어야한다.
데이터를 수정하는 것을 mutation이라고 한다.
Apollo graphQL 이용해서 실습을 한다.
https://studio.apollographql.com/public/SpaceX-pxxbxen/explorer?variant=current
쿼리 필드는 병렬로 실행되지만 뮤테이션 필드는 하나씩 차례대로 실행됩니다.
그래서 삽입 후 바로 업데이트 하는 경우 첫번째 요청은 두번째 요청 전에 완료되는 것이 보장된다.
인터페이스나 유니언 타입을 반환하는 필드를 쿼리하는 경우, 인라인 프래그먼트 을 사용해야한다.
GraphQL 쿼리 언어는 기본적으로 객체의 필드를 선택하기 때문에 쿼리가 반환할 결과를 거의 예측할 수 있다.
하지만 서버에 요청할 수 있는 데이터에 대한 정확한 표현을 가져야지는 것이 좋다.
GraphQL 스키마의 가장 기본적인 구성 요소는 객체 타입이다. 객체 타입은 서비스에서 가져올 수 있는 객체의 종류와 그 객체의 필드를 나타낸다.
type Character {
name: String!
appearsIn: [Episode]!
}
Character
GraphQL 객체 타입. 필드가 있는 타입.
스키마 대부분은 객체 타입이다.
name, appearsIn
Character 타입의 필드.
String
GraphQL에 내장된 스칼라 타입.
[Episode]
Episode 객체의 배열.
객체 타입의 모든 필드는 0개 이상의 인자를 가질 수 있다.
어떤 필드가 구체적인 데이터로 해석되기를 원할 때 지정해주는 타입.
쿼리의 끝을 나타내며 하위 선택을 할 수 없다.
Int
Float
String
Boolean
ID
ID 스칼라 타입은 객체를 다시 요청하거나 캐시의 키로써 자주 사용되는 고유 식별자를 나타낸다. ID 타입은 String 과 같은 방법으로 직렬화되지만, ID 로 정의하는 것은 사람이 읽을 수 있도록 하는 의도가 아니라는 것을 의미한다.
Enums. 특정 값들로 제한 되는 특정한 종류의 스칼라 타입이다.
enum Episode {
NEWHOPE
EMPIRE
JEDI
}
Episode 타입을 사용하면 정확히 NEWHOPE, EMPIRE, JEDI 중에 하나일 것이다. 지정해둔 값 중 하나가 될 것이라는 타입이다.
타입 뒤에 느낌표 ! 를 추가하여 Non-Null 로 표시하면 이 값은 무조건 null이 돼서는 안된다.
리스트에서도 비슷하게 동작한다.
/ | [String] | [String!] | [String]! | [String!]! |
---|---|---|---|---|
null | O | O | X | X |
[ ] | O | O | O | O |
['a', 'b'] | O | O | O | O |
['a', 'b', null] | O | X | O | X |
특정 필드를 포함하는 추상 타입이다.
해당 인터페이스를 구현한 타입들이 가져야 할 필드를 정의.
interface Character {
id: ID!
name: String!
friends: [Character]
appearsIn: [Episode]!
}
Character를 구현한 모든 타입은 이러한 인자와 리턴 타입을 가진 정확한 필드를 가져야한다.
유니온 타입은 인터페이스와 매우 유사하지만, 타입 간에 공통 필드를 특정하지 않는다.
union SearchResult = Human | Droid | Starship
스키마에서 SearchResult 타입을 반환할 때마다 뒤에 명시된 값들을 얻을 수 있다. 유니온 타입의 멤버는 구체적인 객체 타입이어야 한다.
뮤테이션은 생성될 전체 객체를 전달하고자 할 수 있다. GraphQL 스키마 언어에서 입력 타입은 일반 객체 타입과 정확히 같지만, type 대신 input 을 사용한다.
input ReviewInput {
stars: Int!
commentary: String
}