GraphQLスキーマからCRUDを自動生成できるPrismaについて

Prismaは、様々なデータベースをバックエンドにGraphQLのスキーマからCRUDを行うためのエンドポイントを提供するプロキシとして動作するミドルウェアです。最近$4.5Mの資金調達をしてちょっとだけ話題になりました。

www.prisma.io

Prismaが提供するソフトウェアは現在オープンソースソフトウェアとしてGitHub上で公開されています。本体はScalaで書かれていますが、CLIはTypeScript(Node.js)で書かれているようです。Scalaのコードは関数型プログラミングを駆使したものではなく、比較的読みやすい部類だと思います。

github.com

触ってみる

GraphQLのエンドポイントを簡単に用意することができそうということで少し調べてみました。Webサイトにチュートリアルがあり、dockerを使って簡単に試すことができるようになっています。事前にnpmとdockerが利用できるようになっている必要があります。

まずはnpmでPrismaのCLIをインストールします。

$ npm install -g prisma

インストールしたCLIを使ってサンプルを生成します。既存のデータベースを使うか、dockerで新たなデータベースを作成するかを聞かれます。いずれにしろPrisma自体はdockerで起動するので既存のデータベースを使用する場合はdockerコンテナからアクセスできるようになっている必要があります。

$ prisma init hello-world

Webサイトには様々なデータストアを利用できるようになると書かれていますが、今のところ対応しているのはMySQLとPostgreSQLのみのようで、スケールさせる場合はデータベース側で頑張る(Prisma自体は横に並べればOK)ということのようです。現在はまだベータのようですが、既存のテーブルからGraphQLスキーマを生成するという機能も実装されているようです。

生成されたサンプルを見てみましょう。

$ cd hello-world
$ cat datamodel.graphql
type User {
  id: ID! @unique
  name: String!
}

ディレクトリ内にはこの他にもPrismaやデータベースをdockerで起動するためのdocker-compose.ymlや、Prismaの設定ファイルであるprisma.ymlが生成されています。

Prismaにデプロイして動作確認してみます。まずはdockerコンテナを起動します。

$ docker-compose up -d 

スキーマをデプロイします。するとデータベースに自動的に対応するテーブルが作成され、エンドポイントが利用可能になります。

$ prisma deploy

以下のコマンドでGraphQL PlaygroundというWebブラウザでスキーマを確認したりクエリを投げるためのコンソールを表示することができますので、ここで色々試してみるとよいと思います。クエリが間違ってると赤線が表示されたり、スキーマを確認できたりするのでなかなか便利です。

$ prisma playgroud 

f:id:takezoe:20180523121831p:plain

Prismaはスキーマのオートマイグレーションもサポートしています。先ほどのスキーマに以下のようにemailプロパティを追加してみます。

type User {
  id: ID! @unique
  name: String!
  email: String
}

これをprisma deployでデプロイすると以下のようにemailプロパティが追加されていることがわかります。プロパティの削除も可能ですが、すでにデータが入っている場合は警告が表示され、--forceオプションをつけてデプロイを実行する必要がありました.

f:id:takezoe:20180523122625p:plain

Prismaにはサーバーサイドサブスクリプションという機能があり、条件を指定してWebフックを登録しておくことができます。たとえば以下のような設定をprisma.ymlに入れておきます(host.docker.internalというのはdockerコンテナ内からホストにアクセスするためのホスト名ですので実際は呼び出したいホストに置き換えてください)。

subscriptions:
  userChangedName:
    webhook:
      url: http://host.docker.internal:8080/test
    query: |
      subscription {
        user(where: {
          mutation_in: [UPDATED]
        }) {
          node {
            id
            name
          }
        }
      }

Userが変更されると指定したURLに以下のような内容のPOSTリクエストが送信されます。

{"data":{"user":{"node":{"id":"cjhij3xjs000h09748tmsaku4","name":"Alice"}}}}

設定ファイルに1つずつ記述しないといけないので数が増えるとちょっと大変そうですが、この機能を使えば簡単な外部連携などはサーバサイドで完結させることができそうです。

感想的なもの

Prismaを使うとシンプルなCRUD用のGraphQL APIを簡単に作成することができるのですが、実際のシステムではそれだけでは済まないケースがほとんどなのではないかと思います。このような場合、Prismaとクライアントの間にもう1層BFF的なGraphQLサーバを作成することが推奨されているようです。ただ、PrismaをラップするGraphQLサーバを自前で作るのであればバックエンドをPrismaでGraphQL化する意味があまりないような気がするんですよね…。SQLを直接書くよりBFFを書きやすいというのはあるのかもしれませんが…。

また、Prismaはクラウドサービスとして利用可能なPrisma Cloudというサービスも提供しています。が、こちらはデータベースは自前で用意する必要があり、Prisma Cloudからインターネット経由でデータベースに接続することが想定されているようです。前述のようにPrismaの手前に別途GraphQLサーバを立てるとすると、手元にあるデータベースにアクセスするためにインターネット経由で一往復しないといけないという状況が発生します。さすがにこれはちょっと厳しいのではという気がします。

機能面にしろ運用面にしろ面倒な部分を外部に丸投げしてる感があり、個人的にはクライアントアプリケーション向けのGraphQL API開発に使ってもあまり楽にならなそうな印象を受けました。いまのところPrismaはGraphQL DB的なものを志向しているように見えるので、そういうものだと割り切って使う必要がありそうです。