TypeScript + Nexus + Prisma で GraphQL ( for MySQL ) 環境を構築したった

# はじめに

はじめまして。全然関係ないけど、最近は Vue を裏切って React 書いてます。

さて、前回、[TypeORM を使って Node.js の GraphQL 環境を構築しました](https://qiita.com/les-r-pan/items/8f11d90eb0538cac2812)が、ぶっちゃけ TypeORM と GraphQL との親和性があまり良くなくて、結局、その後の開発がそこまでドライブしませんでした。
そんな中、今のチームで Node.js で GraphQL の API サーバを新たに構築する必要があり、参考になる既存資産もあったので Nexus + Prisma でやってみました。

以下の記事を大いに参考にさせていただいております。

https://zenn.dev/queq1890/articles/2a7967cb679357

# 実際にやってみた

## Prisma

https://www.prisma.io/

> Next-generation Node.js and TypeScript ORM

と謳っています。
公式の記載の通り、こちらは ORM ライブラリです。

インストールします。
`package.json` は事前に準備してください。

```bash
$ npm i @prisma/client@2.23
```

2 系を使っているのは、当初、3 系で構築してみて動かしたらエラったためです 😊😊😊

続いて、最初に必要になるコードを自動生成します。以下を実行。

```bash
$ npx prisma init
```

`prisma/` が生成されるので、中に配置されている `.env` と `schema.prisma` を修正。

```test:.env
# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#using-environment-variables

# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server and MongoDB (Preview).
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings

DATABASE_URL="mysql://${username}:${password}@${host}:${port}/${db_name}"
```

続いて、接続の定義と Schema 定義を行います。
以下はサンプルです。

```schema.prisma
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model Company {
  id       Int       @id @default(autoincrement())
  name     String
  address  String
  accounts Account[]
}

model Account {
  id        Int     @id @default(autoincrement())
  name      String
  email     String  @unique
  companyId Int
  company   Company @relation(fields: [companyId], references: [id])
}
```

接続設定と Schema のファイルを修正したら migration ファイルを生成。以下コマンドを実行。
この辺は元記事時点とのバージョンの違いからコマンドに差異があります。

```bash
$ npx prisma migrate dev --name ${migration_file_name} --create-only
```

`prisma/2021xxxxxxxxxx_${migration_file_name}` 的なディレクトリができているので、その中に `.mysql` ファイルがあることを確認。
以下を実行すると migration が走ります。

```bash
$ npx prisma migrate dev
```

```bash
(省略)

✔ Generated Prisma Client (2.30.3) to ./node_modules/@prisma/client in 159ms
```

最後にこんなログが出力されれば成功です。

ターミナルから MySQL に直接ログインできる方は実際にテーブルを確認してみてください。

次に、↑で定義した Schema 情報から prisma-client の型を生成します。

```bash
$ npx prisma generate
```

## Apollo Server

Express で Apollo Server を動かすための設定を行います。

Apollo Server は、ApolloClient を含むすべての GraphQL クライアントと互換性のあるオープンソースの仕様準拠の GraphQL サーバーです。
ちなみに、上記はただ公式の英文を翻訳しただけです。

2 系を使っているのは、当初、3 系で構築してみて動かしたらエラったためです 😊😊😊

```bash
$ npm i -D ts-node-dev typescript @types/express
$ npm i express apollo-server-express@2
```

`tsconfig.json` を作成。内容はお好みで。

```bash
$ touch tsconfig.json
```

サーバのエントリポイントなどを作成。
この辺は、ほぼ元記事のコードをパクっております。

```typescript:src/server.ts
import * as express from 'express';
import { ApolloServer } from 'apollo-server-express';
import { createContext } from './context';
import schema from './schema';

const PORT = 4000;

const app = express();
const apollo = new ApolloServer({ schema, context: createContext });

apollo.applyMiddleware({ app });

app.listen({ port: PORT }, () =>
  console.log(`🚀 Server ready at http://localhost:4000${apollo.graphqlPath}`)
);
```

```typescript:src/context.ts
import { PrismaClient } from '@prisma/client';
import { Request } from 'apollo-server-express';

const prisma = new PrismaClient();

export interface Context {
  request: Request;
  prisma: PrismaClient;
}

export function createContext(request: Request): Context {
  return {
    request,
    prisma,
  };
}
```

`package.json` に以下を追記。

```json:package.json
{
  ...
  "scripts": {
    "dev": "ts-node-dev --no-notify --respawn --transpile-only src/server.ts",
    "build": "tsc -p .",
    "start": "node dist/server.js",
  }
  ...
}
```

## Nexus

https://www.npmjs.com/package/nexus

Node.js で Type-Safe に GraphQL のスキーマを構築するためのライブラリだそうです。

インストールします。

```bash
$ npm i graphql
$ npm i @nexus/schema nexus nexus-plugin-prisma
```

Schema のコードを追加します。
元記事とは違い、自動生成コードの出力先を `src/gen/` 配下に設定してます。

```typescript:src/schema.ts
import * as path from 'path';
import { makeSchema } from '@nexus/schema';
import { nexusPrisma } from 'nexus-plugin-prisma';
import * as types from './types';

const schema = makeSchema({
  types,
  plugins: [
    nexusPrisma({
      experimentalCRUD: true,
    }),
  ],
  outputs: {
    schema: path.join(__dirname, './gen/graphql/schema.graphql'),
    typegen: path.join(__dirname, './gen/nexus/types.ts'),
  },
});

export default schema;
```

```typescript:src/types/index.ts
export * from './models';
export * from './resolvers';
```

```src/types/models/index.ts
// e.g.
export * from './User'
```

```src/types/models/User.ts
import { objectType } from '@nexus/schema';

// e.g.
export const User = objectType({
  name: 'User',
  definition(t) {
    t.int("id")
  },
});
```

```src/types/resolvers/index.ts
export * from './Query';
export * from './Mutation';
```

```src/types/resolvers/Query.ts
import { queryType } from '@nexus/schema';

// e.g.
export const Query = queryType({
  definition(t) {
    t.crud.user();
  },
});
```

```src/types/resolvers/Mutation.ts
import { mutationType } from '@nexus/schema';

// e.g.
export const Mutation = mutationType({
  definition(t) {
    t.crud.createOneUser();
  },
});
```

`package.json` に以下を追記。

```json:package.json
{
  ...
  "scripts": {
    "generate:nexus": "ts-node --transpile-only src/schema"
  }
  ...
}
```

Nexus の型定義を生成します。

```bash
$ npm run generate:nexus
```

## GraphQL Playground 

GraphQL Playground を実行します。

```bash
$ npm run dev
```

ブラウザからアクセスしてみて、意図通りの Schema などが表示されていれば成功です。

# おわりに

TypeORM を使って無理やり GraphQL を構築していた時よりも、Query の頻出パターンを自動で生成できるなどの仕組みがあるので、こっちの方が圧倒的に便利そうな気配がありました。
初期構築も、前回記事の内容よりも少ないので、明らかに導入も簡単です。そして、TypeORM より日本語の参考記事が多い、気がする。

認証系の組み込みなど、実運用レベルのコードをまだ書いてませんが、これから Node.js で GraphQL サーバの構築を始める方は たぶん こっち使った方がいいと思います。



おしまい。