33
28

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

gqlgenのチュートリアルを試しました

Last updated at Posted at 2019-07-03

はじめに

初めまして、k.s.ロジャースの西谷です。

直近では、iOS, Android用のREST APIを開発しております。
このときに、画面描画用データ取得APIが350kb程のレスポンスを返すことがあり、結果としてアプリの描画速度に影響を与えました。
原因はレスポンスのネストしたEntityサイズで、運用当初はデータ量が少ないため問題はありませんでしたが、
運用しているうちにデータが増加することでEntityサイズが膨れ上がりました。

このときの対応としては、レスポンスから不要な内容を削除し、350kbから20kbまで減らすことで正常化できました。
しかし、今回は偶然不要データでしたが本来は返すべき内容ですので、方針として特例を多く作りたくない気持ちがありました。

レスポンスサイズ レスポンス速度 アプリの画面表示までの時間
全データを返す 350kb 9.5秒 15~20秒
必要データだけ返す 20kb 2.5秒 5秒

そこで、各画面・機能にとって必要なデータだけを柔軟に取得できるGraphQLについて調査しました。
本来GraphQLで処理速度が速くなるわけではありませんが、上記の場合は不要Entityを取得しないため、サーバ側の処理速度改善が期待できると考えています。

間違い・助言等があればコメントにてお知らせいただけたらと思います。

なぜgqlgenなのか

まず、Golangで開発したい理由があります。
弊社ではGolangのボイラーテンプレート(REST, gRPC)を開発しており、GraphQLを採用するとなった場合はGolangで実装する可能性が高いです。

golangで実装可能なフレームワークはこちらを参考にさせて頂きました。
弊社ではiOSやAndroidチームと連携して開発を進めることが多いため、スキーマ駆動かつドキュメントが豊富なgqlgenを選択しました。

環境構築

公式のチュートリアルに従って進めます。

まずプロジェクトの作成を行います。

mkdir gqlgen-todos
cd gqlgen-todos
go mod init github.com/[username]/gqlgen-todos

スキーマファイルを作成します。

schema.graphql
# Todoのデータ保持
type Todo {
  id: ID!
  text: String!
  done: Boolean!
  user: User!
}

# Userのデータ保持
type User {
  id: ID!
  name: String!
}

# リクエストの定義(Todo作成)
input NewTodo {
  text: String!
  userId: String!
}

# データ取得APIの定義
type Query {
  todos: [Todo!]!
}

# データ変更APIの定義
type Mutation {
  createTodo(input: NewTodo!): Todo!
}

データ取得関連のAPIはQueryに、新規作成・更新・削除はMutationに定義することになります。

プロジェクトの雛形作成

スキーマファイル作成後にgo run github.com/99designs/gqlgen initで雛形を生成できます。

.
├── generated.go # gqlgenの生成ファイル(基本的に触らない)
├── go.mod 
├── go.sum
├── gqlgen.yml # 設定ファイル
├── models_gen.go # スキーマから生成されたモデル
├── resolver.go # 処理の実装をここに書く
├── schema.graphql
└── server
    └── server.go

サーバ側の実装

Todoモデルの定義

Todoのモデルを新規定義します。
models_gen.goで自動生成されたモデルはUserも含まれています。
しかし、リクエストでユーザデータを指定されたときのみ、データ取得するようにしたいためtodoを再定義しています。

todo.go
package gqlgen_todos

type Todo struct {
	ID     string
	Text   string
	Done   bool
	UserID string
}

gqlgen.ymlに新規作成したtodoの内容を追加します。

gqlgen.yml
schema:
- schema.graphql
exec:
  filename: generated.go
model:
  filename: models_gen.go
resolver:
  filename: resolver.go
  type: Resolver
# 追加
models:
  Todo:
    model: github.com/[username]/gqlgen-todos.Todo

再ビルドします。

go run github.com/99designs/gqlgen

resolversの実装

現在の仕様でgqlgenを実行しても、すでに存在するresolver.goを変更出来ないようです。(対応予定)
ですので、一度resolver.go削除して再生成します。

rm resolver.go
go run github.com/99designs/gqlgen

これでresolver.goが最新になり、not implementedのメソッドを実装して完了です!

resolver.go
package gqlgen_todos

import (
	context "context"
	"fmt"
	"math/rand"
)
// 追加
type Resolver struct {
	todos []*Todo
}

func (r *Resolver) Mutation() MutationResolver {
	return &mutationResolver{r}
}
func (r *Resolver) Query() QueryResolver {
	return &queryResolver{r}
}
func (r *Resolver) Todo() TodoResolver {
	return &todoResolver{r}
}

type mutationResolver struct{ *Resolver }

func (r *mutationResolver) CreateTodo(ctx context.Context, input NewTodo) (*Todo, error) {
	// 追加
	todo := &Todo{
		Text:   input.Text,
		ID:     fmt.Sprintf("T%d", rand.Int()),
		UserID: input.UserID,
	}
	r.todos = append(r.todos, todo)
	return todo, nil
}

type queryResolver struct{ *Resolver }

func (r *queryResolver) Todos(ctx context.Context) ([]Todo, error) {
	// 追加
	return r.todos, nil
}

type todoResolver struct{ *Resolver }

func (r *todoResolver) User(ctx context.Context, obj *Todo) (*User, error) {
	// 追加
	return &User{ID: obj.UserID, Name: "user " + obj.UserID}, nil
}

実行

go run server/server.goでモックサーバが起動してhttp://localhost:8080/からテストできます。

後は次のようにTodo追加と一覧取得ができます。

スクリーンショット 2019-06-27 4.40.36.png スクリーンショット 2019-06-27 4.40.53.png

おわりに

今回はgqlgen公式のチュートリアルを試してみました。
現在はシンプルですが、実用にあたっては対応すべき課題が多々あると思います。
今後も時間を見つけて調査を進めたいと思います。

Wantedlyでもブログ投稿してます

Techブログに加えて会社ブログなどもやっているので、気になった方はぜひ覗いてみてください。
https://www.wantedly.com/companies/ks-rogers

33
28
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
33
28

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?