PrismaでGraphQL APIを自動生成しよう - チュートリアル

1. はじめに

このチュートリアルでは、Prismaのスキーマ定義から型安全なGraphQL APIを自動生成する方法を学びます。

完成イメージ

前提条件

2. プロジェクトのセットアップ

まずは必要なツールとライブラリをインストールします:

# プロジェクトの作成
mkdir prisma-graphql-generator
cd prisma-graphql-generator

# package.jsonの初期化
npm init -y

# 必要なパッケージのインストール
npm install @prisma/client apollo-server graphql
npm install -D prisma typescript ts-node-dev @types/node typegraphql-prisma type-graphql reflect-metadata

TypeScript?の設定ファイルを作成:

# TypeScript設定ファイルの生成
npx tsc --init

`tsconfig.json`を以下のように編集:

{
  "compilerOptions": {
    "target": "es2018",
    "module": "commonjs",
    "lib": ["es2018", "esnext.asynciterable"],
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "strictPropertyInitialization": false,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "strict": true,
    "outDir": "./dist"
  }
}

3. Prismaの設定

Prismaを初期化し、スキーマを定義します:

# Prismaの初期化
npx prisma init

`prisma/schema.prisma`を以下のように編集:

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

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

// ここが重要: GraphQL型の自動生成設定
generator typegraphql {
  provider = "typegraphql-prisma"
  output   = "../src/generated/type-graphql"
}

// データモデルの定義
model User {
  id        Int       @id @default(autoincrement())
  email     String    @unique
  name      String
  posts     Post[]
  createdAt DateTime  @default(now())
}

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

データベースの準備:

# マイグレーションの実行
npx prisma migrate dev --name init

# GraphQL型の生成
npx prisma generate

4. サーバーの実装

`src/index.ts`を作成:

import 'reflect-metadata';
import { PrismaClient } from '@prisma/client';
import { ApolloServer } from 'apollo-server';
import { buildSchema } from 'type-graphql';
import { resolvers } from './generated/type-graphql';

async function main() {
  const prisma = new PrismaClient();

  // 自動生成されたリゾルバーを使用してスキーマを構築
  const schema = await buildSchema({
    resolvers,
    validate: false,
  });

  // Apollo Serverの設定
  const server = new ApolloServer({
    schema,
    context: () => ({ prisma }),
  });

  // サーバーの起動
  const { url } = await server.listen(4000);
  console.log(`🚀 Server ready at ${url}`);
}

main().catch(console.error);

`package.json`にスクリプトを追加:

{
  "scripts": {
    "dev": "ts-node-dev --no-notify --respawn --transpile-only src/index.ts",
    "generate": "prisma generate"
  }
}

5. 自動生成されたコードの確認

`npx prisma generate`を実行すると、`src/generated/type-graphql`ディレクトリに以下のファイルが生成されます:

src/generated/type-graphql/
├── enums/          # 列挙型の定義
├── models/         # モデルクラスの定義
├── resolvers/      # 自動生成されたリゾルバー
└── index.ts        # エクスポート定義

生成されるリゾルバーの例:

6. 動作確認

サーバーを起動:

npm run dev

ブラウザで `http://localhost:4000` にアクセスし、以下のクエリを試してみましょう:

ユーザーの作成:

mutation {
  createUser(data: {
    email: "test@example.com"
    name: "Test User"
  }) {
    id
    email
    name
  }
}

投稿の作成:

mutation {
  createPost(data: {
    title: "First Post"
    content: "Hello, World!"
    published: true
    author: {
      connect: { id: 1 }
    }
  }) {
    id
    title
    author {
      name
    }
  }
}

データの取得:

query {
  users {
    id
    name
    posts {
      title
      content
      published
    }
  }
}

7. 生成されたコードのカスタマイズ

自動生成されたコードに独自の機能を追加することもできます:

// src/resolvers/CustomUserResolver.ts
import { Resolver, Query, Ctx } from 'type-graphql';
import { User } from '../generated/type-graphql';

@Resolver(User)
export class CustomUserResolver {
  @Query(returns => [User])
  async activeUsers(@Ctx() ctx: any) {
    return ctx.prisma.user.findMany({
      where: {
        posts: {
          some: {
            published: true
          }
        }
      }
    });
  }
}

8. まとめ

次のステップ

トラブルシューティング

よくある問題: 1. 型が生成されない

  → `npx prisma generate`を実行

2. デコレータエラー

  → `tsconfig.json`の設定を確認

3. 実行時エラー

  → `reflect-metadata`のインポートを確認
トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2024-11-06 (水) 15:09:25 (131d)