🍋

Graph QL

GraphQL( = Graph + Query Language)는 RESTful API와 같이 CRUD를 지원한다. RESTful API는 URL을 통해 resources를 나타내고 method를 통해 CRUD를 나타낸 반면에 graphQL은 쿼리를 작성하여 나타낸다. 따라서 RESTful API에서는 자원(resources)마다 url이 존재했지만, graphQL API에서는 단 하나의 endpoint(/graphql)만 존재하고 자원마다 쿼리가 달라지는 형태이다.

GraphQL에서는 자원을 읽고 변경하는데 두 가지 형태로 제공한다. 읽기 작업은 'query' 나머지 변경하는 작업은 'mutation'으로 제공한다. 아래는 catalog를 읽고 생성하는 작업에 대한 예제이다.

query

123456789101112131415161718
query ReadCatalog($catalogId: ID!) {
catalog(id: $catalogId) {
id
product {
productId
name
items {
itemId
name
vendorItems {
vendorItemId
vendorId
}
}
}
version
}
}

mutation

12345678
mutation CreateCatalog($product: product!) {
createCatalog(input: {
product: $product
}) {
id
version
}
}

위의 예처럼 카탈로그의 데이터를 읽을 때, 필요한 데이터에 대해 명시를 하면 해당 데이터를 응답 값으로 받을 수 있다. 생성할 때에도 input으로 생성할 때 필요한 데이터와 응답 값을 명시해주면 서버는 카탈로그를 생성하고 응답을 한다.

서버는 위의 요청을 처리하기 위해 어떠한 쿼리(query + mutation)이 들어오는지, 또 들어오는 데이터가 무엇인지 알아야 한다. 이를 지원하기 위해 schema를 작성한다. Schema에서 정의할 수 있는 것은type, input이다. Schema를 구성할 때, type을 통해 새로운 타입(오브젝트)를 구성하거나 이미 정의되어 있는 타입(스칼라: Int, String, ID 등)을 사용해서 각 필드가 어떠한 타입인지 명시할 수 있다. 또한 !을 사용하여 nullable에 대한 여부도 나타낼 수 있다.

type Query

123
type Query {
catalog(id: ID!): Catalog!
}

type Catalog

12345
type Catalog {
id: ID!
product: Product!
version: Int!
}

type Product

123456
type Product {
productId: ID!
name: String
# ...
items: [Item!]
}

type Item

123456
type Item {
itemId: ID!
name: String
# ...
vendorItems: [VendorItem!]
}

type VendorItem

12345
type VendorItem {
vendorItemId: ID!
vendorId: String!
# ...
}

type Mutation

123
type Mutation {
createCatalog(input: CreateCatalogInput): Catalog!
}

input CreateCatalogInput

123
input CreateCatalogInput {
product: Product!
}

RESTful API 보다 더 나은 점은 원하는 데이터를 가져온다는 점이다. 위의 예에서 Product와 Item에 대한 정보가 필요하다면 product에 대한 데이터를 요청한 후, item에 대한 데이터를 요청을 한다. 두 번의 요청이 있는 반면 graphQL에서는 한번의 요청으로 데이터를 가져올 수 있다.

Reference