Skip to content

Cheatsheet NestJS

Halaman ini merangkum command, decorator, dan pola kode yang paling sering muncul di materi. Gunakan sebagai referensi cepat ketika Anda sedang praktik.

Command Utama

KebutuhanCommand
Membuat proyek NestJSnest new nestjs-task-management
Membuat modulenest g module tasks
Membuat controller tanpa specnest g controller tasks --no-spec
Membuat service tanpa specnest g service tasks --no-spec
Menjalankan dev serveryarn start:dev
Menjalankan testyarn test
Menjalankan test watch modeyarn test --watch
Menjalankan PostgreSQL via Dockerdocker run --name postgres-nest -p 5432:5432 -e POSTGRES_PASSWORD=postgres -d postgres

Decorator NestJS yang Sering Muncul

DecoratorDipakai diFungsi
@Module()Class moduleMengelompokkan controller, provider, import, dan export
@Controller('tasks')Class controllerMenentukan route dasar controller
@Injectable()Service/providerMenjadikan class bisa di-inject oleh NestJS
@Get()Method controllerHandler untuk HTTP GET
@Post()Method controllerHandler untuk HTTP POST
@Patch()Method controllerHandler untuk partial update
@Delete()Method controllerHandler untuk delete
@Body()Parameter handlerMengambil request body
@Param()Parameter handlerMengambil path parameter
@Query()Parameter handlerMengambil query string
@UseGuards()Controller atau handlerMelindungi route dengan guard

Decorator Validasi

DecoratorFungsi
@IsNotEmpty()Nilai wajib ada dan tidak kosong
@IsEnum(TaskStatus)Nilai harus termasuk enum tertentu
@IsString()Nilai harus string
@IsOptional()Field boleh tidak dikirim, tetapi tetap divalidasi jika ada
@MinLength()Panjang minimal string
@MaxLength()Panjang maksimal string
@Matches()Validasi string menggunakan regular expression

Pola Layering

text
Client Request
  -> Controller: menerima HTTP request dan mengambil param/body/query
  -> DTO/Pipe: memvalidasi bentuk input
  -> Service: menjalankan business logic
  -> Repository: berinteraksi dengan database
  -> Entity: representasi table database
  -> Response: dikembalikan oleh NestJS sebagai JSON

Pola Response Error

KondisiExceptionStatus
Input tidak validBadRequestException atau ValidationPipe400
Data tidak ditemukanNotFoundException404
Credential salahUnauthorizedException401
Username sudah dipakaiConflictException409
Error tidak terdugaInternalServerErrorException500

Formula Praktis

typescript
constructor(private readonly tasksService: TasksService) {}

Gunakan constructor injection untuk dependency. Jangan membuat instance service manual dengan new, karena itu melewati dependency injection container NestJS.

typescript
@Post()
createTask(@Body() createTaskDto: CreateTaskDto) {
  return this.tasksService.createTask(createTaskDto)
}

Controller cukup menerima request dan menyerahkan pekerjaan ke service. Detail validasi, persistence, dan business rules sebaiknya tidak menumpuk di controller.

Decorator Authentication dan Authorization

Decorator / ClassDipakai diFungsi
@UseGuards(AuthGuard())Controller / handlerMelindungi route agar hanya bisa diakses dengan JWT valid
@GetUser()Parameter handlerDecorator custom untuk mengambil user dari request (dari JWT)
@InjectRepository()Constructor serviceInject TypeORM repository ke dalam service
@CreateDateColumn()Entity propertyOtomatis mengisi tanggal saat baris dibuat
@OneToMany()Entity propertyRelasi satu entitas memiliki banyak entitas lain
@ManyToOne()Entity propertyRelasi banyak entitas dimiliki satu entitas lain
@Exclude()Entity propertyMenyembunyikan field dari serialisasi JSON (class-transformer)

Logging — Referensi Cepat

typescript
// Instansiasi logger (dalam class)
private logger = new Logger('NamaClass')

// Level-level log
this.logger.log('Pesan info umum')
this.logger.verbose('Detail aktivitas rutin')
this.logger.debug('Info debug untuk developer')
this.logger.warn('Peringatan non-fatal')
this.logger.error('Error fatal', error.stack)  // selalu sertakan stack trace

// Pola try/catch yang benar di repository
try {
  return await query.getMany()
} catch (error) {
  this.logger.error('Gagal mengambil data', error.stack)
  throw new InternalServerErrorException()
}

Configuration — Referensi Cepat

typescript
// Mendaftarkan ConfigModule (app.module.ts)
ConfigModule.forRoot({
  envFilePath: `.env.stage.${process.env.STAGE}`,
  validationSchema: configValidationSchema,  // opsional tapi direkomendasikan
})

// Membaca nilai konfigurasi (dalam constructor)
constructor(private configService: ConfigService) {}
const dbHost = this.configService.get<string>('DB_HOST')

// Inisialisasi modul yang bergantung pada ConfigService
TypeOrmModule.forRootAsync({
  imports: [ConfigModule],
  inject: [ConfigService],
  useFactory: async (config: ConfigService) => ({
    type: 'postgres',
    host: config.get('DB_HOST'),
    // ...
  }),
})

TypeORM — Relasi dan Query Builder

typescript
// Relasi one-to-many / many-to-one
@OneToMany((_type) => Task, (task) => task.user, { eager: false })
tasks: Task[]

@ManyToOne((_type) => User, (user) => user.tasks, { eager: true })
user: User

// Query builder dengan filter dan pembatasan user
const query = this.createQueryBuilder('task')
query.where({ user })                               // filter per user
query.andWhere('task.status = :status', { status }) // filter tambahan
query.andWhere(                                     // selalu bungkus OR
  '(task.title LIKE :search OR task.description LIKE :search)',
  { search: `%${search}%` },
)
return query.getMany()

Unit Testing — Referensi Cepat

typescript
// Struktur dasar test file
describe('TasksService', () => {
  let service: TasksService
  let repository

  const mockRepo = () => ({ findOne: jest.fn(), save: jest.fn(), delete: jest.fn() })

  beforeEach(async () => {
    const module = await Test.createTestingModule({
      providers: [
        TasksService,
        { provide: TasksRepository, useFactory: mockRepo },
      ],
    }).compile()

    service = module.get<TasksService>(TasksService)
    repository = module.get<TasksRepository>(TasksRepository)
  })

  it('should return a task when found', async () => {
    repository.findOne.mockResolvedValue(mockTask)
    const result = await service.getTaskById('id', mockUser)
    expect(result).toEqual(mockTask)
  })

  it('should throw NotFoundException when not found', async () => {
    repository.findOne.mockResolvedValue(null)
    await expect(service.getTaskById('id', mockUser)).rejects.toThrow(NotFoundException)
  })
})

File .env yang Wajib Ada

bash
# .env.stage.dev
STAGE=dev
DB_HOST=localhost
DB_PORT=5432
DB_USERNAME=postgres
DB_PASSWORD=postgres
DB_DATABASE=task-management
JWT_SECRET=supersecretkey

# .gitignore (pastikan ada baris ini)
.env.stage.prod