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

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

mutation

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

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

type Catalog

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

type Product

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

type Item

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

type VendorItem

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

type Mutation

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

input CreateCatalogInput

input CreateCatalogInput {
	product: Product!
}

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

Reference