「Fullstack App With TypeScript, PostgreSQL, Next.js, Prisma & GraphQL: GraphQL API」記事の補足

Nexus や prisma を触ってみたいなと思っていたところ、ちょうどいいチュートリアル記事
[Fullstack App With TypeScript, PostgreSQL, Next.js, Prisma & GraphQL: GraphQL API](https://www.prisma.io/blog/fullstack-nextjs-graphql-prisma-2-fwpc6ds155)
があったので、やってみました。
途中でいくつか躓いた箇所があったので、そのメモです。

レポジトリ: https://github.com/y-takey/prisma_gql_example

## 前準備

### Node

Node のバージョンは16系の最新を使用するのが無難。

### DB

PostgreSQL はインストール済み、もしくはコンテナ等で使用可能な前提。

```
psql -d postgres
```

以下のように適当なユーザを作る。databaseを作る必要はないが、その場合はprismaが作ってくれるため `CREATEDB` を付与しておく必要がある。

```
CREATE USER user1 WITH PASSWORD 'pass' CREATEDB CREATEROLE;
```

## [Seeding the database](https://www.prisma.io/blog/fullstack-nextjs-graphql-prisma-2-fwpc6ds155#seeding-the-database)

### DATABASE_URL のフォーマット

`.env.example` をコピーし `.env` を作成後、DATABASE_URL のフォーマットは以下の通り。
database が存在しない場合は prisma が作成してくれる。

```
DATABASE_URL="postgresql://{user}:{pass}@127.0.0.1/{database}"
```

### ts-node のインストール

`prisma db seed` を実行する際にts-nodeが必要となるが、元のpackage.jsonには含まれていなかったのでインストールする。
ちなみに `npx prisma db seed --preview-feature` と書かれているが、現在のprismaでは `db seed` が正式リリースされているため、 `--preview-feature` は不要。

```
yarn add -D ts-node
```

## [Building the GraphQL API](https://www.prisma.io/blog/fullstack-nextjs-graphql-prisma-2-fwpc6ds155#building-the-graphql-api)

### graphqlのバージョン指定

2021/11/23時点では `graphql` はバージョン 16 が最新だが、 [nexus が未対応](https://github.com/graphql-nexus/nexus/pull/977)のためバージョン 15 を指定する

### micro もインストール

インストールするものに `micro` が入っていないが必要だったので追加

### prismaのエラー対応

M1 Mac を使っていると以下のエラーが出たので、書かれている通り `prisma/schema.prisma` の `generator` ブロックに `binaryTargets` を追加し `yarn prisma generate` を実行すると解決した。

```
/path/to/node_modules/@prisma/client/runtime/index.js:36467
      throw new PrismaClientInitializationError(errorText, this.config.clientVersion);
            ^

PrismaClientInitializationError: Query engine library for current platform "darwin-arm64" could not be found.
You incorrectly pinned it to darwin-arm64

This probably happens, because you built Prisma Client on a different platform.
(Prisma Client looked in "/path/to/node_modules/@prisma/client/runtime/libquery_engine-darwin-arm64.dylib.node")

Searched Locations:

  /path/to/node_modules/.prisma/client
  /path/to/node_modules/@prisma/client
  /path/to/node_modules/@prisma/client
  /path/to/node_modules/.prisma/client
  /path/to/prisma
  /tmp/prisma-engines
  /path/to/node_modules/.prisma/client


To solve this problem, add the platform "darwin-arm64" to the "binaryTargets" attribute in the "generator" block in the "schema.prisma" file:
generator client {
  provider      = "prisma-client-js"
  binaryTargets = ["native"]
}

Then run "prisma generate" for your changes to take effect.
Read more about deploying Prisma Client: https://pris.ly/d/client-generator
    at Object.getLibQueryEnginePath (/path/to/node_modules/@prisma/client/runtime/index.js:36467:13)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Object.loadEngine (/path/to/node_modules/@prisma/client/runtime/index.js:36128:33)
    at async Object.instantiateLibrary (/path/to/node_modules/@prisma/client/runtime/index.js:36094:5) {
  clientVersion: '3.4.2',
  errorCode: undefined
}
```

## [Updating the resolver to return paginated data from the database](https://www.prisma.io/blog/fullstack-nextjs-graphql-prisma-2-fwpc6ds155#updating-the-resolver-to-return-paginated-data-from-the-database)

### 型情報の自動生成

チュートリアルに従ってコードを書いていると途中で型エラーとなるかもしれないが、以下のような状態で保存すると型情報が自動生成されてエラーも解消される。ただし `yarn dev` を実行しておく必要がある。

```ts
export const LinksQuery = extendType({
  type: "Query",
  definition(t) {
    t.field("links", {
      type: Response,
      args: { first: intArg(), after: stringArg() },
      async resolve(_, args, ctx) {},
    });
  },
});
```

### `orderBy` を修正

`graphql/types/Link.ts` でクエリの orderBy の値が間違っているので `id` に修正

```ts
const secondQueryResults = await ctx.prisma.link.findMany({
  take: first,
  cursor: { id: myCursor },
  orderBy: { id: "asc" },
});
```

## おまけ

### 自動生成される型情報の利用

チュートリアルでは型情報を `node_modules/@types/nexus-typegen/index.d.ts` に出力するようにしていたが、それだと利用しにくいため `generated/nexus-typegen.ts` に変更。
また、以下のようにすることでエディタで補完が効くようになる。

```ts
// pages/index.tsx
import { NexusGenFieldTypes } from "../generated/nexus-typegen";

    fetchMore<NexusGenFieldTypes["Query"], { after: number }>({
      variables: { after: endCursor },
      updateQuery: (prevResult, { fetchMoreResult }) => {
        fetchMoreResult.links.edges = [
          ...prevResult.links.edges,
          ...fetchMoreResult.links.edges,
        ];
        return fetchMoreResult;
      },
    });
```