GraphQL이란 ?
- API 사용을 위한 Query 언어입니다.
- 데이터에 대해 정의한 Type 시스템을 사용하여 Query를 실행하기 위한 server-side runtime 입니다.
- 특정 데이터베이스와 스토리지 엔진에 연결되지 않고 코드와 데이터로 지원됩니다
왜 server-side runtime일까??
GraphQL Server가 데이터를 Client Application이 query 할 수있는 GraphQL API로 노출시키기 때문입니다.
GraphQL 내부 과정
함수 생성
type Query {
me: User
}
type User {
id: ID
name: String
}
- GraphQL 서비스는 type과 field를 정의하고 각 type의 field에 해당하는 함수를 제공하여 생성하게 됩니다.
function Query_me(request) {
return request.auth.user;
}
function User_name(user) {
return user.getName();
}
function User_id(user) {
return user.getId();
}
- 이처럼 타입에 따른 필드마다 함수를 제공하여 생성하게 됩니다.
검증과 실행
{
me {
name
}
}
- GraphQL 서비스가 실행된 이후에는 GraphQL 쿼리들을 받아 검증과 실행을 진행합니다.
- GraphQL 서비스는 먼저 쿼리가 정의된 타입과 필드를만을 참조하는지 확인합니다.
- 이후에 제공된 함수를 실행하여 결과를 생성합니다.
{
"me": {
"name": "Luke Skywalker"
}
}
Query & Mutation
Field
{
hero {
name
}
}
- 위 예시를 통해 간단히 얘기하자면 GraphQL에서 요청되는 객체의 필드값을 말합니다.
- 이 요청에 대한 결과값 또한 같은 필드를 갖고 있는 json형식으로 반환됩니다.
{
hero {
name
}
friends {
name
}
}
- 필드는 객체를 참조할 수 있습니다.
- 위 예제에서 friends는 필드지만 필드를 갖고있는 객체를 참조합니다.
Arguments
{
human(id: "1000") {
name
height(unit: FOOT)
}
}
- GraphQL에서는 모든 Field와 중첩 된 Object 에서 인수 집합을 넣어줄 수 있습니다.
- 때문에 GraphQL을 multiple API fetch 할 수 있게 만들어 줍니다.
Mutations
mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
createReview(episode: $ep, review: $review) {
stars
commentary
}
}
- GraphQL의 대부분은 data fetching에 집중하고 있지만, Server-Side data 또한 수정할 수 있는 방법이 필요합니다.
- 이외에도 쿼리와 다른 차이점은 Query는 병렬적으로 실행되지만 mutation은 연속적으로 실행된다는 것 입니다.
Type System & Execution
Type System
GraphQL 쿼리 언어는 기본적으로 Object의 Field를 선택하는 것을 말합니다.
{
hero {
name
appearsIn
}
}
위 예제를 통해 설명해보겠습니다.
1. 특별한 'root' Object 부터 시작합니다.
2. hero
field를 선택합니다.
3. hero
가 반환 한 객체의 경우 name
, appearsIn
field를 반환합니다.
- 모든 GraphQL Service는 해당 서비스에서 Query할 수 있는 data set을 설명할 수 있는type set을 정의합니다.
- 때문에 쿼리가 들어오면 해당
schema
에 대해 유효성이 검사되고 실행됩니다.
Execution
- GraphQL의 Field는 다음 Type을 반환하는 함수 또는 메소드 입니다.
- 각 type의 각 field는 GraphQL Server가 제공하는 resolver라는 함수로 제공됩니다.
- Field가 실행되면 해당하는 resolver가 실행되어 다음 값을 생성합니다.
- 만약 Field가 String, Number 와 같은 scalar 값을 생성하면 실행이 완료된 것입니다.
- 하지만 Field가 scalar 값에 도달하지 못하고 다른 Field값에 적용되는 Object Value를 생성한다면 scalar 값에 도달할 때 까지 Execution 과정은 계속 진행됩니다.
- 이 과정은 Trivial resolvers 처럼 진행된다.
{
human{
name
}
}
> Trivial resolvers
{
human{
name(obj, args, context, info) {
return obj.name
}
}
}
- 이 과정에서 name 함수는 이전 Field가 반환한
new Human
객체를 obj를 통해서 받습니다.
- field와 같은 이름의 프로퍼티가 obj에 존재 하고 반환할 것이고, 이러한 간단한 리졸버는 생략하게 됩니다.