Mojolicious でGraphQLを触ってみた。
Mojoliciousで、GraphQLの簡易ブログアプリを書いてみた。
お試し実装ではあるけれど、アプリケーションロジックの書きやすさやDataLoaderを使ったN+1対策なんかも書いてみている。リポジトリはこちら。ここでは、どんな実装にしたのか備忘のため書き留める。
まず、GraphQLのスキーマはこちら。ブログのエントリーとそのエントリーに対するコメントが複数あるようなスキーマ。Query#entries
で、エントリーの一覧なんかが取得できると。
type Query {
entries: [Entry!]
}
type Entry {
id: ID!
title: String!
body: String!
comments: [EntryComment!]
}
type EntryComment {
id: ID!
body: String!
}
アーキテクチャはこんな具合。
% tree lib/Blog/GraphQL
lib/Blog/GraphQL
├── Query.pm ----- クエリのリゾルバ。QueryResolverの実装を集約する。
├── QueryResolver ---- クエリのリゾルバの各実装を格納庫
│ └── Entries.pm ----- entriesのリゾルバ
├── QueryResolverRole.pm ---- スキーマ情報を元に、リゾルバに対して制約やシュガーを提供
├── Schema.pm --- GraphQLのスキーマ
├── Type
│ ├── Entry.pm --- エントリーのtype object。各フィールドのリゾルバを書く。
│ └── EntryComment.pm --- エントリーコメントのtype object。
└── TypeObject.pm --- スキーマ情報を元に、type objectに対して制約やシュガーを提供
実際にentries クエリの実装を書く場合は、リゾルバのQueryResolver::Entriesとタイプオブジェクトの2つを書くだけで良いように設計している。
まず、リゾルバのQueryResolver::Entriesは、次の通り、データをfetchする処理を書いている。
人気エントリーであったり、最近のエントリーだったり、ユーザに価値提供する肝になると思う。
package Blog::GraphQL::QueryResolver::Entries;
use v5.36;
use Moo;
with 'Blog::GraphQL::QueryResolverRole';
use Blog::Unit::Entry::EntryFetcher;
sub main($self, $args, $context, $info) {
my $fetcher = Blog::Unit::Entry::EntryFetcher->entity;
my $entries = $fetcher->select_all({});
return $entries;
}
1;
次に、タイプオブジェクトは、次のような具合にフィールドごとにメソッドを定義すれば良い。
commentsだけは、N+1にならないようにDataLoaderを経由している。
package Blog::GraphQL::Type::Entry;
use v5.36;
use Moo;
extends qw(Blog::GraphQL::TypeObject);
use Blog::Unit::Entry::EntryCommentFetcher;
sub id($self, @) {
$self->object->id;
}
sub title($self, @) {
$self->object->title;
}
sub body($self, @) {
$self->object->body;
}
sub comments($self, $args, $context, @) {
my $loader = $self->data_loader($context, Blog::Unit::Entry::EntryCommentFetcher->can('batch_comments'));
$loader->load($self->object->id);
}
1;
このアーキテクチャの内部実装の肝は、スキーマ情報を元にした制約。
例えば、entriesクエリなら、Blog::GraphQL::QueryResolver::Entries
という命名でリゾルバするように制約を課している。
スキーマを元にしたコードの自動生成にはしていない。
Mojolicious x GraphQLのベストプラクティスがわかっていないから、吐き出すべきものがわかっていないのと、graphql-ruby
の影響も受けて、コードを書く形にしているのもある。(アレはGraphQLスキーマも書いていて、こちらはスキーマはそうでないので、差分は多分にあるんだけど。)処理を挟んだり、柔軟にやる余地がある気がして、これはこれで良い気がしている。
最後に。
おれおれでフレームワーク書くの楽しいですね。習作の目的は果たせたかなと。
graphql-perlは、自由度が高い一方、敷居が高いとも感じるので、
もしかしたらフレームワークのニーズがあるかも?どうなんだろ。
BlogといったアプリケーションやMojoliciousに依存せず、書いてみたいですね。