Next.js + GrapqhQLでTodoアプリを構築する(前編)

# はじめに

最近GraphQLについて学びまして、
Next.js + GraphQL + GraphQL CodeGenerator + Prismaの構成でTodoアプリを構築したので
解説をしつつ、その記録をここに残します。

![スクリーンショット 2023-04-15 20.58.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/ba3aad5a-743d-1dd6-245f-86986e601c3f.png)

# 環境

- Macbook Air
- node
    - v18.13.0
- pnpm
    - 7.27.0

# 目次

- [前編](https://qiita.com/maaaashi/items/fe52db19759ea8a0be31) 👈 今ここ
    1. Next Create App
    1. GraphQLサーバー構築
    1. Subscription
    1. DB・Prisma
- [中編](https://qiita.com/maaaashi/items/722d75cf8bd25efded88)
    1. GraphQL Schema
    1. GraphQL Context
    1. GraphQL Code Generator
    1. GraphQL Resolver
    1. GraphQLサーバー修正
- [後編](https://qiita.com/maaaashi/items/5c63398a34ac3ea8ddad)
    1. フロント側準備
    1. フロント側実装

# 前編

前編は準備フェーズです。

## 1. Next Create App

- create app
    
    ```bash
    $ pnpm create next-app nextjs-sample-graphql --typescript
    
    # ESLintを使うかどうか・・・Yes
    ✔ Would you like to use ESLint with this project? … Yes
    # TailwindCSSを使うかどうか・・・Yes
    ✔ Would you like to use Tailwind CSS with this project? … Yes
    # srcディレクトリを使うかどうか・・・Yes
    ✔ Would you like to use `src/` directory with this project? … Yes
    # appディレクトリを使うかどうか・・・No
    ✔ Would you like to use experimental `app/` directory with this project? … No
    # エイリアス設定・・・@/*
    ✔ What import alias would you like configured? … @/*
    
    $ cd nextjs-sample-graphql
    $ pnpm run dev
    ```

    [localhost:3000](http://localhost:3000)でサーバーが起動します。

    ![スクリーンショット 2023-04-15 12.43.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/a30f1cde-31c1-6320-fe0d-1e5512e7330c.png)

## 2. GraphQLサーバー構築

* install
    
    ```bash
    $ pnpm add graphql graphql-yoga
    ```

* GraphQL Server on `api/graphql.ts`

    ```typescript: src/pages/api/graphql.ts
    import { createYoga, createSchema } from 'graphql-yoga'
    import type { NextApiRequest, NextApiResponse } from 'next'
    import { YogaSchemaDefinition } from 'graphql-yoga/typings/plugins/useSchema';
    
    export const config = {
      api: {
        bodyParser: false
      }
    }
    
    const schema = createSchema({
      typeDefs: /* GraphQL */ `
        type Query {
          greetings: String
        }
      `,
      resolvers: {
        Query: {
          greetings: () => 'This is the `greetings` field of the root `Query` type'
        }
      }
    }) as YogaSchemaDefinition<{
      req: NextApiRequest;
      res: NextApiResponse;
    }>
    
    export default createYoga<{
      req: NextApiRequest
      res: NextApiResponse
    }>({
      schema,
      graphqlEndpoint: '/api/graphql'
    })
    ```

    [localhost:3000/api/graphql](http://localhost:3000/api/graphql)
    
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/a79417f2-bcb0-fd08-1a35-d2a1ba9c9f5c.png)

    YogaGraphQLサーバーが立ち上がっています。
    試しにQueryを叩いてみます。
    
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/bf702a0e-d875-1e1f-8615-0b5584b72d0a.png)
    
    ちゃんと叩けました👍

## 3. Subscription

::: note warn
Next.jsのAPIルートではWebSocketsを使うことができません。GraphQL API、WebSocket、および残りの Next.js コンテンツを使うためには、Next.jsカスタムサーバーを作成する必要があります。
:::

> 引用: WebSockets cannot be used with Next.js API Routes(opens in a new tab), we therefore have to create a custom Next.js server(opens in a new tab) that will serve the GraphQL API, WebSockets and the rest of Next.js content.

今回はAPIルートにGraphQLサーバーを構築し、Todoアプリを作っていきたいので、`Subscription`の機能は使わない事にし、この設定はSKIPします。

## 4. DB・Prisma

- DBには`PostgreSQL`を採用しました

### 4-1. PostgreSQL

* compose.ymlファイルの作成
    
    ```bash
    $ touch compose.yml
    ```
    
    ```yml: compose.yml
    version: '3.9'
    
    services:
      db:
        image: postgres:15.1
        ports:
          - 5432:5432
        volumes:
          - postgres:/var/lib/postgresql/data
        environment:
          - POSTGRES_USER=user           # 自分で変更してください
          - POSTGRES_PASSWORD=password   # 自分で変更してください
          - POSTGRES_DB=graphql-todo     # 自分で変更してください
    volumes:
      postgres:
    ```
    
    ```bash
    docker compose up -d
    ```

### 4-2. Prisma設定

::: note info
prismaとはNodejs, TypeScriptで使えるORM(ObjectRelationalMapping)です
:::

https://www.prisma.io/

* install
    
    ```bash
    pnpm add prisma @prisma/client
    ```

* init
    
    ```bash
    pnpm prisma init
    ```

    .envに`DATABASE_URL`を記述します。


    ```.env:.env
    DATABASE_URL="postgresql://user:password@localhost:5432/graphql-todo?schema=public"
    ```


:::note info
urlは、`compose.yml`で設定した変数を用いて、

postgresql://`${POSTGRES_USER}`:`${POSTGRES_PASSWORD}`@localhost:5432/`${POSTGRES_DB}`schema=public

になります。
:::

* Todoテーブルの作成

    ```diff: prisma/schema.prisma
    // This is your Prisma schema file,
    // learn more about it in the docs: https://pris.ly/d/prisma-schema
    
    generator client {
      provider = "prisma-client-js"
    }
    
    datasource db {
      provider = "postgresql"
      url      = env("DATABASE_URL")
    }
    
    + model Todo {
    +   id        String  @id @default(cuid())
    +   content   String
    +   done      Boolean @default(false)
    +   createdAt String
    + }
    ```

* migrate
    
    ```bash
    $ pnpm prisma migrate dev
    Environment variables loaded from .env
    Prisma schema loaded from prisma/schema.prisma
    Datasource "db": PostgreSQL database "graphql-todo", schema "public" at "localhost:5432"
    
    ? Enter a name for the new migration: › addTodoTable 
    Applying migration `20230413102125_add_todo_table`
    
    The following migration(s) have been created and applied from new schema changes:
    
    migrations/
      └─ 20230413102125_add_todo_table/
        └─ migration.sql
    
    Your database is now in sync with your schema.
    ```

    ::: note info
    migrateが成功すると、`prisma/`に`migrations`ディレクトリが作成され、中に実行されたSQLが入ったmigrationファイルが作成されます。
    RubyOnRailsのORMである、`Active Record`に慣れている人には割とイメージしやすいファイル構成かもしれません。
    
    ```bash
    .
    ├── prisma
    │   ├── migrations
    │   │   ├── yyyyMMddhhmmss
    │   │   │   └─ migration.sql
    │   │   └─ migration_lock.toml
    |   └─ prisma.schema
    ```

- prisma studioの起動

    prismaには入っているデータの検索、操作を簡単に行える`prisma studio`というものが標準で用意されています。

    ```bash
    pnpm prisma studio
    ```
    
    ![スクリーンショット 2023-04-15 20.28.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/284e1ddc-8f6e-ccc5-2427-b8af1698d5a9.png)


# 次回: GraphQL

https://qiita.com/maaaashi/items/722d75cf8bd25efded88

* 中編
    1. GraphQL Schema
    1. GraphQL Context
    1. GraphQL Code Generator
    1. GraphQL Resolver
    1. GraphQLサーバー修正