react-apollo の調査で GraphQL サーバーをさっくり実装する必要があり、 今 graphqool どうなってるんだっけ、と見に行ったら prisma が推奨されていました。
日本語情報がまったくなかったので、調査した結果をまとめておきます。
prisma とはなにか
- GraphQL の形をした ORM
- MySQL/Postgre への マイグレーションヘルパー付き
- モデル定義からインデックス自動生成
- CRUD自動生成
- graphqoolの次期版?
- PaaS に依存せず、自分でデプロイ可能なマイクロサービス
自分も最初よくわからなかったのですが、 使ってみた感じでは、 GraphQL の形をとった ORM + Migration Helper です。
$ npm i -g prisma
$ prisma init my-graphql-server # REPL で実装を選ぶ
$ cd my-grhapql-server
$ docker-compose up -d
$ prisma deploy
これで GraphQL サーバーが起動します。 docker の prismagraphql/prisma イメージが、prisma.yml ファイルを読んで起動します。
データモデル定義
先のチュートリアルの prisma deploy は datamodel.graphql をDBに向けて migration する操作です。
init ではこんなファイルが生成されています。
$ tree my-graphql-server/
├── datamodel.graphql
├── docker-compose.yml
└── prisma.yml
type User {
id: ID! @unique
name: String!
}
この User 定義に合わせて、 DB上のテーブルが生成され、GraphQL 上の CRUD 操作が実装されています。
動作確認のために、組み込みの GraphQL Playground を起動してみましょう。
prisma playground -p 9999
ブラウザが立ち上がるので、クエリを入力してみます。デフォルトだと 4466 に prisma サーバーが立ち上がっています。
mutation {
createUser(data: {
name: "Alice"
}) {
id
}
}
{
users {
id
name
}
}
users, createUser, deleteUser, updateUser
などが datamodel.graphql のモデル定義から自動生成されています。
リレーションを生成
次のようにモデルを追加して prisma deploy してみます。
type User {
id: ID! @unique
name: String!
articles: [Article!]!
}
type Article {
id: ID! @unique
title: String!
content: String!
author: User!
}
これを prisma deploy すると、 DB上に新しいテーブルを作って、User と article 属性の定義に従って、自動的にインデックスを張ってくれます。
こういうクエリが発行できるようになります
{
users {
id
name
articles {
title
content
}
}
}
実際のワークフロー
GraphQLはクライアント側のユースケースでクエリを作るため、CRUD実装のままデプロイしてしまうと、あらゆる操作がクライアントから可能になってしまいます。
なので、この GraphQL を利用する GraphQL サーバーをもう一つ立てます。
クライアントから見たときはこういう構成になります
Client <=> User GraphQL <=> Prisma GraphQL <=> MySQL
この User GraphQL は apollo で resolver を定義した GraphQL サーバーを書きます。詳しい実装方法は、 https://www.prisma.io/docs/tutorials/build-graphql-servers/development/build-a-graphql-server-with-prisma-ohdaiyoo6c を読んでください。
このとき、 prisma は GraphQL サーバーからみた GraphQL による CRUD 実装ということが出来ます。このときの apollo による GraphQL サーバーの resolver が次のようになります。
const resolvers = {
Query: {
posts: (_, args, context, info) => {
return context.prisma.query.articles(
{
where: {
OR: [
{ title_contains: args.searchString },
{ content_contains: args.searchString },
],
},
},
info,
)
},
},
//...
}
apolloのprismaプラグインによって context.prisma が定義され、 datamodel 定義によるクエリ操作が可能です。(これを詳しく覚えないといけないのがちょっと面倒ですね…)
graphqool を使う場合、 PaaS としての graphqool を使う必要がありました。 prisma は prisma cloud にデプロイしてつかうことも可能なのですが、 これは10req/10s の制限があります。
プロダクションで使うには、 prisma の docker image を k8s などでデプロイすることになると思います。結局自前のGraphQL サーバーをデプロイする必要があるので、マイクロサービス前提のアーキテクチャですね。
最後に
https://github.com/mizchi-sandbox/myjam で next.js + prisma で簡単なブログサービスを実装してみました。いわゆる JAM Stack です。
GraphQL は自分でサーバーを書くのが面倒くさかったのですが、prisma は面倒臭さを極力抑えて マイクロサービス前提で複雑さを抑えようというものです。
実際に使い込むと粗が出そうですが、パッと見筋は良さそうに見えます。
追記
日本語情報ない、と言いましたが、書き終わったあとに @takezoen さんの記事があることに気づきました