Node.js＆GraphQL part3 ~ Prismaセットアップ ~

# 前提
完全な自分用メモ。OSはWindows10。DBはPostgreSQL。
Nodejsとはまだつなげない。

# Prisma
サーバーとデータベースをつなぐGraphQL ORM (Object-relational mapping)。
Native driverもあるけどより高機能なのでPrismaを使う（MigrationとかValidationとか便利）。
データベースをラップしてGraphQL APIとして露出させるイメージで、どんなデータベースに対しても使用できる。
他のORM（SequelizerとかMongoose）を使用してもいいけど、上記の理由で柔軟に使えるのでもうPrisma使えばいいじゃんって感じ。
Client - Server 間と Server - DB 間をGraphQLで統一できるので、サーバーの役割としての厚みが一気に薄くなる。クライアントのGraphQLクエリをそのままPrismaにパスして、返ってきたデータをそのままクライアントにパスするだけみたいな感じ（Authはする必要あるけど）。

# Prisma セットアップ
### Heroku PostgreSQL
1. HerokuにログインしたらCreate new app で特に設定を変えずに作成
2. 作成したアプリのページへ遷移してOverviewタブへ移動。Installed add-ons の項目から Configure Add-ons を選択。
3. Add-ons の 検索フォームで「heroku postgresql」を検索して選択。
4. Hobby Dev - Free の無料プランをProvisionしてDBを作成する。

### PostgreSQL GUI (pgAdmin)
1. https://www.pgadmin.org/download/ で最新のpgAdminをダウンロード（xxx.exeファイルをダウンロード）
2. exeファイルを実行してインストール(全部デフォルト)
3. pgAdminを実行するとGUIがブラウザのタブで開く
4. GUI上でAdd New Serverを選択して、適当に名前をつけたらConnectionタブに移動。
5. HerokuのDBページから「Database Credentials」の項目を選択して、そこのHost項目をコピー⇒ConnectionタブのHost name/addressに貼り付け
6. PortはHerokuとデフォルトが同じなので変更なし
7. Herokuの「Database Credentials」からDatabase/User/Passwordをコピー⇒それぞれ、ConnectionタブのMaintenance database/Username/Password に貼り付け
8. まぁSave passwordにチェックでも入れとく
9. 入力し終えたら「Save」をクリックする⇒自動で接続テストが始まる
10. 接続できたら Servers ⇒ 適当につけたサーバー名 ⇒ Databases の順に開いていく。自分の場合 Databaseが6000くらいあったので、Ctr+FでDatabase CredentialsのDatabaseを検索して見つけた。

### Docker
1. https://www.docker.com/get-started から Docker Toolbox をダウンロード
2. exeファイルを実行してインストール(全部デフォルト)
3. Docker QuickStart Terminalを開くと自動で初期化処理が始まる

### Prisma
1. npm install -g prisma でPrismaをグローバルインストール
2. prisma -v でインストール確認
3. プロジェクトフォルダで prisma init [プロジェクト名] を実行
4. プロンプトに対して以下のように答える。
5. Use Existing Database ⇒ PostgreSQL ⇒ No (Does your database contain existing data? に対して) 
6. Set up a new Prisma server or deploy to an existing server? ⇒ Use existing database
7. What kind of database do you want to deploy to? ⇒ PostgreSQL
8. Does your database contain existing data? ⇒ No
9. Enter database host ⇒ Heroku Database Credentials の Host
10. Enter database port ⇒ 5432
11. Enter database user ⇒ Heroku Database Credentials の User
12. Enter database password ⇒ Heroku Database Credentials の Password
13. Enter database name (the database includes the schema) ⇒ Heroku Database Credentials のDatabase
14. Use SSL? ⇒ Yes
15. Select the programming language for the generated Prisma client ⇒ Don't generate
16. prismaフォルダと3つのファイルが作成される

・datamodel.prisma　⇒ GraphQL用にType定義を記述したファイル（schema.graphqlに似ている）。Prismaはこのファイルを使用してDB Structureを決定する。
・docker-compose.yml ⇒ Dockerの設定ファイル
・prisma.yml ⇒ 使用するPrismaの定義ファイル
※ymlファイル ⇒ jsonみたいなkey-valueペアのファイル。Configurationによく使われる。

```yml:docker-compose.yml
version: '3' # Dockerのバージョン（以下に続くフィールドを決定する）
services:  # 使用するサービス（今回はPrismaだけ）
  prisma:
    image: prismagraphql/prisma:1.29  # 使用する Docker Container
    restart: always  # restart when deploy new changes
    ports:  # 使用するポート
    - "4466:4466"
    environment:
      PRISMA_CONFIG: |  # Prismaのコンフィグ
        port: 4466
        # uncomment the next line and provide the env var PRISMA_MANAGEMENT_API_SECRET=my-secret to activate cluster security
        # managementApiSecret: my-secret
        databases:   # 使用するデータベース
          default:
            connector: postgres
            host: xxx
            database: xxx
            ssl: true   # プロンプトで聞かれたのに書かれていなかったので追記しておく
            user: xxx
            password: xxx
            rawAccess: true
            port: '5432'
            migrations: true
```

### Deploy
1. prisma init した後のコンソールに以下のステップが書かれているので従う（

```
Next steps:
  1. Open folder: cd prisma
  2. Start your Prisma server: docker-compose up -d
  3. Deploy your Prisma service: prisma deploy
```

・docker-compose up -d ⇒ Prismaを実行するのに必要なコードをインストール ⇒ PrismaをVirtual Machineで起動
・prisma deploy ⇒ deploy latest change (例えば、datamodel.prismaを書き換えたら prisma deploy でPrismaにデプロイして、データベースに変更を反映させる)
・コマンドが認識されないことがあったのでcmdを管理者権限で実行して事なきを得る
・prisma deploy をするときはprisma.ymlを以下のように書き換えた

```yml:prisma.yml
endpoint: http://[Docker QuickStart Terminalで表示されるIPアドレス]:4466
datamodel: datamodel.prisma
```

2.  prisma deploy が終わったら http://[Docker QuickStart Terminalで表示されるIPアドレス]:4466 にアクセスすると、GraphQL Playgroundにアクセスできるようになる（現時点でこのPlaygroundはPrismaが提供するGraphQL API に接続している） 
⇒ つまり、例えばこのPlaygroundでMutationを実行したらPostgreSQLのデータベースを実際に変更できる。

3. datamodel.prismaに記述されているTypeとフィールドをもとに、Prismaは自動でQuery/Mutation/Subscriptionを作成してくれる。凄い。

```:datamodel.prisma
type User {
  id: ID! @unique // @uniqueは directives といってフィールドに制約をかけられる代物
  name: String!
}
```
![キャプチャ.JPG](https://qiita-image-store.s3.amazonaws.com/0/385539/8a7c639f-a111-b73a-1aa3-c9a32e08852f.jpeg)

3 . このPlaygroundでMutationを実行したらHerokuのPostgreSQL DBが実際に変更される。 

![g.JPG](https://qiita-image-store.s3.amazonaws.com/0/385539/58fec9f3-0674-f50e-ef58-9e5efcc78a40.jpeg)
![キャプチャ.JPG](https://qiita-image-store.s3.amazonaws.com/0/385539/93b42199-b3d2-4602-bb21-475a9f41b056.jpeg)

#####データベース構造の更新
datamodel.prisma を更新したら「prisma deploy」を実行 ⇒ データベースと GraphQL API に反映

### Node.jsと接続

```
npm install prisma-binding
npm install -g graphql-cli
```
・prisma-binding ⇒ Prisma GraphQL API を操作するための Nodejs メソッドを提供するライブラリ
　https://github.com/prisma/prisma-binding

・graphql-cli ⇒ GraphQLのコマンドラインインターフェイス（これでSchemaをfetchさせる）
　https://github.com/graphql-cli/graphql-cli

・PrismaはデフォルトでSchemaを ProjectRoot/prisma/datamodel.prisma からfetchしているので、fetch元を ProjectRoot/src/generated/prisma.graphql に変更するために、graphql-cliを使用する。

・.graphqlconfig ⇒ どこからSchemaをfetchするのか、記述されているType定義をどこに保存するのかを示すconfiguration file

### Workflow
1.　ProjectRoot/prisma/datamodel.prisma を更新して型の定義を変更する
2. 「prisma deploy」 を実行してデータベースに変更を反映する
3. 「npm run get-schema」で最新のSchemaを ProjectRoot/src/generated/prisma.graphql からfetch ⇒ Prisma API が必要なTypeが記述されたファイルが ProjectRoot/generated/prisma.graphql に自動で生成される
__※「prisma deploy」でinternal server error がでたらDBとの接続を確認する。pgAdminからDBテーブルの確認ができなかったりしたら一度pdAdminを閉じる。__
※ prismaのバージョンが最新すぎるとバグることがあるのでバージョン下げました。

---
※ なんか prisma の directives が反映されなかった（リレーションの CASCADE / SET_NULL が反映されなかった）けど、以下のように変更して事なきを得た
1. datamodel.prisma　⇒ datamodel.graphqlに変更（中身は変えてない）
2. prisma.ymlを以下のように変更 

 ```yml:prisma.yml
endpoint: http://[Docker QuickStart Terminalで表示されるIPアドレス]:4466
datamodel: datamodel.graphql
```