Sebagai pengembang backend Node.js, Anda akan setuju bahwa secara default, Node.js sangat sederhana, dan tidak membuat asumsi tentang apa yang Anda butuhkan saat membuat aplikasi. Akibatnya, Anda bertanggung jawab untuk menyiapkan semua yang ingin Anda gunakan di seluruh aplikasi, termasuk menangani perutean, membuat panggilan API, menyiapkan TypeScript atau Soket Web, atau bahkan hal mendasar seperti organisasi kode, struktur file, dan konvensi penamaan .
Mengelola aplikasi skala besar bisa menjadi tugas yang sulit, terutama jika tidak dirancang dengan struktur yang jelas dan panduan organisasi kode yang ketat.
Nest.js mencoba mengatasi beberapa masalah ini dengan membuat abstraksi di sekitar Node.js sehingga Anda sebagai pengembang dapat berfokus pada masalah aplikasi daripada detail implementasi kecil lainnya.
Dalam panduan ini, Anda akan mempelajari dasar-dasar inti Nest.js dari atas ke bawah, yang bertujuan untuk mempercepat Anda sehingga Anda dapat membangun aplikasi Node.js tingkat perusahaan dengan bantuan Nest.js dalam waktu singkat.
Semua yang akan kita pelajari melalui panduan ini akan bersifat inkremental; mencakup banyak dasar pada konsep pengantar. Untuk mendapatkan hasil maksimal dari panduan ini, ada baiknya untuk membuat kode bersama.
Mari kita selami, teman-teman!
Kode sumber: Seperti biasa, Anda dapat bercabang dan mengotak-atik kode sumber yang dihosting GitHub.
Catatan: Kami akan menggunakan Postman untuk menguji API di demo kami. Anda dapat mendownloadnya di Halaman Unduh tukang pos. Atau, Anda cukup menggunakan browser, baris perintah curl
alat, atau alat lain yang mungkin Anda kenal.
Apa itu Nest.js
Pikirkan Nest.js sebagai superset dari Node.js yang mengabstraksikan tugas, alat, dan kode boilerplate yang sulit, sambil juga menambahkan perangkat lengkap untuk pengembangan aplikasi Anda menggunakan JavaScript dan TypeScript modern.
Nest.js menyediakan arsitektur aplikasi out-of-the-box yang memungkinkan pengembang dan tim membuat yang sangat skalabel, dapat diuji, digabungkan secara longgar, dan mudah dipelihara, dengan memanfaatkan opsi dan modul yang tersedia dan menonjol di komunitas, seperti yang tersedia di Aplikasi Express.js. Anda bahkan dapat menukar Express (yang digunakan secara default) untuk Fastify, tetapi melakukan hal itu berarti Anda mungkin perlu menggunakan pustaka lain yang sesuai dengan Fastify dalam aplikasi Anda.
Ini menggabungkan fitur Pemrograman Fungsional, Pemrograman Berorientasi Objek, dan Pemrograman Reaktif Fungsional, dan dengan lebih dari 52.4k bintang dan 6.2k garpu di GitHub dan jumlah unduhan mingguan hingga 1,784,004, kerangka kerja Node.js progresif adalah tujuan populer untuk membuat aplikasi sisi server yang efisien, dapat diskalakan, dan tingkat perusahaan.
Fitur Nest.js
Berikut ini adalah alasan mengapa Nest.js berkembang menjadi framework Node.js yang begitu populer:
- Nest.js dibuat untuk membantu pengembang membangun aplikasi monolitik dan juga layanan mikro.
- Meskipun kuat, ini juga ramah pengembang untuk digunakan; mudah digunakan, cepat dipelajari, dan mudah diterapkan.
- Itu memanfaatkan TypeScript (superset JavaScript) di luar kotak dan memberi ruang bagi pengembang untuk menulis kode yang dapat dipelihara bebas dari kesalahan runtime.
- Itu memiliki Antarmuka Baris Perintah yang membantu meningkatkan produktivitas pengembang dan kemudahan pengembangan.
- Saat membangun dengan Nest.js, proses pengembangan ditingkatkan dan waktu dihemat baik saat Anda melakukan bootstrap Produk yang Layak Minimum atau mengerjakan aplikasi karena Nest dilengkapi dengan struktur folder proyek yang luar biasa secara default.
- Ini mendukung berbagai modul khusus Nest yang membantu dalam integrasi konsep dan teknologi umum termasuk TypeORM, GraphQL, logging, validasi, Mongoose, WebSockets, caching, dll.
- Nest.js dapat membanggakan beberapa dokumentasi terbaik untuk kerangka kerja apa pun di luar sana. Dokumentasinya menyeluruh, mudah dipahami, dan membantu dalam menghemat waktu debugging, karena dapat dilakukan dengan mudah saat ada kebutuhan akan solusi untuk suatu masalah.
- Nest.js terintegrasi dengan Jest, yang memudahkan penulisan pengujian unit pada aplikasi Anda.
- Itu dibangun untuk aplikasi perusahaan skala kecil dan besar.
Membuat Proyek Nest.js
Untuk memulai Nest.js di mesin lokal Anda, pertama-tama Anda harus menginstal Nest Command Line Interface (CLI), yang akan membantu merancah folder proyek Nest.js baru dan mengisi folder dengan file inti dan modul yang diperlukan untuk aplikasi Nest.js.
Jalankan perintah berikut untuk menginstal Antarmuka Baris Perintah Nest.js:
$ npm i -g @nestjs/cli
// Or
$ yarn global add @nestjs/cli
// Or
$ pnpm add -g @nestjs/cli
Setelah Anda berhasil menginstal Nest.js CLI secara global di mesin lokal Anda, Anda dapat menjalankannya nest
pada baris perintah untuk melihat berbagai perintah yang dapat kita manfaatkan:
$ nest
Hasil di:
Usage: nest [options]
Options:
-v, --version Output the current version.
-h, --help Output usage information.
Commands:
new|n [options] [name] Generate Nest application.
build [options] [app] Build Nest application.
start [options] [app] Run Nest application.
info|i Display Nest project details.
add [options] Adds support for an external library to your project.
generate|g [options] [name] [path] Generate a Nest element.
Schematics available on @nestjs/schematics collection:
┌───────────────┬─────────────┬──────────────────────────────────────────────┐
│ name │ alias │ description │
│ application │ application │ Generate a new application workspace │
│ class │ cl │ Generate a new class │
│ configuration │ config │ Generate a CLI configuration file │
│ controller │ co │ Generate a controller declaration │
│ decorator │ d │ Generate a custom decorator │
│ filter │ f │ Generate a filter declaration │
│ gateway │ ga │ Generate a gateway declaration │
│ guard │ gu │ Generate a guard declaration │
│ interceptor │ itc │ Generate an interceptor declaration │
│ interface │ itf │ Generate an interface │
│ middleware │ mi │ Generate a middleware declaration │
│ module │ mo │ Generate a module declaration │
│ pipe │ pi │ Generate a pipe declaration │
│ provider │ pr │ Generate a provider declaration │
│ resolver │ r │ Generate a GraphQL resolver declaration │
│ service │ s │ Generate a service declaration │
│ library │ lib │ Generate a new library within a monorepo │
│ sub-app │ app │ Generate a new application within a monorepo │
│ resource │ res │ Generate a new CRUD resource │
└───────────────┴─────────────┴──────────────────────────────────────────────┘
Di sini, Anda diperlihatkan cara menggunakan perintah, dan sekarang dapat memanfaatkan new|n [options] [name]
perintah untuk membuat proyek Nest.js pertama Anda:
$ nest new getting-started-with-nestjs
// Or
$ nest n getting-started-with-nestjs
Selanjutnya, Anda akan ditanya manajer paket apa yang ingin Anda gunakan:
? Which package manager would you ❤️ to use? (Use arrow keys)
npm
yarn
> pnpm
Jangan ragu untuk memilih pengelola paket pilihan Anda, saya akan ikut pnpm
. Ini karena ini tiga kali lebih efisien dan lebih cepat daripada NPM, dan dengan sistem cache yang cepat, PNPM juga lebih cepat daripada Yarn.
Setelah memilih manajer paket, proses instalasi berlanjut, maka aplikasi Nest.js akan dibuat.
Sekarang kamu bisa cd
ke dalam proyek yang baru dibuat, dan buka dengan editor pilihan Anda:
$ cd getting-started-with-nestjs
Dengan proyek yang sekarang dibuat, kita dapat menjalankannya dengan salah satu dari perintah berikut:
$ npm run start
// Or
$ yarn start
// Or
$ pnpm run start
Jika Anda melihat package.json
file, Anda akan melihat di segmen skrip, nilai untuk pnpm run start
is nest start
:
"start": "nest start",
Artinya, Anda juga dapat menjalankan aplikasi Nest.js dengan menjalankan:
$ nest start
Melihat Struktur Proyek Nest.js
Mari kita lihat lebih dekat bagaimana struktur aplikasi Nest:
/package.json
Grafik package.json
file adalah jantung dari Node.js dan dengan ekstensi, proyek Nest.js. Itu menampung semua metadata tentang proyek dan menentukan berbagai properti fungsional dari proyek yang diperlukan untuk menginstal dependensi aplikasi atau menjalankan skrip proyek.
Kami sudah melihat kemampuannya start
Script.
Grafik start:dev
profile memungkinkan untuk mengamati perubahan dalam aplikasi dan memuat ulang secara otomatis, tanpa perlu menghentikan aplikasi dan memulai ulang – dan ini dimaksudkan untuk pengembangan. Itu start:prod
skrip berguna saat Anda ingin menguji apakah aplikasi Anda siap untuk produksi serta saat Anda menerapkannya ke produksi, bersama dengan skrip lain untuk menguji aplikasi Nest.js.
@nestjs/platform-express
mendefinisikan express sebagai server HTTP default dalam aplikasi Nest.
/tsconfig.json
Grafik tsconfig.json
file adalah file yang ditulis dalam JSON (JavaScript Object Notation) yang menentukan opsi terkait TypeScript yang diperlukan untuk mengompilasi aplikasi Nest.
/nest-cli.json
Ini menyimpan metadata yang diperlukan untuk membuat, mengatur, atau menerapkan aplikasi Nest.
/test
Direktori ini menampung semua file yang diperlukan untuk menjalankan pengujian Nest. Nest menggunakan framework Jest untuk pengujian dengan konfigurasi Jest di jest-e2e.json
file.
/src
Grafik src
direktori adalah folder induk untuk inti proyek Nest. Ini memegang main.ts
file yang merupakan file tempat aplikasi Nest dimulai. Pekerjaan dari main.ts
file untuk memuat AppModule
yang diimpor dari /src/app.module.ts
.
Nanti dalam panduan ini, kita akan belajar tentang Modul; salah satu komponen utama aplikasi Nest.js.
Grafik AppModule
adalah kelas yang dibuat sebagai modul, menggunakan @Module
penghias. Dalam app.module.ts
file, AppService
dari ./app.service
dan AppController
dari ./app.controller
juga diimpor.
Grafik AppController
juga merupakan kelas yang dibuat menggunakan @Controller
dekorator, sedangkan AppService
adalah kelas yang dibuat menggunakan @Injectable
anotasi.
Hal keren tentang Nest adalah ia memiliki sangat sedikit dekorator di dalamnya yang menambahkan metadata ke kelas apa pun dan metadata tersebut menentukan tujuan kelas tersebut, seperti:
@Controller()
mengubah kelas menjadi pengontrol.@Module()
mengubah kelas menjadi modul.@Injectable()
mengubah kelas menjadi penyedia.
Juga di src
direktori adalah app.controller.spec.ts
file, yang merupakan file uji untuk Controllers.
Kita dapat menjalankan aplikasi menggunakan nest start
.
Aplikasi dimulai pada http://localhost:3000
di peramban Anda:
Kami dapat mengubah konten yang ditampilkan di http://localhost:3000
, dengan menuju ke app.service.ts
file, di mana penyedia untuk rute indeks ditentukan.
Blok Bangunan Aplikasi Nest.js
Ada tiga komponen utama aplikasi Nest.js:
- Modul
- controller
- Penyedia
Dalam mempelajari blok penyusun aplikasi Nest, pertama-tama mari kita bersihkan proyek Nest, dengan menghapus file app.controller.spec.ts
, ./app.service
, app.module.ts
, dan ./app.controller
file; pergi begitu saja main.ts
, untuk meniru siklus hidup pengembangan dari awal.
Pada titik ini, saat kami menghapus yang diimpor AppModule
file dari main.ts
, kami diminta bahwa Argumen untuk 'modul' tidak disediakan.
Untuk mendemonstrasikan blok penyusun aplikasi Nest, kita akan melihat implementasi Profil Pengguna sederhana, dengan membuat REST API untuk menangani operasi CRUD pada objek.
Modul
Dalam majalah src
membuat folder baru app.module.ts
file, lalu buat file AppModule
kelas, yang kami ekspor.
Selanjutnya, impor AppModule
kelas ke dalam main.ts
, dan lari nest start
.
Navigasi ke http://localhost:3000
di browser Anda dan Anda akan mendapatkan kesalahan 404:
Ini karena kami belum menentukan rute untuk URL dasar aplikasi Nest.
Kembali di app.module.ts
, kita punya AppModule
kelas yang kita miliki belum menjadi modul Nest. Untuk menjadikannya modul Nest, kami menambahkan @Module()
dekorator yang diimpor dari @nestjs/common
lalu kita melewati objek kosong.
import { Module } from '@nestjs/common';
@Module({})
export class AppModule {}
Sekarang, kami memiliki modul Nest.js!
Catatan: Modul adalah kelas yang dianotasi dengan a @Module()
penghias.
Setiap aplikasi Nest memiliki modul root, yang berfungsi sebagai titik masuk untuk menyelesaikan struktur dan hubungan aplikasi Nest.
Sangat disarankan untuk menggunakan banyak modul untuk mengatur komponen aplikasi Anda.
Grafik @Module()
dekorator memungkinkan pengembang untuk menentukan metadata tentang kelas di aplikasi Nest.
Jika ada beberapa modul, seperti modul pengguna, modul pesanan, modul obrolan, dll app.module.ts
harus digunakan untuk mendaftarkan semua modul lain dari aplikasi Nest.
Membuat Rute; Pengontrol
Pengontrol diperlukan untuk membuat rute di aplikasi Nest. Tujuan pengontrol adalah untuk menerima permintaan khusus untuk aplikasi Nest; mengendalikan siklus permintaan dan respons untuk berbagai rute dalam aplikasi.
Saat permintaan HTTP dibuat dari klien ke aplikasi Nest, rute yang cocok dengan rute tempat permintaan dibuat menangani permintaan dan mengembalikan respons yang sesuai.
Untuk membuat pengontrol di aplikasi Nest, kita harus menggunakan @Controller()
penghias.
Dalam majalah src
direktori, buat file baru app.contoller.ts
, dan di dalamnya, kita dapat mendefinisikan pengontrol Nest:
import { Controller } from '@nestjs/common';
@Controller({})
export class AppController {}
Hanya itu saja! Kami memiliki pengontrol yang sangat bagus, tetapi untuk membuat rute baru, pertama-tama kami harus memberi tahu aplikasi Nest kami tentang pengontrol yang dibuat.
Untuk mencapai ini, kami memastikan untuk mengimpor AppController
di app.module.ts, dan tentukan informasi tentang pengontrol di @Module()
dekorator – sebagai rangkaian pengontrol:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
@Module({
controllers: [AppController],
})
export class AppModule {}
Menangani Permintaan GET
Kemudian kita mendefinisikan sederhana getUser()
rute (dengan @Get()
dekorator yang digunakan untuk menangani permintaan HTTP GET ke jalur yang ditentukan) untuk berfungsi sebagai rute dasar, kita dapat mengaksesnya di browser di https://localhost:3000
:
import { Controller, Get } from '@nestjs/common';
@Controller({})
export class AppController {
@Get()
getUser() {
return 'I am a great person';
}
}
Ini menghasilkan:
Hmm, di sini kita hanya mengembalikan sebuah string, tapi bagaimana jika kita ingin mengembalikan sebuah objek? Alih-alih sebuah string, kita dapat mendefinisikan sebuah objek:
import { Controller, Get } from '@nestjs/common';
@Controller({})
export class AppController {
@Get()
getUser() {
return { name: 'Uchechukwu Azubuko', country: 'Nigeria' };
}
}
Navigasi ke http://localhost:3000
di browser Anda dan Anda akan melihat objek:
Jauh dari rute dasar, bagaimana kalau membuat rute yang mirip dengan http://localhost:3000/user
untuk mengambil semua pengguna?
Kami dapat membuat pengontrol untuk menangani rute seperti itu dalam beberapa cara.
Salah satu caranya adalah dengan mendefinisikan metode baru, menggunakan the @Get()
dekorator/penangan.
import { Controller, Get } from '@nestjs/common';
@Controller({})
export class AppController {
@Get()
getUser() {
return { name: 'Uchechukwu Azubuko', country: 'Nigeria' };
}
}
Nest.js menyediakan dekorator atau penangan untuk semua berbagai metode HTTP termasuk @Get()
, @Post()
, @Put()
, @Delete()
, @Patch()
, @Options()
, dan @Head()
.
Grafik @All()
dekorator mendefinisikan titik akhir yang menangani semua berbagai metode.
Menangani Permintaan POST
Kami juga dapat menentukan permintaan POST untuk menyimpan data dalam database, menggunakan @Post()
penghias:
import { Controller, Post } from '@nestjs/common';
@Controller({})
export class AppController {
@Post()
store() {
return 'Post request successful';
}
}
Kemudian, kami menguji permintaan POST menggunakan Postman dan perhatikan bahwa string berhasil dikembalikan seperti yang ditentukan.
Anda mungkin bertanya, bagaimana jika saya juga ingin melakukan lebih dari sekadar mengembalikan data? Mungkin, untuk mengirim data.
Untuk itu, Anda perlu menyuntikkan data ke dalam metode route, seperti yang ditunjukkan:
import { Controller, Post, Req } from '@nestjs/common';
import { Request } from 'express';
@Controller({})
export class AppController {
@Post()
store(@Req() req: Request) {
return req.body;
}
}
Sekarang, saat kami menguji permintaan POST dengan Postman, kami dapat melihat data yang sedang dikirim. Dalam hal ini, itu hanya objek kosong:
Lihat panduan praktis dan praktis kami untuk mempelajari Git, dengan praktik terbaik, standar yang diterima industri, dan termasuk lembar contekan. Hentikan perintah Googling Git dan sebenarnya belajar itu!
Perutean Dinamis dengan Parameter Rute
Misalkan Anda ingin menerima data dinamis sebagai bagian dari permintaan. Pertama, kita perlu mendefinisikan token di jalur rute, untuk mencatat posisi dinamis pada rute/URL, kemudian menggunakan @Param()
dekorator, parameter rute dapat diakses seperti ini:
import { Controller, Get, Param } from '@nestjs/common';
@Controller({})
export class AppController {
@Get('/:userId')
getUser(@Param() userId: number) {
return userId;
}
}
Grafik userId
berhasil dikembalikan:
Menangani Permintaan Asinkron
Nest.js dapat menangani permintaan asinkron yang mengembalikan janji menggunakan berbagai pendekatan:
import { Controller, Get} from '@nestjs/common';
@Controller({})
export class AppController {
@Get()
async findAll(): Promise {
return [];
}
}
Dalam pendekatan di atas, asinkronisitas ditangani menggunakan async
kata kunci. Pendekatan lain adalah dengan mengembalikan aliran yang dapat diamati RxJS:
import { Controller, Get} from '@nestjs/common';
@Controller({})
export class AppController {
@Get()
findAll(): Observable {
return of([]);
}
}
Di sini, Nest.js akan berlangganan ke sumber di bawah terpal, dan saat streaming selesai, ini akan mengambil nilai terakhir yang dipancarkan secara otomatis.
Menangani Pengalihan di Nest
Grafik @Redirect()
dekorator digunakan untuk mengalihkan respons ke URL yang berbeda. Itu @Redirect()
dekorator menerima dua argumen – URL tujuan pengalihan dan kode status setelah pengalihan, keduanya bersifat opsional:
import { Controller, Get} from '@nestjs/common';
@Controller({})
export class AppController {
@Get()
@Redirect('https://www.ucheazubuko.com', 302)
getSite() {
return { url: 'https://stackabuse.com' };
}
}
Mengembalikan Kode Status
Untuk mengembalikan kode status untuk setiap permintaan yang ditangani di server Nest.js, file @HttpCode(…)
dengan mudah datang melalui.
Di Nest, kode status default untuk permintaan GET adalah 200, permintaan POST adalah 201, permintaan kesalahan adalah 304
Kode status untuk permintaan server dapat didefinisikan seperti yang ditunjukkan di bawah ini:
import { Controller, Post, HttpCode } from '@nestjs/common';
@Controller({})
export class AppController {
@Post()
@HttpCode(204)
create() {
return 'This action adds a new user to the app.';
}
}
Menangani Permintaan DELETE
Mirip dengan membuat permintaan POST, permintaan penghapusan dapat ditangani seperti ini:
import { Controller, Delete, Param } from '@nestjs/common';
@Controller({})
export class AppController {
@Delete('/:userId')
delete(@Param() params: { userId: number }) {
return params;
}
}
Menangani Permintaan PEMBARUAN
Permintaan untuk memperbarui data tertentu di server dapat ditangani menggunakan @Patch()
penghias:
import { Controller, Patch, Req} from '@nestjs/common';
import { Request } from 'express';
@Controller({})
export class AppController {
@Patch('/:userId')
update(@Req() req: Request) {
return req.body;
}
}
Sekarang kita telah melihat berbagai cara untuk mendefinisikan pengontrol tipikal yang sering kita miliki di server yang kuat, penting untuk dicatat bahwa pengontrol harus ramping, bersih, dan ditentukan per kasus penggunaan, sehingga jika ada pengontrol lain untuk mendefinisikan user
rute, maka direktori terpisah harus dibuat dan didedikasikan untuk menangani hal yang sama – jauh dari AppController
.
Lalu masuk user.controller.ts
, kita dapat mengonfigurasi semua penangan rute di dalamnya untuk diawali dengan /user/
dengan menulis kode seperti yang ditunjukkan di bawah ini:
import { Controller, Get } from '@nestjs/common';
@Controller('/user')
export class UserController {
@Get()
getUser() {
return 'I am from the user controller';
}
}
Selanjutnya, daftar UserController
dalam array pengontrol di app.modules.ts
:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { UserController } from './controllers/user/user.controller';
@Module({
controllers: [AppController, UserController],
})
export class AppModule {}
Ketika kita menavigasi ke https:localhost:3000/user
, ia berhasil mengembalikan:
Untuk menjaga agar folder proyek lebih rapi dari sekarang, kita dapat mendefinisikan a user.module.ts
file di mana kita akan mendefinisikan UserController
:
import { Module } from '@nestjs/common';
import { UserController } from './user.controller';
@Module({
controllers: [UserController],
})
export class UserModule {}
Kemudian, impor UserModule
ke app.module.ts
:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { UserModule } from './user/user.module';
@Module({
controllers: [AppController],
imports: [UserModule],
})
export class AppModule {}
Dengan ini, kita akan dapat memiliki efek yang sama seperti sebelumnya.
Catatan: Nest memudahkan untuk (g)menghasilkan (mo)dules dan (co)pengontrol menggunakan nest g mo
dan nest g co
perintah. Modul khusus, seperti user
modul dan pengontrol juga dapat dibuat dengan cepat menggunakan Nest CLI, dengan menjalankan perintah: nest g mo user
– untuk membuat modul pengguna, dan nest g co user
– untuk membuat pengontrol pengguna.
Penyedia
Semua pengambilan data dari database harus ditangani oleh penyedia, bukan pengontrol, untuk membuat lapisan abstraksi antara kode yang menghadap pengguna dan kode yang berinteraksi dengan data yang berpotensi sensitif. Di antara lapisan-lapisan ini – validasi dapat diatur untuk memastikan penanganan basis data yang tepat. Dengan Nest CLI, kami dapat membuat penyedia dengan menghasilkan layanan:
$ nest g s user
Ini menciptakan a UserService
dimana kita akan mendefinisikan semua logika bisnis untuk UserController
, Sehingga UserController
hanya menangani permintaan dan tanggapan. Di dalam user.service.ts
, kita melihat bahwa @Injectable()
dekorator digunakan untuk mendefinisikan kelas. Di Nest, penggunaan @Injectable()
dekorator adalah mengubah layanan, repositori, atau kelas pembantu menjadi penyedia.
Penyedia disuntikkan ke dalam kelas melalui konstruktornya. Mari kita lihat lebih dekat sebuah contoh.
Sebelumnya, di user.controller.ts
, kami telah mendefinisikan logika bisnis untuk mendapatkan objek pengguna, tetapi sekarang, kami harus mendefinisikan hal yang sama di UserService
:
import { Controller, Injectable } from '@nestjs/common';
@Controller({})
export class AppController {
@Injectable()
get() {
return { name: 'Uchechukwu Azubuko', country: 'Nigeria'; };
}
}
Selanjutnya, di user.controller.ts
file, mari kita mendefinisikan konstruktor di UserController
kelas. Dalam konstruktor ini, kami menyediakan private userService
, yang merupakan jenis dari UserService
kelas. Dengan private inilah kita dapat memanfaatkan logika bisnis yang telah kita tentukan sebelumnya untuk mengambil pengguna:
import { Controller, Get } from '@nestjs/common';
import { UserService } from './user.service';
@Controller('/user')
export class UserController {
constructor(private userService: UserService) {}
@Get()
getUser() {
return this.userService.get();
}
}
Dengan demikian, UserController
kelas, sekarang tergantung pada UserService
kelas dalam konsep yang dikenal sebagai
injeksi ketergantungan.
Dengan cara yang sama, logika keduanya user.controller.ts
dan user.service.ts
file diperbarui sesuai:
import {
Controller,
Delete,
Get,
Param,
Patch,
Post,
Req,
} from '@nestjs/common';
import { Request } from 'express';
import { UserService } from './user.service';
@Controller('user')
export class UserController {
constructor(private userService: UserService) {}
@Get()
getUsers() {
return this.userService.get();
}
@Get('/:userId')
getUser(@Param() param: { userId: number }) {
return this.userService.getUser(param);
}
@Post()
store(@Req() req: Request) {
return this.userService.create(req);
}
@Patch('/:userId')
update(@Req() req: Request, @Param() param: { userId: number }) {
return this.userService.update(req, param);
}
@Delete()
delete(@Param() param: { userId: number }) {
return this.userService.delete(param);
}
}
import { Injectable } from '@nestjs/common';
import { Request } from 'express';
@Injectable()
export class UserService {
get() {
return { name: 'Uchechukwu Azubuko', country: 'Nigeria' };
}
getUser(param: { userId: number }) {
return param;
}
create(req: Request) {
return req.body;
}
update(req: Request, param: { userId: number }) {
return { body: req.body, param };
}
delete(param: { userId: number }) {
return param;
}
}
Sekarang, mari kita verifikasi bahwa titik akhir berfungsi sebagaimana mestinya, menggunakan Postman.
Demistifikasi Injeksi Ketergantungan di Nest.js
Saat membuat komponen aplikasi yang lebih kecil, seperti kelas atau modul, kelas Anda mungkin bergantung pada fungsionalitas kelas atau modul lain, misalnya, kebutuhan untuk memanfaatkan layanan HTTP yang disediakan oleh kelas berbeda untuk melakukan panggilan API, atau lapisan layanan yang berinteraksi dengan lapisan kegigihan.
Ketergantungan dapat disediakan di dalam pengontrol melalui injeksi ketergantungan.
Injeksi ketergantungan adalah konsep dan pola pemrograman yang mengungkapkan bagaimana bagian dari suatu aplikasi dikirim ke bagian lain dari aplikasi yang membutuhkannya, sedemikian rupa untuk memberikan kohesi tinggi tetapi sambungan longgar.
Nest mendukung injeksi ketergantungan dan Anda dapat menggunakannya di aplikasi Nest untuk meningkatkan modularitas proyek Anda.
Ilustrasi praktis digambarkan seperti ini:
Misalkan kelas A menggunakan beberapa fungsi dari kelas B. Kemudian dikatakan bahwa kelas A bergantung pada kelas B. Jadi, untuk menggunakan kelas B di kelas A, kita perlu membuat turunan dari kelas B terlebih dahulu (yaitu membuat Objek Kelas B):
const b = new B ()
.
Mentransfer tugas pembuatan instance kelas ke kelas lain dan secara langsung menggunakan ketergantungan di kelas yang disediakan (komponen injektor) dikenal sebagai injeksi ketergantungan.
Saran: Injeksi ketergantungan, atau DI, adalah salah satu konsep dasar dalam kerangka kerja seperti Spring Boot, Nest.js dan Angular.js, jika Anda ingin membaca lebih lanjut tentangnya, Anda dapat memeriksa dokumentasi Angular resmi.
Biasanya, sebuah kelas hanya harus berkonsentrasi untuk memenuhi fungsinya daripada digunakan untuk membuat berbagai objek yang mungkin diperlukan atau tidak.
Manfaat Injeksi Ketergantungan.
- Ini membantu dengan pengujian unit.
- Dengan injeksi ketergantungan, kode boilerplate berkurang, karena inisialisasi ketergantungan dilakukan oleh komponen injektor.
- Proses perpanjangan aplikasi menjadi lebih mudah.
- Injeksi ketergantungan membantu mengaktifkan kopling longgar.
Menjelajahi Muatan Permintaan
Ingatlah bahwa pada berbagai penangan permintaan seperti POST, dan PATCH, kami dapat memanfaatkan permintaan yang dikirim oleh server menggunakan @Req()
penghias. Namun, ada lebih dari itu.
Daripada mengambil seluruh objek permintaan, kita cukup memanfaatkan bagian tertentu dari objek permintaan yang kita butuhkan.
Oleh karena itu, Nest menyediakan berbagai dekorator yang dapat digunakan dengan penangan rute HTTP untuk mengakses objek Express of Fastify:
Dekorator sarang | Fastify atau Express objek yang diakses |
`@Permintaan(), @Req()` | `permintaan` |
`@Respons(), @Res()` | `kembali` |
`@Berikutnya()` | `selanjutnya` |
`@Sesi()` | `permintaan.sesi` |
`@Param(param?: string)` | `req.params` / `req.params[param]` |
`@Tubuh(param?: string)` | `req.body` / `req.body[param]` |
`@Permintaan(param?: string)` | `req.query` / `req.query[param]` |
`@Header(param?: string)` | `req.headers` / `req.headers[param]` |
`@Ip()` | `req.ip` |
`@HostParam()` | `req.hosts` |
Contoh tipikal akan menggantikan @Req()
dekorator yang kita gunakan sebelumnya untuk mendapatkan akses ke badan hasil, dengan @Body()
yang sudah dapat memberi kami akses langsung ke isi permintaan tanpa mengebor:
@Post()
store(@Body() body: any) {
return this.userService.create(body);
}
@Patch('/:userId')
update(@Body() body: any, @Param() param: { userId: number }) {
return this.userService.update(body, param);
}
create(body: any) {
return body;
}
update(body: any, param: { userId: number }) {
return { body: body, param };
}
Dalam beberapa kasus, Anda mungkin hanya ingin mengambil properti tertentu dari payload permintaan. Dalam hal ini, Anda harus menentukan skema Data Transfer Object (DTO). Skema Transfer Data adalah objek yang mendefinisikan salinan objek yang sedang diambil, tetapi digunakan terutama untuk mentransfer data antara objek yang seharusnya disimpan atau diambil, dan lapisan persistensi. Biasanya, karena proses ini lebih rentan terhadap serangan – DTO tidak berisi banyak titik data sensitif. Karakteristik ini juga memungkinkan Anda untuk hanya mengambil bidang tertentu dari suatu objek.
Di Nest, disarankan untuk menggunakan kelas untuk menentukan Objek Transfer Data, karena nilai kelas dipertahankan selama kompilasi.
Misalkan badan permintaan memiliki token, dan Anda tidak ingin mengambil atau memperbarui data tersebut, maka DTO dapat didefinisikan seperti yang ditunjukkan di bawah ini:
@Patch('/:userId')
update(
@Body() updateUserDto: { name: string; email: string },
@Param() param: { userId: number },
) {
return this.userService.update(updateUserDto, param);
}
update(
updateUserDto: { name: string; email: string },
param: { userId: number },
) {
return { body: updateUserDto, param };
}
Namun, Anda akan melihat bahwa kami telah menentukan jenis untuk updateUserDto
dua kali; di dalam user.service.ts
dan dalam user.controller.ts
, tetapi kita perlu menjaga agar kode kita DRY (Jangan Ulangi Sendiri) agar kita tidak mengulangi diri kita sendiri di sekitar basis kode.
Untuk ini, di folder baru /user/dto
dalam /user
direktori, kita perlu membuat file /update-user.dto.ts
pada pengatur terkenal. Pengatur ini menawarkan bantuan hukum kepada traderapabila trader berselisih dengan broker yang terdaftar dengan mereka. .dto.ts
ekstensi tempat kami mendefinisikan dan mengekspor file UpdateUserDto
kelas untuk digunakan dalam user.service.ts
dan user.controller.ts
file:
export class UpdateUserDto {
name: string;
email: string;
}
...
import { UpdateUserDto } from './dto/update-user.dto';
@Patch('/:userId')
update(
@Body() updateUserDto: UpdateUserDto,
@Param() param: { userId: number },
) {
return this.userService.update(updateUserDto, param);
}
...
import { UpdateUserDto } from './dto/update-user.dto';
update(updateUserDto: UpdateUserDto, param: { userId: number }) {
return { body: updateUserDto, param };
}
Pipa dan Validasi
Misalkan ada kebutuhan untuk memvalidasi data yang didapat saat permintaan dibuat melalui server.
Di Nest, kami dapat menguji kebenaran data apa pun yang masuk atau keluar dari aplikasi dengan menggunakan pipa yang memasang dua dependensi – class-validator
dan class-transformer
.
Sebuah pipa adalah kelas yang didefinisikan dengan
@Injectable()
dekorator (dengan demikian, pipa adalah penyedia), yang mengimplementasikanPipeTransform
antarmuka. Mereka mengubah data ke format yang diinginkan dan mengevaluasi data sedemikian rupa sehingga jika data ditemukan valid, data tersebut tidak berubah, jika tidak, pengecualian akan dilemparkan. Untuk menggunakan pipa, Anda perlu mengikat turunan dari kelas pipa tertentu ke konteks yang sesuai.
Grafik class-validator
paket memungkinkan untuk memvalidasi dekorator dan non-dekorator, menggunakan validator.js secara internal. Selagi class-transformer
paket memungkinkan untuk mengubah objek menjadi turunan dari kelas, mengubah kelas menjadi objek, dan membuat serial atau deserialisasi objek berdasarkan kriteria tertentu.
Delapan pipa yang disediakan oleh Nest adalah:
ValidationPipe
ParseArrayPipe
ParseIntPipe
ParseUUIDPipe
ParseBoolPipe
DefaultValuePipe
ParseEnumPipe
ParseFloatPipe
Untuk mendemonstrasikan validasi di Nest dalam panduan ini, kami akan menggunakan built-in ValidationPipe
yang memungkinkan untuk menerapkan validasi pada payload permintaan dan digabungkan dengan baik dengan class-validator
kemasan; aturan khusus dideklarasikan dengan anotasi sederhana dalam deklarasi Objek Transfer Data/kelas lokal di setiap modul.
Untuk mulai menggunakan built-in ValidationPipe
yang diekspor dari @nestjs/common
, mari kita instal class-validator
dan class-transformer
paket:
$ npm i --save class-validator class-transformer
# Or
$ yarn add class-validator class-transformer
# Or
$ pnpm install class-validator class-transformer
Selanjutnya, arahkan ke main.ts
di mana kita akan mengikat ValidationPipe
di tingkat akar aplikasi untuk memastikan bahwa semua titik akhir di aplikasi kami dilindungi dari pengambilan data yang tidak valid:
import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe());
await app.listen(3000);
}
bootstrap();
Selanjutnya, dalam deklarasi Objek Transfer Data dari setiap modul, kami menambahkan beberapa aturan validasi dengan mendeklarasikan pemeriksaan data yang sesuai untuk setiap data individual. Dalam kasus kami, kami akan mendeklarasikan aturan validasi yang sesuai untuk name
dan email
in UpdateUserDto
:
import { IsEmail, IsString } from 'class-validator';
export class UpdateUserDto {
@IsString()
name: string;
@IsEmail()
email: string;
}
Grafik @IsString()
dekorator memeriksa apakah data yang diberikan adalah string nyata, dan @IsEmail()
validator memeriksa apakah data yang diberikan adalah email, jika tidak maka akan mengembalikan false dan mengeluarkan pengecualian.
Sekarang, jika kita mencoba untuk membuat PATCH
permintaan ke profil pengguna, dan masukkan nomor alih-alih email yang valid, misalnya, pengecualian akan dilemparkan:
Dengan ini, kami memiliki validasi yang sangat bagus di aplikasi Nest kami.
Saat memvalidasi dengan ValidationPipe
, juga memungkinkan untuk memfilter properti kita yang tidak ingin diterima oleh penangan metode kita. Misalnya, jika penangan kita hanya mengharapkan name
dan email
properti, tetapi permintaan juga menyertakan a country
properti, kita dapat menghapus country
properti dari objek yang dihasilkan dengan pengaturan whitelist
untuk true
ketika kita instantiate ValidationPipe
:
import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
}),
);
await app.listen(3000);
}
bootstrap();
Mengikat Pipa pada Level Parameter Metode
Pipa juga dapat didefinisikan pada params
, demikian juga. Untuk ini, kami akan mengikat pipa pada level param metode.
Sebelum sekarang, meskipun kami mendefinisikan userId
menjadi nomor, Anda akan melihat bahwa jika kami membuat permintaan dengan userId
sebagai string, ternyata berhasil terlepas dari:
Untuk memastikan bahwa nilai dari userId
harus selalu berupa angka, kami akan mendeklarasikannya mengikat getUser()
penangan metode dengan pemeriksaan validasi yang memastikan hal yang sama:
...
import { ParseIntPipe } from '@nestjs/common';
@Get('/:userId')
getUser(@Param('userId', ParseIntPipe) userId: number) {
return this.userService.getUser(userId);
}
getUser(userId: number) {
return { userId };
}
Grafik ParseIntPipe
mendefinisikan ParseInt Pipe bawaan dan memastikan bahwa data yang dijalankannya harus bilangan bulat.
Sekarang, ketika kita membuat GET
permintaan ke yang tidak valid userId
string "ab", validasi gagal dan pengecualian dilemparkan dengan a 400
Kode status:
Tetapi dengan nilai numerik, validasi berhasil:
Kami juga dapat memperbarui penangan metode lain yang sesuai untuk memastikan validasi yang tepat:
import {
Body,
Controller,
Delete,
Get,
Param,
ParseIntPipe,
Patch,
Post,
Req,
} from '@nestjs/common';
import { Request } from 'express';
import { UserService } from './user.service';
@Controller('user')
export class UserController {
constructor(private userService: UserService) {}
@Get()
getUsers() {
return this.userService.get();
}
@Get('/:userId')
getUser(@Param('userId', ParseIntPipe) userId: number) {
return this.userService.getUser(userId);
}
@Post()
store(@Req() req: Request) {
return this.userService.create(req);
}
@Patch('/:userId')
update(
@Body() updateUserDto: { name: string; email: string },
@Param('userId', ParseIntPipe) userId: number,
) {
return this.userService.update(updateUserDto, userId);
}
@Delete()
delete(@Param('userId', ParseIntPipe) userId: number) {
return this.userService.delete(userId);
}
}
import { Injectable } from '@nestjs/common';
import { Request } from 'express';
import { UpdateUserDto } from './dto/user-update.dto';
@Injectable()
export class UserService {
get() {
return { name: 'Uchechukwu Azubuko', country: 'Nigeria' };
}
getUser(userId: number) {
return { userId };
}
create(req: Request) {
return req.body;
}
update(updateUserDto: UpdateUserDto, userId: number) {
return { body: updateUserDto, userId };
}
delete(userId: number) {
return { userId };
}
}
Sekarang, kami telah memastikan teknik praktik terbaik untuk memvalidasi data yang masuk ke aplikasi kami, mungkin dari sumber eksternal, kapan saja.
Kesimpulan
Dalam panduan ini, Anda telah dapat mempelajari tentang anak terbaru di blok Node.js; Nest.js, dan semua yang diperlukan untuk membantu Anda memulai jika Anda ingin membuat aplikasi dengannya. Anda telah mempelajari apa itu Nest, fitur-fiturnya, cara membuat proyek Nest, cara menangani data yang masuk ke dalam aplikasi Nest, dan cara memvalidasi data yang masuk. Secara keseluruhan, Anda telah mempelajari blok penyusun aplikasi Nest apa pun, dan nilai yang dibawa setiap komponen ke aplikasi Nest.js.
Dari titik ini, masih banyak yang harus dipelajari sehubungan dengan membangun aplikasi tingkat perusahaan dengan Nest, tetapi Anda telah berhasil membahas konsep dasar yang dapat membuat Anda siap dan berlari menuju semua yang ada di depan.
Nantikan panduan baru di masa mendatang, tempat kami mempelajari cara membuat API yang tenang dengan Nest dan MySQL.
Terima kasih sudah membaca!