Appearance
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
| Kebutuhan | Command |
|---|---|
| Membuat proyek NestJS | nest new nestjs-task-management |
| Membuat module | nest g module tasks |
| Membuat controller tanpa spec | nest g controller tasks --no-spec |
| Membuat service tanpa spec | nest g service tasks --no-spec |
| Menjalankan dev server | yarn start:dev |
| Menjalankan test | yarn test |
| Menjalankan test watch mode | yarn test --watch |
| Menjalankan PostgreSQL via Docker | docker run --name postgres-nest -p 5432:5432 -e POSTGRES_PASSWORD=postgres -d postgres |
Decorator NestJS yang Sering Muncul
| Decorator | Dipakai di | Fungsi |
|---|---|---|
@Module() | Class module | Mengelompokkan controller, provider, import, dan export |
@Controller('tasks') | Class controller | Menentukan route dasar controller |
@Injectable() | Service/provider | Menjadikan class bisa di-inject oleh NestJS |
@Get() | Method controller | Handler untuk HTTP GET |
@Post() | Method controller | Handler untuk HTTP POST |
@Patch() | Method controller | Handler untuk partial update |
@Delete() | Method controller | Handler untuk delete |
@Body() | Parameter handler | Mengambil request body |
@Param() | Parameter handler | Mengambil path parameter |
@Query() | Parameter handler | Mengambil query string |
@UseGuards() | Controller atau handler | Melindungi route dengan guard |
Decorator Validasi
| Decorator | Fungsi |
|---|---|
@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 JSONPola Response Error
| Kondisi | Exception | Status |
|---|---|---|
| Input tidak valid | BadRequestException atau ValidationPipe | 400 |
| Data tidak ditemukan | NotFoundException | 404 |
| Credential salah | UnauthorizedException | 401 |
| Username sudah dipakai | ConflictException | 409 |
| Error tidak terduga | InternalServerErrorException | 500 |
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 / Class | Dipakai di | Fungsi |
|---|---|---|
@UseGuards(AuthGuard()) | Controller / handler | Melindungi route agar hanya bisa diakses dengan JWT valid |
@GetUser() | Parameter handler | Decorator custom untuk mengambil user dari request (dari JWT) |
@InjectRepository() | Constructor service | Inject TypeORM repository ke dalam service |
@CreateDateColumn() | Entity property | Otomatis mengisi tanggal saat baris dibuat |
@OneToMany() | Entity property | Relasi satu entitas memiliki banyak entitas lain |
@ManyToOne() | Entity property | Relasi banyak entitas dimiliki satu entitas lain |
@Exclude() | Entity property | Menyembunyikan 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