prisma - 最速 GraphQL Server実装

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
```

```:datamodel.graphql
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 してみます。

```:datamodel.graphql
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 さんの記事があることに気づきました

[GraphQLスキーマからCRUDを自動生成できるPrismaについて - たけぞう瀕死ブログ](http://takezoe.hatenablog.com/entry/2018/05/23/125752)