Monday

18-08-2025 Vol 19

Parameter decorators in NestJS

Memahami Decorator Parameter di NestJS: Panduan Mendalam

NestJS, kerangka kerja progresif Node.js untuk membangun aplikasi sisi server yang efisien, andal, dan mudah diskalakan, menawarkan berbagai fitur canggih untuk menyederhanakan pengembangan. Salah satu fitur yang sangat kuat dan sering digunakan adalah *decorator parameter*. Decorator parameter memungkinkan kita untuk mengakses metadata dan memanipulasi argumen yang diteruskan ke handler rute dalam controller kita. Artikel ini akan menyelami secara mendalam tentang decorator parameter di NestJS, menjelaskan cara kerjanya, jenis-jenis yang tersedia, dan cara membuat decorator kustom.

Daftar Isi

  1. Pendahuluan
  2. Apa itu Decorator Parameter?
  3. Decorator Parameter Bawaan di NestJS
    1. @Req()
    2. @Res()
    3. @Next()
    4. @Param()
    5. @Query()
    6. @Body()
    7. @Headers()
    8. @Session()
    9. @HostParam()
    10. @Ip()
    11. @UploadedFile() dan @UploadedFiles()
    12. @HttpCode()
    13. @Header()
    14. @Redirect()
  4. Membuat Decorator Parameter Kustom
    1. Memahami createParamDecorator
    2. Contoh Decorator Parameter Kustom
  5. Penggunaan Lanjutan
    1. Decorator Parameter dengan Pipes
    2. Decorator Parameter dengan Interceptors
  6. Praktik Terbaik
  7. Kesimpulan

1. Pendahuluan

Dalam pengembangan aplikasi web, berinteraksi dengan permintaan dan respons HTTP adalah tugas mendasar. NestJS menyediakan cara yang elegan dan terstruktur untuk menangani interaksi ini melalui controller dan handler rute. Decorator parameter adalah komponen kunci dalam arsitektur ini, menyediakan cara yang ringkas dan mudah dibaca untuk mengakses informasi yang relevan dari permintaan dan respons HTTP.

2. Apa itu Decorator Parameter?

Decorator parameter adalah fungsi yang diawali dengan simbol @ (at) dan ditempatkan sebelum parameter fungsi dalam handler rute controller. Decorator ini memberi NestJS petunjuk tentang bagaimana parameter tersebut harus diisi. Mereka bertindak sebagai shortcut untuk mengakses dan memproses data yang tersedia dalam objek permintaan dan respons HTTP. Singkatnya, decorator parameter menjembatani kesenjangan antara framework NestJS dan data HTTP yang masuk, memungkinkan pengembang untuk bekerja dengan data tersebut dengan cara yang lebih deklaratif dan ringkas.

Misalnya, alih-alih secara manual mengakses objek permintaan untuk mendapatkan parameter query, kita dapat menggunakan decorator @Query() untuk langsung menyuntikkan nilai parameter query ke dalam handler rute kita.

3. Decorator Parameter Bawaan di NestJS

NestJS menyediakan sejumlah decorator parameter bawaan yang mencakup kasus penggunaan umum. Berikut adalah beberapa decorator yang paling umum dan penjelasan terperinci tentang cara penggunaannya:

3.1. @Req()

Decorator @Req() menyuntikkan objek permintaan Express (atau Fastify jika Anda menggunakan adapter Fastify) ke dalam handler rute Anda. Objek permintaan berisi semua informasi tentang permintaan HTTP, termasuk header, parameter query, body, dan lainnya.

Contoh:


import { Controller, Get, Req } from '@nestjs/common';
import { Request } from 'express';

@Controller('users')
export class UsersController {
  @Get()
  findAll(@Req() request: Request): string {
    console.log(request.headers);
    return 'Daftar semua pengguna';
  }
}
  

Dalam contoh ini, request akan menjadi objek permintaan Express, dan kita dapat mengakses header permintaan menggunakan request.headers.

3.2. @Res()

Decorator @Res() menyuntikkan objek respons Express (atau Fastify). Objek respons memungkinkan kita untuk mengontrol respons HTTP yang dikirim kembali ke klien, termasuk mengatur header, kode status, dan body respons. Penting: Penggunaan @Res() dan memanipulasi objek respons secara langsung dapat mengganggu fitur NestJS seperti interceptor dan pipes. Gunakan dengan hati-hati, dan pertimbangkan alternatif seperti mengembalikan nilai dari handler atau menggunakan interceptor untuk memodifikasi respons.

Contoh:


import { Controller, Get, Res } from '@nestjs/common';
import { Response } from 'express';

@Controller('products')
export class ProductsController {
  @Get()
  findAll(@Res() res: Response): void {
    res.status(200).json({ message: 'Daftar semua produk' });
  }
}
  

Dalam contoh ini, kita menggunakan objek res untuk mengatur kode status respons menjadi 200 dan mengirim respons JSON.

3.3. @Next()

Decorator @Next() menyuntikkan fungsi next dari middleware Express (atau Fastify). Fungsi ini digunakan untuk meneruskan kontrol ke middleware berikutnya dalam pipeline. Jarang digunakan secara langsung di controller, biasanya lebih relevan dalam middleware itu sendiri.

Contoh (dalam middleware):


import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    console.log('Request...');
    next();
  }
}
  

Dalam contoh ini, next() dipanggil untuk meneruskan kontrol ke middleware berikutnya.

3.4. @Param()

Decorator @Param() digunakan untuk mengakses parameter rute. Parameter rute adalah bagian dari URL yang digunakan untuk mengidentifikasi sumber daya tertentu. Misalnya, dalam rute /users/:id, :id adalah parameter rute.

Contoh:


import { Controller, Get, Param } from '@nestjs/common';

@Controller('users')
export class UsersController {
  @Get(':id')
  findOne(@Param('id') id: string): string {
    return `Mendapatkan user dengan ID: ${id}`;
  }
}
  

Dalam contoh ini, @Param('id') menyuntikkan nilai parameter rute id ke dalam variabel id.

Anda juga dapat menggunakan @Param() tanpa argumen untuk mendapatkan objek yang berisi semua parameter rute:


import { Controller, Get, Param } from '@nestjs/common';

@Controller('products')
export class ProductsController {
  @Get(':category/:id')
  getProduct(@Param() params: { category: string, id: string }): string {
    return `Kategori: ${params.category}, ID: ${params.id}`;
  }
}
  

3.5. @Query()

Decorator @Query() digunakan untuk mengakses parameter query dalam URL. Parameter query adalah bagian dari URL yang mengikuti tanda tanya (?). Misalnya, dalam URL /products?category=electronics&sort=price, category=electronics dan sort=price adalah parameter query.

Contoh:


import { Controller, Get, Query } from '@nestjs/common';

@Controller('products')
export class ProductsController {
  @Get()
  findAll(@Query('category') category: string, @Query('sort') sort: string): string {
    return `Daftar produk dengan kategori: ${category} dan urutkan berdasarkan: ${sort}`;
  }
}
  

Dalam contoh ini, @Query('category') menyuntikkan nilai parameter query category ke dalam variabel category, dan @Query('sort') menyuntikkan nilai parameter query sort ke dalam variabel sort.

Sama seperti @Param(), Anda juga dapat mendapatkan semua parameter query dalam bentuk objek:


import { Controller, Get, Query } from '@nestjs/common';

@Controller('products')
export class ProductsController {
  @Get()
  findAll(@Query() query: { category: string, sort: string }): string {
    return `Daftar produk dengan kategori: ${query.category} dan urutkan berdasarkan: ${query.sort}`;
  }
}
  

3.6. @Body()

Decorator @Body() digunakan untuk mengakses body permintaan. Body permintaan biasanya berisi data yang dikirimkan oleh klien dalam format JSON, XML, atau format lainnya. Biasanya digunakan dengan metode HTTP seperti POST, PUT, dan PATCH.

Contoh:


import { Controller, Post, Body } from '@nestjs/common';

@Controller('users')
export class UsersController {
  @Post()
  create(@Body('name') name: string, @Body('email') email: string): string {
    return `Membuat user dengan nama: ${name} dan email: ${email}`;
  }
}
  

Dalam contoh ini, @Body('name') menyuntikkan nilai properti name dari body permintaan ke dalam variabel name, dan @Body('email') menyuntikkan nilai properti email dari body permintaan ke dalam variabel email.

Anda juga bisa mendapatkan seluruh body permintaan sebagai objek:


import { Controller, Post, Body } from '@nestjs/common';

@Controller('users')
export class UsersController {
  @Post()
  create(@Body() createUserDto: { name: string, email: string }): string {
    return `Membuat user dengan nama: ${createUserDto.name} dan email: ${createUserDto.email}`;
  }
}
  

3.7. @Headers()

Decorator @Headers() digunakan untuk mengakses header permintaan HTTP. Header permintaan berisi informasi tambahan tentang permintaan, seperti jenis konten, otorisasi, dan user-agent.

Contoh:


import { Controller, Get, Headers } from '@nestjs/common';

@Controller('products')
export class ProductsController {
  @Get()
  findAll(@Headers('authorization') authorization: string): string {
    return `Daftar produk dengan authorization: ${authorization}`;
  }
}
  

Dalam contoh ini, @Headers('authorization') menyuntikkan nilai header authorization ke dalam variabel authorization.

Seperti decorator lainnya, Anda dapat memperoleh semua headers sebagai objek:


import { Controller, Get, Headers } from '@nestjs/common';

@Controller('products')
export class ProductsController {
  @Get()
  findAll(@Headers() headers: { authorization: string, 'content-type': string }): string {
    return `Daftar produk dengan authorization: ${headers.authorization} dan content-type: ${headers['content-type']}`;
  }
}
  

3.8. @Session()

Decorator @Session() digunakan untuk mengakses objek sesi. Sesi digunakan untuk menyimpan informasi tentang pengguna di antara permintaan. Untuk menggunakan decorator ini, Anda perlu mengkonfigurasi middleware sesi (seperti express-session atau cookie-session) terlebih dahulu.

Contoh:


import { Controller, Get, Session } from '@nestjs/common';

@Controller('auth')
export class AuthController {
  @Get('profile')
  getProfile(@Session() session: Record): string {
    if (session.user) {
      return `Profil user: ${session.user.name}`;
    } else {
      return 'User belum login';
    }
  }
}
  

Dalam contoh ini, @Session() menyuntikkan objek sesi ke dalam variabel session. Objek sesi ini berisi data yang tersimpan untuk pengguna tersebut.

3.9. @HostParam()

Decorator @HostParam() digunakan untuk mengakses parameter host. Parameter host adalah bagian dari hostname yang sesuai dengan wildcard. Ini sangat berguna ketika menangani subdomain atau virtual host.

Contoh:


import { Controller, Get, HostParam } from '@nestjs/common';

@Controller({ host: ':account.example.com' })
export class AccountController {
  @Get()
  getInfo(@HostParam('account') account: string): string {
    return `Menampilkan informasi untuk account: ${account}`;
  }
}
  

Dalam contoh ini, jika permintaan dikirim ke test.example.com, maka account akan bernilai test.

3.10. @Ip()

Decorator @Ip() digunakan untuk mendapatkan alamat IP dari permintaan. Ini bisa berguna untuk logging, analisis, dan deteksi penipuan.

Contoh:


import { Controller, Get, Ip } from '@nestjs/common';

@Controller('users')
export class UsersController {
  @Get('login')
  login(@Ip() ip: string): string {
    console.log(`User login dari IP: ${ip}`);
    return 'Login berhasil';
  }
}
  

Dalam contoh ini, @Ip() menyuntikkan alamat IP permintaan ke dalam variabel ip.

3.11. @UploadedFile() dan @UploadedFiles()

Decorator @UploadedFile() dan @UploadedFiles() digunakan untuk menangani upload file. Untuk menggunakan decorator ini, Anda perlu mengkonfigurasi middleware upload file (seperti multer) terlebih dahulu.

Contoh:


import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { diskStorage } from 'multer';

@Controller('files')
export class FilesController {
  @Post('upload')
  @UseInterceptors(FileInterceptor('file', {
    storage: diskStorage({
      destination: './uploads',
      filename: (req, file, cb) => {
        const filename = file.originalname;
        cb(null, filename);
      },
    }),
  }))
  uploadFile(@UploadedFile() file: Express.Multer.File): string {
    console.log(file);
    return 'File berhasil diupload';
  }
}
  

Dalam contoh ini, @UploadedFile() menyuntikkan file yang diupload ke dalam variabel file. Perhatikan penggunaan FileInterceptor untuk mengkonfigurasi middleware multer.

@UploadedFiles() digunakan untuk menangani multiple upload files, perbedaannya adalah parameter file akan bertipe array:


import { Controller, Post, UploadedFiles, UseInterceptors } from '@nestjs/common';
import { FilesInterceptor } from '@nestjs/platform-express';
import { diskStorage } from 'multer';

@Controller('files')
export class FilesController {
  @Post('upload')
  @UseInterceptors(FilesInterceptor('files', 20, { // 20 adalah jumlah maksimum file
    storage: diskStorage({
      destination: './uploads',
      filename: (req, file, cb) => {
        const filename = file.originalname;
        cb(null, filename);
      },
    }),
  }))
  uploadFile(@UploadedFiles() files: Express.Multer.File[]): string {
    console.log(files);
    return 'Files berhasil diupload';
  }
}
  

3.12. @HttpCode()

Decorator @HttpCode() bukanlah decorator parameter dalam arti yang sama dengan yang lain, tetapi penting untuk disebutkan karena berkaitan dengan kontrol respons HTTP. Decorator ini digunakan di tingkat method handler untuk secara eksplisit mengatur kode status HTTP. Secara default, NestJS mengirimkan kode status 200 OK untuk semua handler. Jika Anda ingin mengubahnya (misalnya, menjadi 201 Created untuk operasi pembuatan), Anda menggunakan @HttpCode().

Contoh:


import { Controller, Post, HttpCode, Body, HttpStatus } from '@nestjs/common';

@Controller('products')
export class ProductsController {
  @Post()
  @HttpCode(HttpStatus.CREATED) // Kode status 201 Created
  create(@Body() createProductDto: { name: string, price: number }): string {
    console.log(createProductDto);
    return 'Produk berhasil dibuat';
  }
}
  

3.13. @Header()

Sama seperti @HttpCode(), @Header() juga decorator method, bukan decorator parameter. Ia digunakan untuk mengatur header respons HTTP. Ini berguna untuk mengontrol cache, menentukan jenis konten, atau menambahkan header kustom.

Contoh:


import { Controller, Get, Header } from '@nestjs/common';

@Controller('images')
export class ImagesController {
  @Get('logo.png')
  @Header('Content-Type', 'image/png')
  getLogo(): Buffer {
    // Logika untuk mendapatkan gambar logo.png dari sistem file atau database
    const logo = Buffer.from('...'); // Replace '...' with actual image data
    return logo;
  }
}
    

3.14. @Redirect()

@Redirect() adalah decorator method yang digunakan untuk mengalihkan permintaan ke URL lain. Ia menerima dua parameter: url dan statusCode (opsional, default ke 302 Found).

Contoh:


import { Controller, Get, Redirect } from '@nestjs/common';

@Controller('docs')
export class DocsController {
  @Get()
  @Redirect('https://docs.nestjs.com', 302)
  getDocs() {
    return { url: 'https://docs.nestjs.com' }; // Alternatif cara setting redirect url
  }
}
  

4. Membuat Decorator Parameter Kustom

Selain decorator parameter bawaan, NestJS memungkinkan kita untuk membuat decorator kustom sendiri untuk menangani kasus penggunaan yang lebih spesifik. Ini memberi kita fleksibilitas untuk mengabstraksi logika kompleks dan membuat kode kita lebih mudah dibaca dan dipelihara.

4.1. Memahami createParamDecorator

Untuk membuat decorator parameter kustom, kita menggunakan fungsi createParamDecorator dari modul @nestjs/common. Fungsi ini menerima dua argumen:

  • data (opsional): Data yang diteruskan ke decorator saat digunakan.
  • context: Objek yang berisi informasi tentang konteks permintaan, termasuk objek permintaan, objek respons, dan argumen handler.

Fungsi createParamDecorator harus mengembalikan nilai yang akan disuntikkan ke parameter.

4.2. Contoh Decorator Parameter Kustom

Mari kita buat decorator kustom yang mengekstrak user agent dari header permintaan:


import { createParamDecorator, ExecutionContext } from '@nestjs/common';

export const UserAgent = createParamDecorator(
  (data: unknown, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    return request.headers['user-agent'];
  },
);
  

Dalam contoh ini, kita membuat decorator bernama UserAgent. Fungsi yang diteruskan ke createParamDecorator menerima objek ExecutionContext. Kita menggunakan ctx.switchToHttp().getRequest() untuk mendapatkan objek permintaan HTTP, dan kemudian kita mengakses header user-agent dari objek permintaan.

Untuk menggunakan decorator ini, kita bisa menambahkannya ke handler rute kita:


import { Controller, Get } from '@nestjs/common';
import { UserAgent } from './user-agent.decorator';

@Controller('users')
export class UsersController {
  @Get('profile')
  getProfile(@UserAgent() userAgent: string): string {
    return `User agent: ${userAgent}`;
  }
}
  

Sekarang, ketika kita mengakses rute /users/profile, decorator @UserAgent() akan menyuntikkan user agent dari header permintaan ke dalam variabel userAgent.

Contoh lain, misal kita ingin membuat decorator untuk mendapatkan ID User dari JWT token:


import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import * as jwt from 'jsonwebtoken';

export const UserId = createParamDecorator(
  (data: unknown, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    const token = request.headers.authorization?.split(' ')[1]; // Ambil token dari header Authorization

    if (!token) {
      return null; // Atau throw exception jika token wajib ada
    }

    try {
      const decodedToken = jwt.verify(token, 'secretKey'); // Ganti 'secretKey' dengan secret key yang sebenarnya
      return decodedToken.userId; // Asumsi payload token memiliki property 'userId'
    } catch (error) {
      return null; // Atau throw exception jika token tidak valid
    }
  },
);
  

Penggunaan:


import { Controller, Get, UseGuards } from '@nestjs/common';
import { UserId } from './user-id.decorator';
import { AuthGuard } from '@nestjs/passport';

@Controller('profile')
@UseGuards(AuthGuard('jwt')) // Proteksi rute dengan JWT guard
export class ProfileController {
  @Get()
  getProfile(@UserId() userId: string): string {
    return `User ID: ${userId}`;
  }
}
  

5. Penggunaan Lanjutan

5.1. Decorator Parameter dengan Pipes

Pipes di NestJS digunakan untuk transformasi dan validasi data. Mereka dapat digunakan dengan decorator parameter untuk memproses data sebelum disuntikkan ke handler rute. Pipes berjalan *setelah* decorator parameter dieksekusi. Misalnya, kita bisa menggunakan pipe untuk memvalidasi bahwa ID pengguna yang diekstrak dari parameter rute adalah angka yang valid.


import { Controller, Get, Param, ParseIntPipe } from '@nestjs/common';

@Controller('users')
export class UsersController {
  @Get(':id')
  findOne(@Param('id', ParseIntPipe) id: number): string {
    return `Mendapatkan user dengan ID: ${id}`;
  }
}
    

Dalam contoh ini, ParseIntPipe akan mencoba mengubah nilai parameter id menjadi angka integer. Jika gagal (misalnya, jika id adalah string), pipe akan melempar pengecualian, yang akan ditangani oleh NestJS.

5.2. Decorator Parameter dengan Interceptors

Interceptors di NestJS digunakan untuk memodifikasi permintaan dan respons. Mereka dapat digunakan dengan decorator parameter untuk memproses data sebelum atau sesudah disuntikkan ke handler rute. Interceptors berjalan *sebelum* dan *sesudah* handler rute dieksekusi, memberikan kemampuan untuk menambahkan logika sebelum atau sesudah decorator parameter bekerja.


import { Controller, Get, UseInterceptors, ExecutionContext, CallHandler, Injectable } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { UserAgent } from './user-agent.decorator';
import { NestInterceptor } from '@nestjs/common';

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable {
    const now = Date.now();
    return next
      .handle()
      .pipe(
        map(data => {
          console.log(`After... ${Date.now() - now}ms`);
          console.log(`Response data: ${JSON.stringify(data)}`);
          return data;
        }),
      );
  }
}

@Controller('users')
@UseInterceptors(LoggingInterceptor)
export class UsersController {
  @Get('profile')
  getProfile(@UserAgent() userAgent: string): string {
    return `User agent: ${userAgent}`;
  }
}
  

Dalam contoh ini, LoggingInterceptor akan mencatat waktu sebelum dan sesudah handler getProfile dieksekusi. Interseptor dapat digunakan untuk berbagai tugas seperti logging, caching, transformasi data, dan penanganan kesalahan.

6. Praktik Terbaik

  • Gunakan Decorator Bawaan: Manfaatkan decorator parameter bawaan sebanyak mungkin sebelum membuat decorator kustom. Ini akan membuat kode Anda lebih mudah dibaca dan dipelihara.
  • Jaga Decorator Kustom tetap Sederhana: Decorator kustom harus fokus pada satu tugas tertentu. Hindari menambahkan logika yang terlalu kompleks ke dalam decorator.
  • Dokumentasikan Decorator Kustom: Berikan dokumentasi yang jelas tentang cara menggunakan decorator kustom dan apa yang dikembalikannya.
  • Pertimbangkan Pipes dan Interceptors: Gunakan pipes untuk validasi dan transformasi data, dan interceptors untuk logika lintas-potong seperti logging dan caching.
  • Hindari Manipulasi Objek Respons Langsung (@Res()): Sebisa mungkin, hindari penggunaan @Res() untuk memanipulasi objek respons secara langsung. Ini dapat mengganggu fitur NestJS lainnya. Pertimbangkan alternatif seperti mengembalikan nilai atau menggunakan interceptor.
  • Gunakan Tipe yang Tepat: Tentukan tipe data yang tepat untuk parameter yang disuntikkan oleh decorator. Ini akan membantu mencegah kesalahan dan membuat kode Anda lebih mudah dibaca.
  • Validasi Input: Selalu validasi input yang diterima dari decorator parameter, terutama jika input tersebut berasal dari body permintaan atau parameter query. Ini akan membantu mencegah kerentanan keamanan.

7. Kesimpulan

Decorator parameter adalah fitur yang kuat dan serbaguna di NestJS yang menyederhanakan pengembangan aplikasi sisi server. Dengan memahami decorator parameter bawaan dan cara membuat decorator kustom, Anda dapat membuat kode yang lebih mudah dibaca, dipelihara, dan diuji. Ingatlah untuk mengikuti praktik terbaik dan memanfaatkan pipes dan interceptors untuk pemrosesan data dan logika lintas-potong.

Dengan menguasai decorator parameter, Anda dapat secara signifikan meningkatkan produktivitas pengembangan dan membangun aplikasi NestJS yang lebih robust dan efisien.

“`

omcoding

Leave a Reply

Your email address will not be published. Required fields are marked *