GraphQL 자체는 단순 문자열이다. (JSON이 key:value 구조를 가지고 있지만 근본적으로는 그냥 문자열인 것처럼!)
기본
POST 요청의 data 부분에 GraphQL 문자열을 넣어 end point로 전송한다. 그러면 GraphQL 쿼리에서 요청한 데이터 구성과 같은 구성의 JSON 객체가 반환된다. 만약 GraphQL 실행 중 오류가 있다면, 반환된 JSON 객체의 내부에 error 필드가 입력되어 반환된다.
1. 루트 타입
루트 타입은 해당 쿼리의 작업 종류를 의미한다. (조회/수정) - query : 조회 - mutation : 입력/삭제/수정 - subscription : 구독형 조회(조회하고 있는 데이터에 수정사항이 있을 때, 실시간 반영을 한다). websocket 방식으로 소통한다.
2. 쿼리 인자(query arguments)
Sql에서 사용하던 where절이라고 생각하면 편함. Primary key 역할을 하는 id 또는 특정 type에 대한 값 비교를 통해 원하는 조건의 데이터를 조작할 수 있음
3. 쿼리 필드(query field)
스칼라 타입(scalar type) - 개발 언어에서 사용하는 변수 선언 타입인 primitive type 과 유사하다고 보면 된다. Int, Float, String, Boolean, 그리고고유 식별자(ID)로 되어있다. 객체 타입(object type) - 스키마에 정의한 필드를 그룹으로 묶어둔 JSON 객체 타입. 객체 지향 언어에서 자주 사용하는 객체형 변수라고 생각하면 될 것 같다.
4. 프래그먼트(fragment)
중복되는 필드들의 집합이 있을 때, 프래그먼트로 묶어 중복을 줄일 수 있다. (안드로이드에서의 프래그먼트와 같은 목적을 가지고 있는 것 같긴 하지만 오히려 c언어의 구조체(struct)가 더 어울리는 말이 아니었을까 생각된다.)
*정리하다가 보니 객체 타입과 프래그먼트의 정의가 헷갈린다. 객체 타입은 여러 타입들의 객체를 묶어놓은 '데이터 형'
이지만, 프래그먼트는 쿼리의 중복 구간을 줄이기 위한 표기법이라고 생각하는 것이 맞는 것 같다.
5. 유니언 타입(Union type)
여러 개의 타입들을 한 번에 리스트에 담아 반환하기 위한 타입이다.
예를 들어 A라는 데이터 하위 목록을 조회할 때, 여러 개의 타입을 하나의 타입 아래에 받을 수 있다.
A type {
a type,
b type
}
의 구조로 조회를 할 때, a와 b는 내부 필드가 다른 객체 타입이다.
하지만 사용자가 A type 하나로 a와 b 두 형의 데이터를 보고 싶을 때, 유니언 타입으로 서로 다른 두 가지 타입의 데이터 목록을 붙여서 조회한다.
설명이 복잡해 보이는데, 사실 DB sql의 union과 같다. 차이점이라면 두 데이터 형을 하나의 목록으로 합칠 때, alias 및 column의 구조를 맞춰줄 필요가 없다는 것 정도다.
생산성 및 성능 이슈로 sql에서는 가급적 피해야하는 문법인데, GraphQL에서는 어떨지 잘 모르겠다. 계속 보다보면 나오겠지?
6. 인터페이스(interface)
개발 언어에서 많이 사용하는 그 인터페이스와 같은 목적/기능이다. 추상 타입이고 유사한 객체 타입을 만들 때 필요한 필드 목록을 모아둔 것이다. 특정 인터페이스를 바탕으로 만들어진 객체 타입은 반드시 해당 필드들을 보유하고 있어야 한다.
7. 인트로스펙션(introspection : 단어 뜻은 내성, 자아성찰)
API 스키마의 세부 사항을 알려주는 기능이다.
api에서 사용할 수 있는 타입(루트/스칼라/객체) 혹은 특정 타입을 골라서 세부 사항을 조회할 수 있다.
프래그먼트를 사용한 중복 코드 방지가 가능하다.
8. 추상 구문 트리(abstract syntax tree : AST)
API로 쿼리를 보낼 때, 쿼리 문자열은 추상 구문 트리로 파싱된 후 유효성 검사를 거친다.
계층 구조의 객체로 쿼리를 표현하는데 사용된다. (쿼리 문자열 -> 트리)
GraphQL은 AST를 횡단하면서(한 바퀴 돌면서) 현재 api스키마와 비교해 유효성 검사를 진행한다. 구문에 오류가 없고 스키마에 필드와 타입이 다 들어있다면 데이터 조회 후 결과 반환을 해주고, 아니면 특정 에러를 반환한다.
* 여러 문법/구조가 있....는데 이거 다 쓸지 의문이다. 1,2,3,4번 정도는 쓸 것 같지만 나머지는 안쓰게 될 삘이다.
- RESTful API와 같은 선상이라고 보는 것이 이해하기 좋다. (정확히는 RESTful의 하위다. POST 통신의 Data 구간에 요청 쿼리를 전달한다.) - *클라이언트와 서버 간의 통신 명세다. - 페이스북에서 내부적 성능 개선을 목적으로 만들었다. - 선언형 데이터 페칭 언어(Declarative Data Fetching Language)다. 어떤 데이터가 필요한지에 중점을 두고, 어떻게 가져올지에 대한 것은 신경쓰지 않는다.
2. GraphQL이 생긴 이유
RESTful API의 단점을 해결하기 위해 만들어졌다. 단점 1. 오버페칭(Overfetching) - 클라이언트가 필요로 하는 데이터보다 많은 데이터를 반환 받는 상황을 말한다. 요구사항의 추가 및 여러 페이지에서 1개의 api를 사용하는 경우, RESTful API 서버에서는 필연적으로 발생한다.
단점 2. 언더페칭(Underfetching) - 1개의 웹 페이지에서 필요로 하는 데이터를 준비하기 위해, n개의 api를 호출해야 하는 상황을 말한다.
단점 3. RESTful API 서버 엔드포인트 관리 (api 개수 = uri 개수) - 서버 운영 및 유지 보수 시에 변경/추가 기능이 생기면 api 라우팅을 새로 만들어서 사용하는 경우가 많다. (유사 기능이라고 해도 개발/운영 편의성을 위해 새로 만들어 사용하는 경우가 생각보다 많다.)
위 3가지 단점을 보완하기 위해 1. GraphQL로 필요로 하는 파라미터만을 질의하여, 질의한 데이터 구조 그대로 반환 받는다. 2. 중첩 GraphQL을 작성하여, api를 1회 호출하여 필요로 하는 데이터를 받을 수 있도록 한다. 3. GraphQL 서버는 서버 엔드포인트(라우팅 uri)를 하나로 설계된다. (엔드포인트를 기준으로 호출하지 않기 때문에 가능하다.)
*3번의 경우, RESTful API 서버에서는 [도메인 + endpoint]를 기준으로 호출하지만 Graphql은 쿼리 내부에 어떤 데이터를 불러올지를 담기 때문에 uri를 통한 endpoint를 따로 만들어줄 필요가 없다(Graphql로 데이터를 호출하면 바로 이해가 가는 부분이었다). -> 서버 개발의 생산성면에서 작업을 줄일 수 있다. Controller와 Service를 관리하던 서버 개발자의 작업 중 Controller의 작업을 줄일 수 있게 되었다. (근데 마냥 그렇지만도 않다. 결국 호출 쿼리 이름을 지어줘야 한다.)
* "GraphQL이 RESTful을 망하게하는 것이 아니라 RESTful의 약점을 보완하기 위한 수단"이라고 보는 것이 좋다고 한다. 처음부터 GraphQL을 기반으로 개발한 경우가 아닌, RESTful api 서버에 GraphQL을 연동한 곳도 많다고 서술되어 있다.
* RESTful과 GraphQL 2중 구성으로 만들 수도 있다. 서버 로직의 핵심이 되는 서비스 코드는 동일하기에 접근 방식만 허용해주면 된다.