Artikel ini tersedia dalam Bahasa Inggris

šŸ‡¬šŸ‡§ Read in English

10 Mei 2026

šŸ‡®šŸ‡© Bahasa Indonesia

Fleet Management Part 3: Backend API dengan NestJS

Membangun backend API yang scalable dengan NestJS dan TypeScript. Modules, controllers, services, DTOs, dependency injection, dan pola clean architecture.

4 min read

Apa itu NestJS?

Jika Anda kenal Express.js, Anda tahu itu seperti kanvas kosong — Anda mengorganisir semuanya sendiri. NestJS adalah Express.js dengan opini dan struktur. NestJS memberi tahu Anda di mana menaruh kode, bagaimana mengorganisir module, dan menyediakan pola bawaan seperti Dependency Injection.

Analogi sederhana:

  • Express.js = Setumpuk batu bata LEGO. Anda bisa membangun apapun, tapi tidak ada buku panduan.
  • NestJS = Set LEGO Technic. Anda tetap punya kebebasan kreatif, tapi ada struktur terbukti untuk diikuti.

Setup Proyek

npm i -g @nestjs/cli
nest new fleet-api
cd fleet-api

Memahami Sistem Module

NestJS mengorganisir kode ke dalam modules. Setiap module adalah fitur yang mandiri. Analoginya:

Aplikasi NestJS seperti perusahaan: ā”œā”€ā”€ Perusahaan (AppModule) — Seluruh organisasi │ ā”œā”€ā”€ Departemen HR (AuthModule) — Menangani karyawan │ ā”œā”€ā”€ Departemen Armada (FleetModule) — Mengelola kendaraan │ ā”œā”€ā”€ Departemen Driver (DriverModule) — Mengelola pengemudi │ └── Departemen IT (SharedModule) — Utilitas bersama

Setiap departemen (module) punya:

  • Controller = Resepsionis. Menerima request dan mendelegasikan pekerjaan.
  • Service = Pekerja. Berisi logika bisnis sebenarnya.
  • Repository = Lemari arsip. Menangani operasi database.

Membangun Fleet Module

Langkah 1: Generate Module

nest generate module fleet
nest generate controller fleet
nest generate service fleet

Langkah 2: Definisikan Entity

// src/fleet/entities/vehicle.entity.ts
@Entity('vehicles')
export class Vehicle {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column({ length: 20, unique: true })
  plateNumber: string;

  @Column({ type: 'enum', enum: VehicleStatus, default: VehicleStatus.OFFLINE })
  status: VehicleStatus;

  @Column({ type: 'decimal', precision: 5, scale: 2, default: 100 })
  fuelLevel: number;

  @CreateDateColumn()
  createdAt: Date;
}

Langkah 3: Buat DTO (Data Transfer Object)

Apa itu DTO? Ini adalah objek sederhana yang mendefinisikan data apa yang diterima API Anda. Pikirkan seperti formulir — jika seseorang mengisi field yang salah, formulir menolaknya sebelum Anda memprosesnya.

// src/fleet/dto/create-vehicle.dto.ts
export class CreateVehicleDto {
  @IsString()
  @Length(3, 20)
  plateNumber: string;

  @IsString()
  @Length(2, 100)
  model: string;

  @IsInt()
  @Min(2000)
  @Max(2030)
  year: number;
}

Langkah 4: Bangun Service

// src/fleet/fleet.service.ts
@Injectable()
export class FleetService {
  constructor(
    @InjectRepository(Vehicle)
    private readonly vehicleRepo: Repository<Vehicle>,
  ) {}

  async findAll(): Promise<Vehicle[]> {
    return this.vehicleRepo.find({ order: { plateNumber: 'ASC' } });
  }

  async findOne(id: string): Promise<Vehicle> {
    const vehicle = await this.vehicleRepo.findOne({ where: { id } });
    if (!vehicle) throw new NotFoundException(`Kendaraan dengan ID "${id}" tidak ditemukan`);
    return vehicle;
  }

  async create(dto: CreateVehicleDto): Promise<Vehicle> {
    const existing = await this.vehicleRepo.findOne({ where: { plateNumber: dto.plateNumber } });
    if (existing) throw new ConflictException(`Kendaraan dengan plat "${dto.plateNumber}" sudah ada`);
    return this.vehicleRepo.save(this.vehicleRepo.create(dto));
  }
}

Langkah 5: Bangun Controller

@Controller('api/vehicles')
export class FleetController {
  constructor(private readonly fleetService: FleetService) {}

  @Get()
  findAll() { return this.fleetService.findAll(); }

  @Get(':id')
  findOne(@Param('id', ParseUUIDPipe) id: string) { return this.fleetService.findOne(id); }

  @Post()
  create(@Body() dto: CreateVehicleDto) { return this.fleetService.create(dto); }
}

Memahami Dependency Injection

Ini konsep yang membingungkan kebanyakan pemula. Biar saya jelaskan dengan sederhana.

Tanpa Dependency Injection:

// āŒ Buruk — service membuat dependensinya sendiri
class FleetService {
  private repo = new VehicleRepository(); // Hardcoded!
}

Dengan Dependency Injection:

// āœ… Baik — dependensi disuntikkan dari luar
@Injectable()
class FleetService {
  constructor(
    private readonly repo: VehicleRepository, // Disuntikkan!
  ) {}
}

Mengapa ini penting?

  1. Testing — Anda bisa menyuntikkan repository palsu untuk testing
  2. Fleksibilitas — Ganti MySQL ke PostgreSQL tanpa mengubah service
  3. Pemisahan — Setiap class fokus pada satu pekerjaan

Pikirkan seperti restoran. Chef (Service) tidak pergi ke ladang untuk mengambil bahan. Bahan-bahan (Dependencies) dikirimkan ke dapur. Ini membuat chef lebih efisien.


Kesalahan Umum

Kesalahan 1: Logika Bisnis di Controller

// āŒ Buruk — controller terlalu banyak bekerja
@Post()
async create(@Body() dto: CreateVehicleDto) {
  const existing = await this.repo.findOne({ where: { plate: dto.plate } });
  if (existing) throw new ConflictException();
  await this.emailService.notify('Kendaraan baru ditambahkan');
  return this.repo.save(this.repo.create(dto));
}

// āœ… Baik — controller mendelegasikan ke service
@Post()
create(@Body() dto: CreateVehicleDto) { return this.fleetService.create(dto); }

Kesalahan 2: Tidak Menggunakan Pipes untuk Validasi

// āœ… Baik — gunakan pipe bawaan
@Get(':id')
findOne(@Param('id', ParseUUIDPipe) id: string) { return this.service.findOne(id); }

Selanjutnya

Di Part 4, kita akan membangun Admin Panel Laravel — antarmuka administrasi yang powerful untuk mengelola pengemudi, invoice, dan jadwal menggunakan Laravel dan Filament.


Ini adalah Part 3 dari seri Fleet Management System. Kita membangun backend API yang bersih dan terstruktur seperti cara developer senior melakukannya.

Lanjut Membaca

Previous article thumbnail

← Artikel Sebelumnya

Fleet Management Part 2: Building the Real-Time Dashboard with Next.js

Artikel Selanjutnya →

Fleet Management Part 4: Admin Panel & Business Logic with Laravel

Next article thumbnail