TypeScript+NestJS+PrismaでGraphQLサーバーを作成してみた

# はじめに
この数年フロントエンドドリブンな開発が盛んに行われており、バックエンド側の処理もTypeScriptで実装している記事や動きをよく見かけます。マイクロフロントエンドみたいな単語も出てきましたね。
GoQSystemでも新しい技術の情報収集やキャッチアップは常に行っています。私はバックエンドエンジニアですが、システム全体のアーキテクチャを検討する上でフロントエンド側の技術の情報収集やキャッチアップは常に行っています。
今回はPrismaのGitHubリポジトリにあるExampleを使用してGraphQLサーバー作成してみます。

# 使用技術
* TypeScript
* NestJS
* Prisma
* GraphQL

# NestJSとは
効率的で信頼性が高く、スケーラブルなサーバーサイドアプリケーションを構築するためのプログレッシブNode.jsフレームワークです。

https://nestjs.com/

# Prismaとは
オープンソースのORM(Object-relational mapping)です。

https://www.prisma.io/

# GraphQLとは
クエリ言語とスキーマ言語で構成されたWeb APIの規格です。GraphQLは、Facebook社によって2012年に開発がスタートし、2015年にオープンソース化されました。

https://graphql.org/

# 開発環境
※ nodeやnpmはインストールされているものとします。
```
マシン：MacBook Pro （13インチ, 2020）（Apple M1, メモリ16GBモデル）
OS：macOS Ventura 13.0.1

npm -v
8.19.2

node -v
v18.12.1
```

# 使用するExample
https://github.com/prisma/prisma-examples/tree/latest/typescript/graphql-nestjs 

# GraphQLサーバーを作成する
### 1. **Exampleダウンロードとnpm依存関係インストール**
[Exampleリポジトリ](https://github.com/prisma/prisma-examples/tree/latest/typescript/graphql-nestjs)をREADME通りに以下のコマンドでダウンロードします。
```
npx try-prisma --template typescript/graphql-nestjs
```
以下のように自動でパッケージをインストールするか聞かれるので今回は`y`を選択し、自動でインストールしてもらいます。
```
? Should we automatically install packages for you? y
```
次に使用するパッケージマネジャーを選ぶ必要があるので、選択します。今回は`npm`を使用するのでこのままEnterを押します。
```
? Which package manager do you prefer? (Use arrow keys)
❯ npm
  yarn
  pnpm
```
次にプロジェクトの名前を聞かれるので入力します。今回は`nestjs-prisma-graphql`とします。
```
? What should the project be named? nestjs-prisma-graphql
```
最後にフォルダの作成場所を聞かれるので、適当なパスを入力します。今回は`.`とします。
```
? Where should the new folder be created? .
```

<details><summary>私は最終的にこのような出力となりました。</summary>

```
npx try-prisma --template typescript/graphql-nestjs
✔ Loaded 40 templates
? Should we automatically install packages for you? Yes
? Which package manager do you prefer? npm
? What should the project be named? nestjs-prisma-graphql
? Where should the new folder be created? .
✔ Downloaded and extracted the typescript/graphql-nestjs project.
✔ Installed packages.

The project is good to go! Next steps:

  1. Navigate into the project directory:
      cd ./nestjs-prisma-graphql

  2. Create and execute initial migration based on `schema.prisma`:
      npx prisma migrate dev

For more information about this project, visit:
https://github.com/prisma/prisma-examples/tree/latest/typescript/graphql-nestjs

If you have any feedback about this specific template, we want to hear it!
Submit any feedback here: https://pris.ly/prisma-examples-feedback
```
</details>

### 2. **データーベースの作成とシード**
以下のコマンドを実行すると、SQLiteを作成、`User`と`Post`テーブルを作成してくれます。
```
cd ./nestjs-prisma-graphql
npx prisma migrate dev --name init
```
このコマンドがデータベースとテーブル作成ファイル[prisma/schema.prisma](https://github.com/prisma/prisma-examples/blob/latest/typescript/graphql-nestjs/prisma/schema.prisma)、シード実行ファイル[prisma/seed.ts](https://github.com/prisma/prisma-examples/blob/latest/typescript/graphql-nestjs/prisma/seed.ts)を実行しています。

*※今回はPrismaのExampleなのでORMはPrismaを使用していますが、TypeORMも使用してみました。
TypeORMがNestJSのデファクト？なのだと思いますが、0.2系と0.3系の変更点が破壊的で情報が少なく少々苦労しました。個人的にはPrismaの方が使いやすいと感じました。（特に設定ファイルとマイグレーション関連）*

<details><summary>実行すると以下のような出力になりました。</summary>

```
npx prisma migrate dev --name init
Prisma schema loaded from prisma/schema.prisma
Datasource "db": SQLite database "dev.db" at "file:./dev.db"

SQLite database dev.db created at file:./dev.db

Applying migration `20230115152921_init`

The following migration(s) have been created and applied from new schema changes:

migrations/
  └─ 20230115152921_init/
    └─ migration.sql

Your database is now in sync with your schema.

✔ Generated Prisma Client (4.8.1 | library) to ./node_modules/@prisma/client in 194ms


Running seed command `ts-node prisma/seed.ts` ...
Start seeding ...
Created user with id: 1
Created user with id: 2
Created user with id: 3
Seeding finished.

🌱  The seed command has been executed.
```
</details>

### 3. **GraphQLサーバーの起動**
以下のコマンドでNestJSを起動します。
```
npm run dev
```
以下のようなログがターミナル上に表示され、
```
npm run dev
...
🚀 Server ready at: http://localhost:3000/graphql
⭐️ See sample queries: http://pris.ly/e/ts/graphql-nestjs#using-the-graphql-api
```

http://localhost:3000/graphql にアクセスしGraphQL Playgroundが表示されればOKです。
![スクリーンショット 2023-01-16 0.35.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/765794/1a6f39f3-a02e-446b-4e73-3ae29dcb8459.png)

# GraphQLでデータを取得してみる
[GraphQL Playground](https://github.com/graphql/graphql-playground)を使用してデータを取得してみます。
**http://localhost:3000/graphql にアクセスし、以下のクエリーを使用して、`posts`とそれに紐つく`authors`を取得します。**

```graphql
query {
  feed {
    id
    title
    content
    published
    author {
      id
      name
      email
    }
  }
}
```

GraphQL Playgroundの左側へ上記クエリーを貼り付けて、画面真ん中の`execute`ボタンを押せばデータが取得できます。
![スクリーンショット 2023-01-16 0.41.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/765794/8dba0270-c8d8-ac0b-efc9-be3ef6241840.png)

他にもデータ作成（`mutation`）、新しいモデルの作成（Prisma）方法なども[Exampleリポジトリ](https://github.com/prisma/prisma-examples/tree/latest/typescript/graphql-nestjs)にあるので是非試してみてください。

GraphQLの実現には`package.json`を確認したらわかるように、[Apollo](https://www.apollographql.com/)が使用されています。（`src/app.module.ts`で`ApolloDriver`が読み込まれています。）

```typescript
@Module({
  imports: [
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
      autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
      buildSchemaOptions: { dateScalarMode: 'timestamp' },
    }),
  ],
  controllers: [],
  providers: [PrismaService, UserResolver, PostResolver],
})
```

そして、GraphQLのSchema定義は`src/schema.gql`で行われています。

# 感想
今回は紹介しませんが、Exampleを使用せずに0からNestJSをインストールしてデフォルト機能を使用してREST APIを作成したり、SQLiteではなくDockerでPostgreSQLやMySQLを構築し使用したり、TypeORM使ったり、tRPCサーバー立ててみたりいろいろなことを試してみました。

シンプルな記述内容で簡単にAPIサーバーを作成することができるのでとても魅力的な技術だなと思っています。AWS CDKでTypeScriptを使用すれば、フロントエンド+バックエンド+インフラ全てTypeScriptで実現できますね。

上述したようにtRPCのサーバーも非常に簡単に作成できました。これらの技術を使用すれば非常に簡単にREST APIやGraphQL環境を作成できるのは魅力的です。

ただ、がっつりバックエンドAPIを作成するときにあえてNestJSというフレームワークを選択することはないのかなというのが正直な思いです。もう少し複雑な処理やアーキテクチャを組みたい時やスケールさせていくことを考えると特に思うところです。
しかしながら、組織・チームでの開発、保守運用を考慮するとフロントエンドエンジニアが慣れ親しんだ言語でバックエンド側の処理を構築できるのは魅力的だなと感じました。組織やチームにバックエンドエンジニアが不足している、いないなどの状況もあり得るのでその場合は選択する理由にはなるかと思います。

フロントエンドエンジニアからすると簡単にアプリケーションを構築するのであれば[T3 Stack](https://github.com/t3-oss/create-t3-app)、もしくは[SvelteKit](https://kit.svelte.dev/)や[Supabase](https://supabase.com/)(or Firebase)使用してといった選択になるのではないかと想像しています。

使い所はしっかりと検討しなければいけない技術ですが、どこかで採用していきたいとも感じました。いずれにしても、自分の専門外（TypeScript）の技術を触ると知見が広がって楽しかったです。

# 最後に
#### **GoQSystemでは一緒に働いてくれる仲間を募集中です！**
求人は出していませんが、SREやQAエンジニアも今後募集していこうと考えています！
ご興味がある方は以下リンクよりご確認ください。

https://goqsystem.recruit.site?qiita=438e834b5ea134472d2f