🌈

Prisma を使った効率的なバックエンド開発ワークフロー

2023/03/28に公開

1. はじめに


この記事では、Node.js 上でのデータベース操作やクエリを簡単かつ効率的に行うことができる Prisma と、Prisma を使用したバックエンド開発のワークフローについて学びます。開発環境のセットアップから、スキーマの定義、マイグレーション、データ操作、そしてデータの可視化までの一連の流れを説明します。

また、TypeScript や GraphQL との親和性についても触れます。Prisma は TypeScript を前提にしたクライアントを生成するため、型安全なデータベース操作が可能です。TypeScript を使用することで、コードの品質や保守性が向上し、開発プロセスが効率化されます。また、GraphQL と組み合わせることで、GraphQL を使用する際に発生しやすい N+1 問題に対応しつつ、データアクセスと API の柔軟性を向上します。実際に動くコードを示しながら、TypeScript や GraphQL との関係性についても説明します。最後に Appendix として Prisma と GraphQL を用いた API 開発についても記載します。

次の章では、Prisma の概要と主要な機能について説明します。それ以降の章については、目次を参照してください。それでは、Prisma を使ったバックエンド開発の世界を一緒に学んでいきましょう。

2. Prisma とは

Prisma は、Node.js と TypeScript のための次世代 ORM(Object Relational Mapping)であり、データベースへのアクセスを簡単かつ効率的にするためのツールです。Prisma はデータベースとアプリケーションの間にある抽象化レイヤーを提供し、型安全なクエリビルディングとデータベーススキーマ管理機能を備えています。

2.1 主要な機能

以下は、Prisma の主要な機能です。

  • Prisma Client - スキーマから自動的に生成される、型安全なクライアントライブラリで、データベースへのアクセスを容易にします。
  • Prisma Migrate - Prisma スキーマを使用してデータベーススキーマを定義し、マイグレーション機能でスキーマの変更を管理できます。
  • Prisma Studio - ブラウザからデータベースの内容を直感的に閲覧・編集できる、モダンな GUI ツールです。


from Prisma – The Complete ORM for Node.js & TypeScript

Prisma は、PostgreSQL、MySQL、SQLite、MongoDB、CockroachDB、Microsoft SQL Server などの主要なデータベースに対応しており、上記機能を用いて開発者がデータベースとのやりとりを効率化できるように設計されています。

2.2 GraphQL との親和性

Prisma は、GraphQL API の開発にも適しています。Prisma Client を使ってバックエンドでデータベースへのアクセスを行い、フロントエンドからの GraphQL クエリやミューテーションを処理することができます。また、Prisma は Nexus や TypeGraphQL などの GraphQL ツールとの連携事例も多く見つかります。また、本記事の最後に Appendix として Prisma と GraphQL を使用した API のコード例を示します。

参考:
GraphQL with Database & Prisma | Next-Generation ORM for SQL Databases
Home page | TypeGraphQL Prisma
Nexus Prisma - Prisma plugin for Nexus – Nextra

3. Prisma を使った開発環境のセットアップ

この章では、Prisma を使用した開発環境のセットアップ方法について説明します。Node.js と TypeScript のプロジェクトを作成し、必要なパッケージをインストールします。

3.1. 使用するライブラリや環境のバージョン

この記事で使用するライブラリや環境のバージョンは以下の通りです。

  • Node.js: v18.15.0
  • npm: 9.5.0
  • Prisma: 4.11.0
  • SQLite: 3.39.5

Prisma の説明に集中し環境構築の手間を減らすために、RDB は SQLite としています。
バージョンが異なる場合、動作しない可能性がありますので、ご注意ください。

3.2. プロジェクトの作成

まず、新しいディレクトリを作成し、その中に Node.js と TypeScript のプロジェクトを作成します。

mkdir prisma-example
cd prisma-example
npm init -y

次に、TypeScript とその関連パッケージをインストールします。

npm install typescript ts-node ts-node-dev --save-dev

プロジェクトのルートディレクトリに npx tsc --initコマンドで tsconfig.json ファイルを作成し、TypeScript の設定を行います。

3.3. プロジェクトの初期化

Prisma CLI と Prisma Client をインストールします。

npm install prisma @prisma/client --save-dev

Prisma CLI を使って、Prisma の設定ファイル(prisma/schema.prisma)を生成します。

npx prisma init

以上で、Prisma の開発環境のセットアップが完了です。次の章では、データベーススキーマの定義方法について説明します。

4. Prisma スキーマの定義

この章では、Prisma でデータベーススキーマを定義する方法について説明します。Prisma のスキーマ言語を使用してモデルを定義し、データベースとのマッピングを行います。

4.1. スキーマファイルの作成

Prisma スキーマファイル(prisma/schema.prisma)は、データベースの接続設定やモデル定義を記述するためのファイルです。このファイルを更新することで、データベーススキーマと Prisma クライアントが同期されます。

4.2. データベース接続設定

作成した prisma/schema.prisma ファイルには、データベース接続設定が記述されています。SQLite を使用する場合、以下のようになります。

prisma/schema.prisma
datasource db {
  provider = "sqlite"
  url      = "file:./dev.db"
}

4.3. モデルの定義

Prisma では、データベーススキーマをモデルとして定義します。モデルは、データベースのテーブルと対応しており、テーブルの構造を表現します。以下は、UserPost という 2 つのモデルを定義した例です。

prisma/schema.prisma
model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  name      String?
  posts     Post[]
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  published Boolean  @default(false)
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
}

対応する ER 図は以下のとおりです。

モデル内では、各フィールドのデータ型やリレーションシップ、制約を指定できます。例えば、@id は主キーを、@unique はユニーク制約を、@default はデフォルト値を表します。

4.4. リレーションシップの定義

Prisma では、モデル間のリレーションシップを簡単に定義できます。上記の例では、User モデルと Post モデルの間に 1 対多のリレーションシップが定義されています。これにより、各ユーザーは複数の投稿を持ち、各投稿は 1 人のユーザーによって作成されることが表現されています。

リレーションシップは、@relation 属性を使用して定義されます。この属性は、関連するフィールドと参照先のフィールドを指定することで、リレーションシップを構成します。

model User {
  // ...
  posts     Post[]
}

model Post {
  // ...
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
}

上記の例では、User モデルの posts フィールドは Post モデルの配列を持ち、Post モデルの author フィールドは User モデルを参照しています。@relation 属性は、Post モデルの authorId フィールドを User モデルの id フィールドにマッピングしています。

Prisma のスキーマでは、親モデル(User)にも posts フィールドを記述することで、双方向のリレーションシップが定義されます。これにより、Prisma クライアントを使ったデータ操作時に、両方向から関連データにアクセスできるようになります。

例えば、User モデルに posts フィールドを定義することで、後述する Prisma クライアントを用いて以下のようなデータ操作が可能になります。

  1. ユーザーが持つすべての投稿を取得します。
const userWithPosts = await prisma.user.findUnique({
  where: { id: 1 },
  include: { posts: true },
});
  1. ユーザーを作成する際に、関連する投稿も同時に作成します。
const newUserWithPosts = await prisma.user.create({
  data: {
    email: "john@example.com",
    name: "John",
    posts: {
      create: [
        { title: "Hello, World!", content: "My first post", published: true },
      ],
    },
  },
});

子モデル(Post)には author フィールドと@relation 属性がありますが、これだけでは親モデルから子モデルへのリレーションシップが定義されません。双方向のリレーションシップを定義することで、データ操作がより柔軟になり、コードの可読性も向上します。クライアントの使用方法については、改めて 6 章につて説明します。

4.5. 既存のデータベースからのスキーマ生成(prisma db pull

Prisma では、既存のデータベースからスキーマを自動生成することもできます。この機能を使えば、すでに存在するデータベースに基づいてスキーマを作成することができます。これは、既にデータベースが存在しているシステムに対して、Prisma を導入する場合に非常に便利です。

スキーマの生成には、 prisma db pull コマンドを使用します。このコマンドは、指定されたデータベースからスキーマを生成し、schema.prisma ファイルに保存します。生成されたスキーマは、手動で定義した場合と同様に、Prisma クライアントで使用することができます。

ただし、既存のデータベースから自動生成されたスキーマは、完全ではない場合があります。生成されたスキーマには、データベースから取得できない情報が含まれている場合があります。そのため、生成されたスキーマを確認しながら導入するのが良いでしょう。


from What is Prisma? (Overview)

これで、4 章「データベーススキーマの定義」が完了です。

5. マイグレーションの管理

この章では、Prisma Migrate を使用してデータベースにマイグレーションを適用する方法について説明します。

Prisma Migrate は、データベーススキーマの変更を管理するためのマイグレーションツールです。prisma/schema.prisma ファイルで定義したデータベーススキーマに基づいて、マイグレーションファイルを生成し、データベースに適用することができます。

5.1. マイグレーションの生成

まず、マイグレーションファイルを生成するために、下記コマンドを実行します。このコマンドは、現在のデータベーススキーマと prisma/schema.prisma ファイルの差分を検出し、必要なマイグレーションファイルを生成します。

npx prisma migrate dev --create-only --name newMigration

コマンドが成功すると、prisma/migrations ディレクトリに下記のような新しいマイグレーションファイルが生成されます。このファイルには、データベーススキーマの変更内容が SQL 形式で記述されています。ここで、スキーマのモデルにあったUserテーブルのpostsPostテーブルのauthorが存在しないことがわかります。Prisma 上では、親であるUserモデルが子であるPostモデルの情報を持ち冗長な構成となっていますが、SQL では、子であるPostのみが親の ID を持っています。ここに、Prisma の特徴があるように思います。

prisma/migrations/20230328022211_init/migration.sql
-- CreateTable
CREATE TABLE "User" (
    "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    "email" TEXT NOT NULL,
    "name" TEXT
);

-- CreateTable
CREATE TABLE "Post" (
    "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    "title" TEXT NOT NULL,
    "content" TEXT,
    "published" BOOLEAN NOT NULL DEFAULT false,
    "authorId" INTEGER NOT NULL,
    CONSTRAINT "Post_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);

-- CreateIndex
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");

参考:
Prisma CLI Command Reference

5.2. マイグレーションの適用

次に、下記コマンドを実行することで、マイグレーションファイルをデータベースに適用します。

npx prisma migrate deploy

また、下記コマンドでも、マイグレーションを適用できます。

npx prisma migrate dev

このコマンドは、マイグレーションファイルが生成されていない場合、マイグレーションファイルを生成した後、データベースに適用し、スキーマの変更を反映させます。このコマンドを用いる場合は、npx prisma migrate dev --create-onlyは不要です。
prisma migrate dev コマンドは、開発環境でのマイグレーションの適用に適しています。
開発環境では、このコマンドを使用して自動的にマイグレーションファイルを生成・適用し、スキーマの変更をデータベースに反映させることができます。


from What is Prisma? (Overview)

5.3. マイグレーションのロールバック

適用したマイグレーションを取り消す(ロールバック・ダウンマイグレーション)場合は、基本的には、スキーマを元に戻るように修正して、同じようにマイグレーションすることが求められている。

参考:
Generating down migrations
Roll back the latest migration group · prisma/prisma · Discussion #4617
Migration troubleshooting in production

6. Prisma クライアントを使ったデータ操作

この章では、Prisma クライアントを使ってデータベースとやりとりする方法について説明します。Prisma クライアントは、Prisma スキーマに定義されたモデルに基づいて自動生成される TypeScript のクライアントライブラリで、データベース操作を簡単かつ安全に行うことができます。

以下の章で実行するコードは下記リポジトリに置いています。参考にしてください。
optimisuke/hello-prisma-graphql

6.1. クライアントの生成

まず、prisma generate コマンドを実行して Prisma クライアントを生成します。このコマンドは、prisma/schema.prisma ファイルの内容に基づいてクライアントを生成し、node_modules/@prisma/client ディレクトリに保存します。

npx prisma generate

6.2. CRUD 操作の実行

Prisma クライアントを使って、データベースに対して CRUD(Create, Read, Update, Delete)操作を行うことができます。以下に、いくつかの一般的なデータ操作の例を示します。

生成された Prisma クライアントを使ってデータベース操作を行うには、まず@prisma/client パッケージから PrismaClient をインポートします。

import { PrismaClient } from "@prisma/client";

次に、PrismaClient のインスタンスを作成し、データベースとの接続を開始します。

const prisma = new PrismaClient();

データを作成するには、create メソッドを使用します。以下の例では、新しい User レコードを作成しています。

const newUser = await prisma.user.create({
  data: {
    email: "alice@example.com",
    name: "Alice",
  },
});

データを読み取るには、findUnique メソッドや findFirst メソッド、findMany メソッドを使用します。以下の例では、ID が 1 の User レコードを取得しています。

const user = await prisma.user.findUnique({
  where: { id: 1 },
});

データを更新するには、update メソッドを使用します。以下の例では、ID が 1 の User レコードの名前を更新しています。

const updatedUser = await prisma.user.update({
  where: { id: 1 },
  data: { name: "Updated Alice" },
});

データを削除するには、delete メソッドを使用します。以下の例では、ID が 1 の User レコードを削除しています。

const deletedUser = await prisma.user.delete({
  where: { id: 1 },
});

6.3. リレーションの操作

Prisma クライアントを使って、モデル間のリレーションを操作することができます。以下に、いくつかの一般的なリレーション操作の例を示します。

6.3.1. リレーションの読み取り

リレーションを読み取るには、include オプションを使用します。以下の例では、User レコードとそれに関連する Post レコードを取得しています。

const userWithPosts = await prisma.user.findUnique({
  where: { id: 1 },
  include: { posts: true },
});

6.3.2. リレーションの作成

リレーションを作成するには、create メソッドの data オプションでリレーションを指定します。以下の例では、新しい User レコードとそれに関連する Post レコードを作成しています。

const newUserWithPost = await prisma.user.create({
  data: {
    email: "bob@example.com",
    name: "Bob",
    posts: {
      create: {
        title: "First post",
        content: "Hello, world!",
      },
    },
  },
});

コード例

以下に、例を記載します。

src/index.ts
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

async function main() {
  const newUser = await prisma.user.create({
    data: {
      email: "alice@example.com",
      name: "Alice",
    },
  });
  //   console.log(newUser);
  //   const user = await prisma.user.findUnique({
  //     where: { id: 1 },
  //   });
  //   console.log(user);
  console.log(newUser);
  const user = await prisma.user.findUnique({
    where: { email: "alice@example.com" },
  });
  console.log(user);

  const updatedUser = await prisma.user.update({
    where: { id: user?.id },
    data: { name: "Updated Alice" },
  });
  console.log(updatedUser);

  const deletedUser = await prisma.user.delete({
    where: { id: user?.id },
  });
  console.log(deletedUser);

  const newUserWithPost = await prisma.user.create({
    data: {
      email: "bob@example.com",
      name: "Bob",
      posts: {
        create: {
          title: "First post",
          content: "Hello, world!",
        },
      },
    },
  });
  console.log(newUserWithPost);

  const userWithPosts = await prisma.user.findUnique({
    where: { id: newUserWithPost.id },
    include: { posts: true },
  });
  console.log(userWithPosts);
  const deletedPost = await prisma.post.deleteMany({
    where: { authorId: newUserWithPost.id },
  });
  console.log(deletedPost);
  const deletedUser2 = await prisma.user.delete({
    where: { id: newUserWithPost.id },
  });
  console.log(deletedUser2);
}

main()
  .catch((error) => {
    console.error("Error:", error);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });

下記コマンドで実行します。

npx ts-node src/index.ts

これで、Prisma クライアントを使ってデータベースとやりとりする方法についての基本的な知識が得られました。次の章では、データの可視化や管理について説明します。

6.4. トランザクションの管理

トランザクションとは、データベースに対する複数のクエリを一つのまとまりとして扱い、すべてのクエリが成功する場合のみ、変更をコミットして永続的に反映させることができる機能です。トランザクションを使用することで、データベース操作においてデータの整合性を保つことができます。

Prisma を使ったトランザクションの実装方法は簡単です。まず、PrismaClient インスタンスを取得し、トランザクションを実行する関数を async/await を使って作成します。その後、PrismaClient インスタンスの .$transaction() メソッドを呼び出し、作成した関数を渡します。

以下は、Prisma を使ったトランザクションの具体例です。

src/transaction.ts
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

async function createPostWithTransaction() {
  try {
    await prisma.$transaction(async (prisma) => {
      await prisma.post.create({
        data: {
          title: "title",
          content: "content",
          authorId: 1,
        },
      });

      await prisma.user.update({
        where: { id: 1 },
        data: {
          name: "Updated name",
        },
      });
    });
  } catch (e) {
    console.error(e);
  }
}

createPostWithTransaction()
  .catch((error) => {
    console.error("Error:", error);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });

下記コマンドで実行します。

npx ts-node src/transaction.ts

この例では、post テーブルに新しいレコードを挿入し、同時に user テーブルの name を更新しています。$transaction() メソッドに渡した関数は、トランザクション内で実行されるすべてのクエリが成功した場合にのみ変更がコミットされます。何らかのエラーが発生した場合は、変更がロールバックされます。

トランザクションを実装することで、データの整合性を保つことができます。また、複数のクエリを一つのまとまりとして扱うことができるため、データベースの操作をより安全に行うことができます。

6.5. 初期データの挿入(seeding)

データベースに初期データを挿入することは、アプリケーション開発やテストでよく行われます。Prisma では、upsert メソッドを使って初期データを簡単に挿入することができます。upsert は、レコードが存在しない場合は作成し、存在する場合は更新する操作を行います。

以下の例では、User モデルに初期データを挿入しています。

src/seed.ts
async function seed() {
  const userData = [
    {
      email: "alice@example.com",
      name: "Alice",
    },
    {
      email: "bob@example.com",
      name: "Bob",
    },
  ];

  for (const user of userData) {
    await prisma.user.upsert({
      where: { email: user.email },
      update: {},
      create: user,
    });
  }
}

seed()
  .catch((error) => {
    console.error("Error:", error);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });

下記コマンドで実行します。

npx ts-node src/index.ts

この例では、seed 関数を定義して、その中で User モデルに対して初期データを挿入しています。各ユーザーに対して、upsert メソッドを使ってデータを挿入し、同じメールアドレスのユーザーが存在しない場合は作成し、存在する場合は更新します。このスクリプトは、アプリケーションの起動時やテスト時に実行することができます。

これで、Prisma クライアントを使ってデータベースとやりとりする方法や初期データの挿入についての基本的な知識が得られました。次の章では、データの可視化や管理について説明します。

参考:
Seeding your database
How to add initial data in migration? · prisma/prisma · Discussion #7357

7. Prisma スキーマの更新フロー

ここで、Prisma スキーマを更新する際の手順を振り返ってみましょう。

7.1. スキーマの更新

schema.prisma ファイルを変更します。この時、以下のような変更が可能です。

  • 新しいテーブルの追加
  • 既存のテーブルのカラムの追加、削除、変更
  • テーブル間のリレーションの追加、削除、変更

7.2. マイグレーションファイルの更新と再適用

prisma migrate dev コマンドを実行して、マイグレーションファイルを生成します。これにより、実際のデータベーススキーマの変更が実行されます。この時、以下のようなことが行われます。

  • Prisma が自動的に SQL マイグレーションクエリを生成する
  • 生成されたクエリをデータベースに適用する

7.3. マイグレーションの再適用

本番環境では、prisma migrate devコマンドで生成したマイグレーションファイルとprisma migrate deploy コマンドを用いて、マイグレーションを適用します。これにより、実際のデータベースに変更が反映されます。

7.4. クライアントの再生成

prisma generate コマンドを実行して、新しい Prisma クライアントを生成します。これにより、変更されたスキーマが反映されたクライアントを使用することができます。ただし、マイグレーション時にprisma migrate devコマンドを実行した場合、同時にクライアントも更新されるため、prisma generateコマンドは不要です。

スキーマの更新は、安全性が重要であるため、変更の前にバックアップを作成することも検討する必要があります。また、マイグレーションの実行中に問題が発生した場合、ロールバックが必要になる場合があります。そのため、実行前にテストを実施し、問題が発生した場合に備えた対応を準備することが重要です。

以上で、Prisma を使った開発の大まかな流れを理解できたと思います。次章では、最後に Prisma Studio 等のデータを可視化するツールについて説明します。

8. データの可視化

この章では、データの可視化に関連するツールや技術について説明します。具体的には、Prisma Studio と、スキーマから ER 図を生成する方法について説明します。

8.1. Prisma Studio を使ったデータの可視化

Prisma Studio は、npx prisma studioコマンドで起動し、開発者がデータベースを簡単に操作できるように設計されており、データの可視化や管理が容易に行えます。直感的に使用できるので、ぜひ一度試してください。

  • データの閲覧: データベース内の各モデルのレコードを一覧表示し、ページネーションやソートを使ってデータを閲覧できます。

マイグレーションの SQL 分にはなかったposts[]が User テーブルの中にあります。Prisma のスキーマに則した表記になるようです。

  • データの作成: 新しいレコードを追加できます。入力フォームはモデルの定義に基づいて自動的に生成されます。

  • データの更新: 既存のレコードを編集して更新できます。編集画面はモデルの定義に基づいて自動的に生成されます。

  • データの削除: レコードを削除できます。削除前に確認ダイアログが表示されます。

8.2. スキーマから ER 図の生成

データベースのスキーマを理解する際、ER 図(Entity Relationship Diagram)が役立ちます。ER 図は、データベース内のエンティティ(モデル)とそれらの関連(リレーション)を視覚的に表現したものです。

Prisma スキーマから ER 図を生成するには、サードパーティ製のツールを使用することができます。以下は、一般的な ER 図生成ツールの例です。

  • Prisma DBML Generator: Prisma スキーマから DBML(Database Markup Language)ファイルを生成し、それを dbdiagram.io などのツールで ER 図に変換することができます。

  • Prisma Entity Relationship Diagram Generator: Prisma スキーマから svg ファイルや mermaid js 形式の md ファイルとして ER 図に変換することができます。

    これらのツールを使って、Prisma スキーマから ER 図を生成し、データベース設計を視覚的に理解することができます。

以下に、DBML Generator を使用した場合の設定と出力ファイル・ER 図を示します。

下記コマンドでインストールします。

npm install -D prisma-dbml-generator

shcema.prismaファイルに以下の設定を追記します。

prisma/schema.prisma
generator erd {
  provider = "prisma-dbml-generator"
}

下記コマンドで、生成します。

npx prisma generate

デフォルトの設定では、下記のように dbml ファイルが出力されます。
マイグレーションの SQL 分にはなかったposts[]が User テーブルの中にあります。ま他、Post テーブルにauthorカラムがあります。ER 図は、Prisma のスキーマに則した表現になるようです。

//// ------------------------------------------------------
//// THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)
//// ------------------------------------------------------

Table User {
  id Int [pk, increment]
  email String [unique, not null]
  name String
  posts Post [not null]
}

Table Post {
  id Int [pk, increment]
  title String [not null]
  content String
  published Boolean [not null, default: false]
  author User [not null]
  authorId Int [not null]
}

Ref: Post.authorId > User.id

上記ファイルから、dbdiagram.ioを利用することで、下記のような ER 図を取得できます。

参考:
prisma の ER 図を mermaid 形式で吐くには

9. まとめ

この記事では、Prisma の基礎と Prisma を利用した開発ワークフローを紹介しました。
本記事を参考にして、Prisma を使った API 開発を始めてみてください。

Appendix: Prisma と GraphQL を使った API 開発

Prisma は TypeScript を使ったプロジェクトで頻繁に使用されます。この章では、TypeScript を使って Prisma と GraphQL を使った API を開発する方法について説明します。

Prisma と GraphQL を組み合わせて使用するには、まず GraphQL サーバーをセットアップする必要があります。以下は、Apollo Server を使用した GraphQL サーバーのセットアップ例です。

上記 prisma のディレクトリに、追加で必要なパッケージをインストールします。

npm install apollo-server graphql

GraphQL サーバーを作成し、リゾルバとスキーマを定義します。
src/graphql.ts に以下の内容を記述します。

src/graphql.ts
import { ApolloServer, gql } from "apollo-server";
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

const typeDefs = gql`
  type Query {
    allUsers: [User!]!
  }

  type User {
    id: Int!
    name: String!
  }
`;

const resolvers = {
  Query: {
    allUsers: async () => {
      return await prisma.user.findMany();
    },
  },
};

const server = new ApolloServer({
  typeDefs,
  resolvers,
});

server.listen().then(({ url }) => {
  console.log(`🚀  Server ready at ${url}`);
});

下記コマンドで実行します。

npx ts-node src/graphql.ts

ブラウザから、http://localhost:4000/にアクセスすると、User 情報を取得できます。

まず、Query your serverをクリックします。

Operation のところに、取得したいデータを記載し、実行ボタンを押すとデータを取得できます。

これで、クライアントからの GraphQL クエリを受け取り、Prisma クライアントを使ってデータベースとやり取りすることができます。
是非、他のドキュメントも参照しながら、Prisma を活用し GraphQL API の開発に取り組んでください。

参考:
GraphQL と相性の良い ORM Prisma - Qiita

あとがき

本記事は、ChatGPT と対話しながら文章を生成し、一部修正した上で公開しています。
非常に面白い経験だったので、感想を共有しておこうと思います。

  • かなりに長い文章になったので、ChatGPT がいなければ、書く気が起きなかったと思います。アウトプットの心理的ハードルが下がった気がします。
  • 文体はあまり自分の好みではないですが、修正するのも大変なので基本的にそのまま使いました。最初にいい感じの指示を出せば改善できる気がします。
  • アウトプットすることで自分の理解が深まるのは疑いのないところだと思いますが、ChatGPT にアウトプットしてもらうことでも理解は深まった気がします。
  • 平気で嘘をつくので、自分の理解以上のことは書けないと思います。
  • 「内容は本当に正しいのか」「理解しやすい流れになっているか」「抜け漏れ・冗長なところはないか」を気にしながら修正することで学びがあるんじゃないかと思います。
  • 「読めばわかる」程度の理解でもアウトプットできるようになったのが画期的だと思います。

ChatGPT の能力をまだまだ活かしきれてないと思うので、そのうち他の記事も書いて、ChatGPT 力を磨いていこうと思います。

GitHubで編集を提案

Discussion