GraphQL Serverを実装してみた
次のプロジェクトで GraphQL API を使おう!という話になったので、
GraphQL ServerをGolangで試しに作成してみました。
Githubにサンプル実装のソースをコミットしましたので、ご参考下さい。
tochukaso/graphql-server-sample
GraphQLとは
GraphQLとは、一言でいうと、
SQL感覚で書けるAPI である
graphql.orgによると、以下の通り
GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data.
GraphQL provides a complete and understandable description of the data in your API,
gives clients the power to ask for exactly what they need and nothing more,
makes it easier to evolve APIs over time, and enables powerful developer tools.
GraphQLは、APIのためのクエリー言語であり、また、そのクエリーを実行するためのランタイムです。
GraphQLはクライアントに正確で無駄のない要求を行えるようにし、APIの進化を簡単にします。
GraphQLを利用することで、具体的には以下の事ができるようになります。
- 取得したいデータをクライアント側から項目単位で指定出来る
- REST APIではレスポンスの項目はサーバー側に決められていたが、GraphQLはクライアント側が指定する
- 一度のクエリーでSQLのJOINの様に複数のテーブルのデータを取得する事ができる
- 単一のエンドポイントに出来る
- REST APIの場合、アクセス対象のエンティティ単位でエンドポイントが異なっていた
- リアルタイム通信(PUB/SUB)に対応している
GraphQL の QL は、Query Language の略で、問い合わせをする言語という意味です。
SQLは Structured Query Language の略で、GraphQLもSQL同様に問い合わせ言語となります。
クエリー(問い合わせ)として、以下の三種類が実行できます。
- query
- データの取得処理を行う
- mutation
- データの登録・更新・削除を行う
- subscription
- リアルタイム通信を行う
GraphQLは2015年にFacebookが仕様を公開し、2018年11月にGraphQL Foundationに移譲された。
GraphQL Serverの実装
Golangを使ってGraphQL Serverを実装しました。
- Go 1.16.5
- gqlgen
Githubにサンプル実装のソースをコミットしました。
tochukaso/graphql-server-sample
GraphQL Serverの作成は以下の手順で行います。
- スキーマファイルの作成
- スキーマファイルをベースにコードの自動生成
- resolver(各queryやmutation)の実装
スキーマファイルの作成
スキーマファイルには以下の要素があります。
- type
- データモデルの定義
- type Query
- 問い合わせよう関数の定義
- type Mutation
- 更新よう関数の定義
- type Subscription
- サブスクリプション(リアルタイム通信)よう関数の定義
- input
- Mutationよう関数の引数
※他にも interface,enum_や_union,extend 等があります。
商品マスター(product) と商品のバリエーション(SKU)を表す定義は以下のように表現できます。
schema.graphqls というファイル名で保存します。
type Product {
id: ID!
name: String!
price: Int!
code: String
detail: String
createdAt: String
updatedAt: String
deletedAt: String
skus: [Sku!]!
}
type Sku {
id: ID!
name: String!
stock: Int!
code: String
createdAt: String
updatedAt: String
deletedAt: String
product: Product!
}
type Query {
products: [Product!]!
product(id: ID!): Product!
skus: [Sku!]!
}
type Mutation {
createProduct(input: NewProduct!): Product!
updateProduct(input: EditProduct!): Product!
deleteProduct(productId: Int!): Int!
createSku(input: NewSku!): Sku!
}
type Subscription {
updateProduct(id: ID!): Product
}
input NewProduct {
name: String!
price: Int!
code: String
detail: String
}
input EditProduct {
id: Int!
name: String
price: Int
code: String
detail: String
}
input NewSku {
productId: Int!
name: String!
stock: Int!
code: String
}
スキーマファイルをベースにコードの自動生成
GraphQLのコードを、スキーマファイルから自動生成してくれるパッケージとして、gqlgenがあります。
gqlgen を使用することで、GraphQL用のコードを自動生成することが出来ます。
gqlgen-generate ./...をルートディレクトリー直下(_gqlgen.yml_が置いてあるディレクトリー)で実行します。
読み込み対象のスキーマファイルや、モデルデータの作成有無、カスタムスカラータイプの設定などを _gqlgen.yml_で設定できます。
スキーマを変更したい場合も同様に、schema.graphqls を変更後に、gqlgen-generate ./...を実行します。
schema.resolvers.go が作成、または変更されます。
resolver(各queryやmutation)の実装
schema.resolvers.go に新しく作成されるメソッドは、デフォルトは未実装( panic となっている)となっています。
こちらのメソッドを実装していきます。
商品を新しく登録するメソッドは以下のように実装します。
DBのORマッパーとして、 GORMを使用しています。
func (r *mutationResolver) CreateProduct(ctx context.Context, input model.NewProduct) (*model.Product, error) {
product := &model.Product{
Name: input.Name,
Price: input.Price,
Code: getString(input.Code, ""),
Detail: getString(input.Detail, ""),
}
result := db.GetDB().Create(&product)
if result.Error != nil {
log.Print("商品の登録に失敗しました")
} else {
log.Print("商品を登録しました")
}
return product, result.Error
}
商品情報を取得するメソッドの場合、以下のように実装します。
func (r *queryResolver) Product(ctx context.Context, id string) (*model.Product, error) {
var product *model.Product
db.GetDB().First(&product, id)
return product, nil
}
まとめ
今回、Golangを使ってGraphQL Serverを実装する方法を紹介しました。GraphQLの特徴や利便性に触れながら、具体的な手順としてスキーマファイルの作成、コード自動生成、そしてResolverの実装までをカバーしました。GraphQLは従来のREST APIと比べて柔軟性が高く、クライアントが必要なデータだけを取得できる点が大きな魅力です。
Golangとgqlgenを利用することで、GraphQL Serverの構築がシンプルかつ効率的に行えることが分かりました。本記事がGraphQLの理解や導入の一助となれば幸いです。