GraphQL은 Graph + Query Language의 약자로 페이스북이 2012년에 개발하여 2015년에 공개 발표한 API를 위한 쿼리 언어이다. 마인드맵과 유사한 형태의 그래프 구조로 실제 현실 세계의 현상과 가깝게 모델링할 수 있다.
상승중인 GraphQL 인기 (출처: 2020.stateofjs)
SQL이 데이터베이스에 저장된 데이터를 효율적으로 가져오는 것이라면, GraphQL은 웹 클라이언트가 데이터를 서버로부터 효율적으로 가져오는 것이 목적이다. 주체가 클라이언트라는 점이 매우 큰 특징을 가진다. GraphQL 서버는 여러 언어로 구현되어 있는데, 그 중 javascript로 를 참고해 실습해 볼 예정이다.
GraphQL은 객체의 특정 필드를 요청한다. 위 예시처럼 요청과 응답 항목이 정확히 같은 구조로 이루어져 있음을 알 수 있다(중요). GraphQL은 관련 개체 및 해당 필드를 순회할 수 있으므로 REST API에서 여러 왕복이 필요한 데이터들도 한번의 요청으로 그림2와 같이 관련 데이터를 가져올 수 있다.
REST API에서 요청시 ?id=1000
쿼리나 /1000(/:id)
파라미터로 전달되었던 전달인자를 GraphQL에서는 모든 필드와 중첩된 객체에서도 전달인자를 적용하여 원하는 데이터만 받아 올 수 있다.
다른 전달인자를 가진 같은 필드의 데이터를 요청한 경우, 필드명이 중복되어 별칭이 필요하다. 별칭을 사용하면 그림2와 같이 필드 결과를 원하는 이름으로 바꿀 수 있다.
위 예시에서는 operation name을 생략했지만 실제 앱에서는 명시적으로 사용을 권하고 있다. 쿼리 이름은 타입 + 이름
으로 작성하는데, 그림은 operation type으로 query
퀴워드와 함께 쿼리명을 HeroNameAndFriends
로 작성한 것이다.
query
는 type 중 하나이며, 외에도 mutation
, subscription
, describes
등이 있다. 명시적인 역할 뿐만 아니라, 문제가 발생했을 때 디버깅 및 서버 측 로깅에 매우 유용하다고 한다.
대부분 어플리케이션에서 필드에 대한 전달인자는 검색, 필터 등으로 동적인 경우가 많다. 이때 변수를 사용할 수 있는데, 그림에 나온 예시처럼 $
는 접두어로 변수를 정의할 수 있다. 그림에서 ($episode: Episode)
에 해당하는 부분은 변수를 선언하는 것으로 $변수명:
다음에 따라오는 것은 타입이다.
($episode: Episode = JEDI)
처럼 기본값을 정할 수 있다. 당연하지만 변수가 전달되면 기본값은 무시된다. 변수를 정의할 때 필수 조건일 경우 ($episode: Episode!)
처럼 !
를 함께 작성한다.
그리고 JSON(일반적으로)으로 {"episode": "JEDI"}
과 같이 전달한다.
🛑 실습에서 주의! 생각보다 위 부분이 실습하면서 가장 어려웠던 부분이었는데,
괄호의 늪에 빠져syntax 에러를 많이 만났다.
여기까지 이미지는 모두 GraphQL의 learn queries 레퍼런스에서 가져온 것인데, 코드가 잘려서 링크를 남겨둔다. (앞부분 mutation
키워드만 참고!)
GraphQL은 조회하는 것에 중점을 두지만 데이터에 수정 요청을 보내직도 한다. query 퀴워드 대신 mutation
을 넣어 수정할 수 있다. 마치 REST API의 PUT
이나 PATCH
처럼.
GraphQL에서 필드를 선택할 때, 반환할 내용을 예측할 수 있지만, 정확하게 어떤 종류의 개체를 선택하고 받을 수 있는지 쿼리할 수 있는 가능한 데이터 집합을 설명하는 스키마가 필요하다. 스키마의 가장 기본적인 구성 요소는 서비스에서 가져올 수 있는 객체의 종류, 그리고 포함하는 필드를 나타내는 객체 유형이다. 쿼리가 들어올 때, 해당 스키마에 대한 유효성 검사가 후, 실행된다.
GraphQL 쿼리문 파싱은 대부분 GraphQL 라이브러리에서 처리하지만 데이터를 가져오는 과정은 resolver(이하 리졸버)가 한다. 리졸버는 요청에 대한 응답을 결정해주는 함수로 각각의 필드마다 함수가 하나씩 존재한다고 이해하면 된다. 이 함수는 타입을 반환하는데, 필드가 원시값인 경우 실행이 종료되며 리졸버 호출이 일어나지 않는다.