GraphQL 시작하기
What is GraphQL?
GraphQL은 React.js를 개발한 meta(전 facebook)에서 개발하였으며 기존의 REST API가 가진 단점을 극복하기 위해 개발되었다.
GraphQL은 QueryLanguage를 통해 연결되어 있는 데이터를 필요한 데이터만 골라 전송받을 수 있게 만들어준다.
또 GraphQL은 개발자가 단일 API 호출로 다양한 데이터 소스에서 데이터를 끌어오는 요청을 구성할 수 있도록 지원한다.
GraphQL의 쿼리는 직관적으로 구성되어 있다.
Content 스키마 중 contentId, contentTitle 그리고 comment 스키마 중 commentId, commentBody만을 담은 Array가 반환될 것이다.
//쿼리
{
content {
contentId
contentTitle
comments {
commentId
commentBody
}
}
}
//응답
{
"data": {
"content": {
"contentId": "ct1",
"contentTitle": "title",
"comments": [
{
"commentId": "comment1",
"commentBody": "comment"
}
]
}
}
}
GraphQL 쿼리 용어
- Fields
//Field
{
content {
contentId
}
}
위 쿼리에서 contentId가 Field이다.
- Arguments
//Arguments
{
content(id : 1) {
contentId
}
}
쿼리에 인자를 넣어 보낼 수도 있다. int 형 외에도 다양한 자료형과 사용자 정의형도 보낼 수 있다.
- Aliases
//쿼리
{
content1 : content(id : 1) {
contentId
}
content2 : content(id : 2) {
contentId
}
}
//응답
{
"data" : {
"content1" : {
"contentId" : "1"
},
"content2" : {
"contentId" : "2"
}
}
}
Aliases는 쿼리의 앞에 위치하여 사용된다. 위의 예시와 같이 인자만 다른 같은 쿼리를 보낼 때 Aliases를 사용하지 않는다면 응답에서 어느 것이 content 데이터가 될지 몰라 오류가 날 것이며 이를 해결하기 위해 Aliases를 사용한다.
- Fragments
//Fragments
{
content1 : content(id : 1) {
...fields
}
content2 : content(id : 2) {
...fields
}
fragment fields on Character {
contentId
contentTitle
}
}
Fragment는 쿼리에서 불필요한 반복을 줄이기 위해 사용된다. 공통부분은 Fragment로 따로 빼서 사용할 수 있다.
- Operation Name
query {
content : {
contentId
}
}
꼭 필요하지 않지만 쿼리의 목적을 위해 맨 앞에 명시할 수 있다. Operation Name에는 query, mutation, subscription이 있다.
- Variables
query getContents($contentId : Int) {
content(id : $contentId) : {
contentId
}
}
클라이언트 쪽에서 쿼리를 보낼 때 쿼리 내에 static하게 인자를 넣어 보내는 경우는 흔치 않기 때문에 변수를 사용한다.
서버 측 GraphQL
GraphQL에서도 SQL를 사용할 때 처럼 스키마를 작성해야 한다. 스키마는 *.graphqls 확장자 파일로 생성해야 한다. 그리고 classPath 내 어디에든 존재 가능하며 개수도 제한이 없지만 루트 Query와 루트 Mutation이 존재해야 한다.
// *.graphqls 파일
type Content {
contentId: ID!
contentTitle: String!
contentBody: String
comments: [Comment]
}
type Comment {
commentId: ID!
commentBody: String
}
// Root Query
type Query {
contentList: [Content]
}
extend type Query {
commentList: [Comment]
}
type Mutation {
writeContent(title: String!, body: String): Int
}
schema {
query: Query
mutation: Mutation
}
- type Content, Comment
DB에서 Content 테이블과 Comment 테이블을 만드는 것과 같은 역할
- Content, Comment : 오브젝트 타입
- contentId, commentId... : 필드
- (!) : 필수값
- [] : 배열 - type Query, Mutation
기본적으로 루트 Query와 루트 Mutation을 의미한다. 이것들을 단 하나씩만 존재해야 하며 이름은 아래의 schema를 이용해 변경할 수도 있다. - extend
스키마 파일에서 이름이 같은 오브젝트는 있을 수 없다. 하지만 파일 또는 오브젝트를 분리하고 싶을 수도 있기 때문에 exnted를 이용해 오브젝트를 확장 및 분리할 수 있다. 이외에도 여러 방식으로 사용된다. - schema
스키마 내의 루트 Query와 루트 Mutation, Subscription을 지정할 수 있다. 이것은 명시적인 표현으로서 작동하며 명시하지 않으면 스키마 파일 내의 "Query", "Mutation", "Subscription" 이름을 가진 오브젝트가 루트 오브젝트가 된다.