| name | nestjs_specialist |
| router_kit | DevOpsKit |
| description | Comprehensive NestJS framework guide with Drizzle ORM integration. Use when building NestJS applications, setting up APIs, implementing authentication, working with databases, or integrating Drizzle ORM. Covers controllers, providers, modules, middleware, guards, interceptors, testing, microservices, GraphQL, and database patterns. |
| license | Complete terms in LICENSE.txt |
| metadata | {"skillport":{"category":"auto-healed","tags":["architecture","automation","backend framework","best practices","clean code","coding","collaboration","compliance","debugging","decorators","dependency injection","design patterns","development","documentation","efficiency","git","modules","nestjs specialist","optimization","productivity","programming","project management","quality assurance","refactoring","software engineering","standards","testing","typescript","utilities","version control","workflow"]}} |
NestJS Framework with Drizzle ORM
When to Use
- Building REST APIs or GraphQL servers with NestJS
- Setting up authentication and authorization
- Implementing middleware, guards, or interceptors
- Working with databases (TypeORM, Drizzle ORM)
- Creating microservices architecture
- Writing unit and integration tests
- Setting up OpenAPI/Swagger documentation
Core Architecture
Module Structure
import { Module } from '@nestjs/common';
@Module({
imports: [],
controllers: [],
providers: [],
exports: [],
})
export class FeatureModule {}
Controller Pattern
import { Controller, Get, Post, Body, Param, Query } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Get()
findAll(@Query() query: any) {
return 'This returns all users';
}
@Get(':id')
findOne(@Param('id') id: string) {
return `This returns user #${id}`;
}
@Post()
create(@Body() createUserDto: any) {
return 'This creates a user';
}
}
Service with Dependency Injection
import { Injectable } from '@nestjs/common';
@Injectable()
export class UsersService {
constructor() {}
findAll() {
return 'Users service logic';
}
}
Database Integration with Drizzle
Setup with Drizzle ORM
Installation
npm install drizzle-orm pg
npm install -D drizzle-kit tsx @types/pg
yarn add drizzle-orm pg
yarn add -D drizzle-kit tsx @types/pg
Configuration
import 'dotenv/config';
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
out: './drizzle',
schema: './src/db/schema.ts',
dialect: 'postgresql',
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});
Database Schema
import { pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';
export const users = pgTable('users', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
email: text('email').notNull().unique(),
createdAt: timestamp('created_at').defaultNow(),
});
Database Service
import { Injectable } from '@nestjs/common';
import { drizzle } from 'drizzle-orm/node-postgres';
import { Pool } from 'pg';
import * as schema from './schema';
@Injectable()
export class DatabaseService {
private db: ReturnType<typeof drizzle>;
constructor() {
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
});
this.db = drizzle(pool, { schema });
}
get database() {
return this.db;
}
}
User Repository with Drizzle
import { Injectable } from '@nestjs/common';
import { DatabaseService } from '../db/database.service';
import { users } from '../db/schema';
import { eq } from 'drizzle-orm';
@Injectable()
export class UserRepository {
constructor(private db: DatabaseService) {}
async findAll() {
return this.db.database.select().from(users);
}
async findOne(id: number) {
const result = await this.db.database
.select()
.from(users)
.where(eq(users.id, id))
.limit(1);
return result[0];
}
async () {
result = ..
.(users)
.(data)
.();
result[];
}
() {
result = ..
.(users)
.(data)
.((users., id))
.();
result[];
}
() {
result = ..
.(users)
.((users., id))
.();
result[];
}
}
Complete User Module
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { UserRepository } from './user.repository';
import { DatabaseService } from '../db/database.service';
@Module({
controllers: [UsersController],
providers: [UsersService, UserRepository, DatabaseService],
exports: [UsersService],
})
export class UsersModule {}
User Service Implementation
import { Injectable } from '@nestjs/common';
import { UserRepository } from './user.repository';
import { User } from './interfaces/user.interface';
@Injectable()
export class UsersService {
constructor(private userRepository: UserRepository) {}
async findAll(): Promise<User[]> {
return this.userRepository.findAll();
}
async findOne(id: number): Promise<User> {
const user = await this.userRepository.findOne(id);
if (!user) {
throw new Error('User not found');
}
return user;
}
async create(userData: Partial<User>): <> {
..(userData);
}
(: , : <>): <> {
.(id);
..(id, userData);
}
(: ): <> {
.(id);
..(id);
}
}
Authentication & Authorization
JWT Authentication Guard
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
@Injectable()
export class JwtAuthGuard implements CanActivate {
constructor(private jwtService: JwtService) {}
canActivate(context: ExecutionContext) {
const request = context.switchToHttp().getRequest();
const token = request.headers.authorization?.split(' ')[1];
if (!token) {
return false;
}
try {
const decoded = this.jwtService.verify(token);
request.user = decoded;
return true;
} catch {
return false;
}
}
}
Roles-Based Guard
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.get<string[]>('roles', context.getHandler());
if (!requiredRoles) {
return true;
}
const { user } = context.switchToHttp().getRequest();
return requiredRoles.some((role) => user.roles?.includes(role));
}
}
Validation with Pipes
Validation Pipe
import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
import { validate } from 'class-validator';
import { plainToClass } from 'class-transformer';
@Injectable()
export class ValidationPipe implements PipeTransform {
async transform(value: any, { metatype }: ArgumentMetadata) {
if (!metatype || !this.toValidate(metatype)) {
return value;
}
const object = plainToClass(metatype, value);
const errors = await validate(object);
if (errors.length > 0) {
throw new BadRequestException(errors);
}
return value;
}
private toValidate(metatype: Function): boolean {
const types: [] = [, , , , ];
!types.(metatype);
}
}
Exception Handling
Global Exception Filter
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const status = exception.getStatus();
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
message: exception.message,
});
}
}
Testing Patterns
Unit Testing Services
import { Test, TestingModule } from '@nestjs/testing';
import { UsersService } from './users.service';
import { UserRepository } from './user.repository';
describe('UsersService', () => {
let service: UsersService;
let repository: jest.Mocked<UserRepository>;
beforeEach(async () => {
const mockRepository = {
findAll: jest.fn(),
findOne: jest.fn(),
create: jest.fn(),
update: jest.fn(),
remove: jest.fn(),
} as any;
const module: TestingModule = await Test.createTestingModule({
providers: [
UsersService,
{
provide: UserRepository,
useValue: mockRepository,
},
],
}).compile();
service = .<>();
repository = .();
});
(, () => {
expectedUsers = [{ : , : , : }];
repository..(expectedUsers);
result = service.();
(result).(expectedUsers);
(repository.).();
});
});
E2E Testing with Drizzle
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
import * as request from 'supertest';
import { AppModule } from './../src/app.module';
import { DatabaseService } from '../src/db/database.service';
import { drizzle } from 'drizzle-orm/node-postgres';
import { migrate } from 'drizzle-node-postgres/migrator';
import { migrate as drizzleMigrate } from 'drizzle-orm/node-postgres/migrator';
describe('UsersController (e2e)', () => {
let app: INestApplication;
let db: DatabaseService;
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).();
app = moduleFixture.();
db = moduleFixture.<>();
(db., { : });
app.();
});
( () => {
app.();
});
( () => {
db..(users).();
});
(, {
createUserDto = {
: ,
: ,
};
(app.())
.()
.(createUserDto)
.()
.( {
(res.).(createUserDto);
(res.).();
});
});
(, () => {
db..(users).({
: ,
: ,
});
(app.())
.()
.()
.( {
(.(res.)).();
(res.).();
});
});
});
Migrations with Drizzle
Generating Migrations
npx drizzle-kit generate
Running Migrations
import { Injectable } from '@nestjs/common';
import { migrate } from 'drizzle-orm/node-postgres/migrator';
import { DatabaseService } from '../db/database.service';
@Injectable()
export class MigrationService {
constructor(private db: DatabaseService) {}
async runMigrations() {
try {
await migrate(this.db.database, { migrationsFolder: './drizzle' });
console.log('Migrations completed successfully');
} catch (error) {
console.error('Migration failed:', error);
throw error;
}
}
}
Configuration Management
Environment Configuration
export default () => ({
database: {
url: process.env.DATABASE_URL,
},
jwt: {
secret: process.env.JWT_SECRET || 'default-secret',
expiresIn: process.env.JWT_EXPIRES_IN || '24h',
},
app: {
port: parseInt(process.env.PORT, 10) || 3000,
},
});
Advanced Patterns
Custom Decorators
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
export const User = createParamDecorator(
(data: string, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
const user = request.user;
return data ? user?.[data] : user;
},
);
Interceptors for Logging
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const request = context.switchToHttp().getRequest();
const { method, url } = request;
const now = Date.now();
console.log(`[${method}] ${url} - Start`);
return next
.handle()
.pipe(
tap(() => console.log(`[${method}] ${url} - End ${Date.now() - now}ms`)),
);
}
}
Microservices
TCP Microservice
import { NestFactory } from '@nestjs/core';
import { Transport, MicroserviceOptions } from '@nestjs/microservices';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
AppModule,
{
transport: Transport.TCP,
options: {
host: 'localhost',
port: 8877,
},
},
);
await app.listen();
}
bootstrap();
GraphQL Integration
GraphQL Resolver with Drizzle
import { Resolver, Query, Mutation, Args } from '@nestjs/graphql';
import { UserRepository } from './user.repository';
@Resolver(() => User)
export class UsersResolver {
constructor(private userRepository: UserRepository) {}
@Query(() => [User])
async users() {
return this.userRepository.findAll();
}
@Mutation(() => User)
async createUser(@Args('input') input: CreateUserInput) {
return this.userRepository.create(input);
}
}
Best Practices
- Always use constructor injection - Never use property injection
- Use DTOs for data transfer - Define interfaces for request/response
- Implement proper error handling - Use exception filters
- Validate all inputs - Use validation pipes
- Keep modules focused - Single responsibility principle
- Use environment variables - Never hardcode credentials
- Write comprehensive tests - Unit and integration tests
- Use transactions for complex operations - Maintain data consistency
- Implement proper logging - Use interceptors for cross-cutting concerns
- Use type safety - Leverage TypeScript features
Common Patterns with Drizzle
Transactions
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));
});
}
Soft Deletes
export const users = pgTable('users', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
email: text('email').notNull().unique(),
deletedAt: timestamp('deleted_at'),
});
async softDelete(id: number) {
return this.db.database
.update(users)
.set({ deletedAt: new Date() })
.where(eq(users.id, id));
}
Complex Queries with Relations
async getUsersWithPosts() {
return this.db.database
.select()
.from(users)
*NestJS Specialist v1.1 - Enhanced*
## 🔄 Workflow
> **Kaynak:** [NestJS Documentation](https:
### Aşama 1: Module Design
- [ ] **Boundary**: Her özellik (Feature) için ayrı bir modül oluştur (UserModule, AuthModule).
- [ ] **DI Types**: "Interface-based" injection kullanmak test edilebilirliği artırır (Provider token kullan).
- [ ] **Config**: `ConfigModule` ve `Joi` validasyonu ile ortam değişkenlerini güvene al.
### Aşama 2: Data Access (Drizzle)
- [ ] **Repo Pattern**: Drizzle kodunu doğrudan Service'e yazma, Repository katmanına soyutla.
- [ ] **Transactions**: İş mantığı gerektirdiğinde `db.transaction()` ile atomikliği sağla.
- [ ] **Migrations**: Şema değişiklikleri için mutlaka migration dosyası oluştur ve versiyonla.
### Aşama 3: Security & Stability
- [ ] **Guards**: Role-based access control (RBAC) için global veya route-bazlı guardları kur.
- [ ] **Interceptors**: Response formatını standardize et (`{ data: ..., meta: ... }`).
- [ ] **Filters**: Global Exception Filter ile hata mesajlarını kullanıcı dostu hale getir (500 hatalarını gizle).
### Kontrol Noktaları
| Aşama | Doğrulama |
|-------|-----------|
| 1 | Döngüsel bağımlılık (Circular Dependency) var mı? |
| 2 | Tüm inputlar DTO ve `class-validator` ile kontrol ediliyor mu? |
| 3 | Controller'lar , te mi?) |