nestjs について
NestJSとDrizzle ORMによるサーバーアプリケーション開発のパターン集です。REST API、GraphQL、マイクロサービスを扱う開発者向けに、CRUD、JWT、マイグレーション、テストなどを説明します。
主な機能
- 01NestJSとDrizzle ORMの設定
- 02CRUDモジュールとレイヤー構成
- 03JWTとロールガード
- 04データベーストランザクションとマイグレーション
- 05単体テストと統合テスト
- 06マイクロサービスとGraphQLのパターン
活用シーン
- 01REST APIまたはGraphQLサーバーの構築
- 02JWT認証と認可の実装
- 03データベース操作とマイグレーション
- 04TCPまたはRedisマイクロサービスの開発
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ giuseppe-trisciuoglio/ developer-kit --skill nestjsインストール後、Claude Code で/nestjsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/best-practices.mddrizzle-reference.mdmigrations.mdpatterns.mdreference.mdtesting.mdworkflow-optimization.md詳細
Drizzle ORM を使用した NestJS フレームワーク
概要
本番環境に対応したサーバーサイドアプリケーションの構築に向けて、Drizzle ORM を使用する NestJS のパターンを提供します。CRUD モジュール、JWT 認証、データベース操作、マイグレーション、テスト、マイクロサービス、GraphQL 連携を網羅しています。
使用する場面
- NestJS で REST API または GraphQL サーバーを構築する場合
- JWT を使用して認証と認可を設定する場合
- Drizzle ORM を使用してデータベース操作を実装する場合
- TCP/Redis トランスポートを使用してマイクロサービスを作成する場合
- 単体テストと統合テストを作成する場合
- drizzle-kit でデータベースのマイグレーションを実行する場合
手順
- 依存関係をインストールする:
npm i drizzle-orm pg && npm i -D drizzle-kit tsx - スキーマを定義する:Drizzle のテーブル定義を記述した
src/db/schema.tsを作成します - DatabaseService を作成する:Drizzle クライアントを NestJS のプロバイダーとして注入します
- CRUD モジュールを構築する:Controller → Service → Repository のパターンを使用します
- バリデーションを追加する:ValidationPipe と class-validator の DTO を使用します
- ガードを実装する:ルートを保護する JWT/ロールガードを作成します
- テストを作成する:モックしたリポジトリを使い、
@nestjs/testingを使用します - マイグレーションを実行する:
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- コアパターン、ガード、インターセプター、マイクロサービス、GraphQLreferences/drizzle-reference.md- Drizzle ORM のインストール、設定、クエリreferences/workflow-optimization.md- 開発ワークフロー、並列実行戦略
コメント
Markdown 対応