mcpField
N
nestjs

nestjs

github.com/giuseppe-trisciuoglio開発3654.2k 回インストール7 週間前に更新
リポジトリ

nestjs について

NestJSとDrizzle ORMによるサーバーアプリケーション開発のパターン集です。REST API、GraphQL、マイクロサービスを扱う開発者向けに、CRUD、JWT、マイグレーション、テストなどを説明します。

主な機能

  1. 01NestJSとDrizzle ORMの設定
  2. 02CRUDモジュールとレイヤー構成
  3. 03JWTとロールガード
  4. 04データベーストランザクションとマイグレーション
  5. 05単体テストと統合テスト
  6. 06マイクロサービスとGraphQLのパターン

活用シーン

  1. 01REST APIまたはGraphQLサーバーの構築
  2. 02JWT認証と認可の実装
  3. 03データベース操作とマイグレーション
  4. 04TCPまたはRedisマイクロサービスの開発

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill nestjs

インストール後、Claude Code で/nestjsを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
best-practices.md
drizzle-reference.md
migrations.md
patterns.md
reference.md
testing.md
workflow-optimization.md

詳細

Drizzle ORM を使用した NestJS フレームワーク

概要

本番環境に対応したサーバーサイドアプリケーションの構築に向けて、Drizzle ORM を使用する NestJS のパターンを提供します。CRUD モジュール、JWT 認証、データベース操作、マイグレーション、テスト、マイクロサービス、GraphQL 連携を網羅しています。

使用する場面

  • NestJS で REST API または GraphQL サーバーを構築する場合
  • JWT を使用して認証と認可を設定する場合
  • Drizzle ORM を使用してデータベース操作を実装する場合
  • TCP/Redis トランスポートを使用してマイクロサービスを作成する場合
  • 単体テストと統合テストを作成する場合
  • drizzle-kit でデータベースのマイグレーションを実行する場合

手順

  1. 依存関係をインストールする:npm i drizzle-orm pg && npm i -D drizzle-kit tsx
  2. スキーマを定義する:Drizzle のテーブル定義を記述した src/db/schema.ts を作成します
  3. DatabaseService を作成する:Drizzle クライアントを NestJS のプロバイダーとして注入します
  4. CRUD モジュールを構築する:Controller → Service → Repository のパターンを使用します
  5. バリデーションを追加する:ValidationPipe と class-validator の DTO を使用します
  6. ガードを実装する:ルートを保護する JWT/ロールガードを作成します
  7. テストを作成する:モックしたリポジトリを使い、@nestjs/testing を使用します
  8. マイグレーションを実行する:npx drizzle-kit generate → SQL を検証する → npx drizzle-kit migrate

例

Drizzle を使用した完全な CRUD モジュール
// src/db/schema.ts
export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  email: text('email').notNull().unique(),
  createdAt: timestamp('created_at').defaultNow(),
});

// src/users/dto/create-user.dto.ts
export class CreateUserDto {
  @IsString() @IsNotEmpty() name: string;
  @IsEmail() email: string;
}

// src/users/user.repository.ts
@Injectable()
export class UserRepository {
  constructor(private db: DatabaseService) {}

  async findAll() {
    return this.db.database.select().from(users);
  }

  async create(data: typeof users.$inferInsert) {
    return this.db.database.insert(users).values(data).returning();
  }
}

// src/users/users.service.ts
@Injectable()
export class UsersService {
  constructor(private repo: UserRepository) {}

  async create(dto: CreateUserDto) {
    return this.repo.create(dto);
  }
}

// src/users/users.controller.ts
@Controller('users')
export class UsersController {
  constructor(private service: UsersService) {}

  @Post()
  create(@Body() dto: CreateUserDto) {
    return this.service.create(dto);
  }
}

// src/users/users.module.ts
@Module({
  controllers: [UsersController],
  providers: [UsersService, UserRepository, DatabaseService],
  exports: [UsersService],
})
export class UsersModule {}
JWT 認証ガード
@Injectable()
export class JwtAuthGuard implements CanActivate {
  constructor(private jwtService: JwtService) {}

  canActivate(context: ExecutionContext) {
    const token = context.switchToHttp().getRequest()
      .headers.authorization?.split(' ')[1];
    if (!token) return false;
    try {
      const decoded = this.jwtService.verify(token);
      context.switchToHttp().getRequest().user = decoded;
      return true;
    } catch {
      return false;
    }
  }
}
データベーストランザクション
async transferFunds(fromId: number, toId: number, amount: number) {
  return this.db.database.transaction(async (tx) => {
    await tx.update(accounts)
      .set({ balance: sql`${accounts.balance} - ${amount}` })
      .where(eq(accounts.id, fromId));
    await tx.update(accounts)
      .set({ balance: sql`${accounts.balance} + ${amount}` })
      .where(eq(accounts.id, toId));
  });
}
モックを使用した単体テスト
describe('UsersService', () => {
  let service: UsersService;
  let repo: jest.Mocked<UserRepository>;

  beforeEach(async () => {
    const module = await Test.createTestingModule({
      providers: [
        UsersService,
        { provide: UserRepository, useValue: { findAll: jest.fn(), create: jest.fn() } },
      ],
    }).compile();
    service = module.get(UsersService);
    repo = module.get(UserRepository);
  });

  it('should create user', async () => {
    const dto = { name: 'John', email: '[email protected]' };
    repo.create.mockResolvedValue({ id: 1, ...dto, createdAt: new Date() });
    expect(await service.create(dto)).toMatchObject(dto);
  });
});

制約と警告

  • DTO が必須:常に class-validator の DTO を使用し、生のオブジェクトを受け取らないでください
  • トランザクション:トランザクションは短く保ち、ネストしたトランザクションは避けてください
  • ガードの順序:JWT ガードはロールガードより先に実行する必要があります
  • 環境変数:DATABASE_URL や JWT_SECRET をハードコードしないでください
  • マイグレーション:スキーマを変更した後、デプロイ前に drizzle-kit generate を実行してください
  • 循環依存:forwardRef() は慎重に使用し、モジュールの再構成を優先してください

ベストプラクティス

  • グローバルな ValidationPipe ですべての入力を検証します
  • 複数のテーブルを操作する場合はトランザクションを使用します
  • OpenAPI/Swagger デコレーターで API をドキュメント化します

参考資料

高度なパターンと詳細な例については、以下を参照してください。

  • references/reference.md - コアパターン、ガード、インターセプター、マイクロサービス、GraphQL
  • references/drizzle-reference.md - Drizzle ORM のインストール、設定、クエリ
  • references/workflow-optimization.md - 開発ワークフロー、並列実行戦略

コメント