Nest.js kontroleri

Šta su kontroleri?

Kontroleri u Nest.js su klasične TypeScript klase koje su dekorisane @Controller() dekoratorom. U ovakvim klasama se definišu metode koji odgovaraju HTTP operacijama kao što su GET, POST, PUT, DELETE, gde je svaki metod u okviru kontrolera dekorisan odgovarajućim HTTP dekoratorom.

Primer jednostavnog kontrolera:

U ovom primeru @Controller('users') dekorator definiše osnovnu rutu (“/users“) za sve metode unutar kontrolera. Ovaj kontroler iz primera ima tri metode za tri tipa zahteva, i sve tri metode su obeležene sa odgovajućim dekoratorima u zavisnosti od tipa HTTP zahteva koji obrađuju:

  • findAll(): Obradjuje GET zahtev na ruti /users i vraća listu svih korisnika.
  • findOne(): Obradjuje GET zahtev na ruti /users/:id i vraća korisnika sa zadatim ID-om.
  • create(): Obradjuje POST zahtev na ruti /users i kreira novog korisnika.

nest.js

Kreiranje kontrolera

Da biste dodali kontroler u modul, najlakše je koristiti sledeće komande u terminalu:

Ova komanda će generisati users.controller.ts fajl u okviru novog foldera “users” i njega će smestiti u root projekta tj. src/users:

NAPOMENA:
Ako ne postoji direktorijum pod nazivom “users” ova komanda će i njega napraviti. Ukoliko ipak ne želimo da napravimo folder pod nazivom kontrolera već samo kontroler fajl, onda koristimo flag --flat.

Prethodna naredba će napraviti u root direktorijumu (“src”) samo fajl vezan za kontroler nekiKontroler.controller.ts, takodje postoji način da kreiramo novi kontroler fajl u već postojeći folder, a za to koristimo sledeću sintaksu:

Sa ovom naredbom će biti kreiran fajl “noviKontroler.controller.ts” u okviru foldera pod nazivom “nekiFolder”.

Naredba će pored toga će istovremeno dodati taj kontroler i u modul u okviru liste svih kontrolera:

Dekoratori za pristup podacima request-a

Pored dekoratora za obeležavanje tipa request-a (@Get(), @Post()…), postoje i dekoratori za lakši pristup podacima zahteva. Ovi dekoratori olakšavaju rad sa različitim delovima HTTP zahteva i omogućavaju jednostavno i čitljivo rukovanje zahtevima unutar kontrolera:

  • @Param('id'): Omogućava pristup parametru id iz URL-a
  • @Body(): Omogućava pristup telu POST zahteva.
  • @Headers() omogućava pristup HTTP zaglavljima.
  • @Ip() omogućava pristup IP adresi klijenta.
  • @Body() omogućava pristup telu POST zahteva.
  • @Session() omogućava pristup sesijskim podacima.
  • @Cookies() omogućava pristup kolačićima.
  • @HostParam('host') omogućava pristup parametrima hosta.
Primer

Evo kako možete koristiti neke od ovih dekoratora u kontroleru:

U prethodnom primeru dekorator @Get označava da će metoda findOne() odgovoriti na zahtev. Dekorator @Param(‘id’) izvlači parametar pod imenom “id” iz URL-a zahteva, dok dekorator @Query() izvlači sve query parametre iz URL-a zahteva i čuva ih u objektu “query” (npr. za URL /users/123?search=test, query će biti { search: ‘test’ }). Dekorator @Ip() obezbedjuje IP adresu klijenta koji je poslao zahtev.

Dostupnost servisa u kontrolerima

Servisi se koriste za enkapsulaciju poslovne logike i omogućavaju ponovnu upotrebu koda. Servisi se mogu lako uvesti u kontrolere korišćenjem mehanizma za injekciju zavisnosti (dependency injection) koji pruža Nest.js. U Nest.js postoji nekoliko načina za injekciju servisa u kontroler.

Injectovanje servisa kroz konstruktor

Najčešći način je putem konstruktora, kao što je prikazano u sledećem primeru:

U ovom primeru, UsersController koristi UsersService za obradu zahteva. Servis se ubacuje u kontroler kroz konstruktor.

Injektovanje servisa kroz svojstvo

Iako nije toliko često korišćena, moguća je i injekcija servisa putem svojstava koristeći dekorator @Inject.

NAPOMENA:
Takodje postoji i “Manuelna injekcija” servisa ali je prilično komplikovana a koristi se samo u specifičnim slučajevima kada ne možete koristiti konstruktorsku ili property-based injekciju. Ovaj pristup koristi ModuleRef, koji omogućava pristup Nest.js Dependency Injection (DI) kontejneru za ručno dobijanje instanci servisa.


Uvod u Nest.js

Šta je Nest.js?

Nest.js je Node.js framework za izradu server-side aplikacija. Koristi modularnu arhitekturu što podrazumeva da se aplikacija deli na module, gde svaki modul grupiše povezane funkcionalnost, tako da se lako mogu dodati nove funkcionalnosti bez narušavanja postojećih delova aplikacije.

Nest.js korisi TypeScript jezik (mada se može koristiti i JavaScript), uz korišćenje dekoratora (dekoratori su specijalne oznake koje se dodaju iznad koda sa kojima definišemo dodatna uputstva). Pored HTTP-a, Nest.js podržava WebSockets, GraphQL, gRPC i druge protokole.

nest.js

Moduli

U Nest.js, moduli su osnovni gradivni blokovi aplikacije i služe za organizaciju i strukturu koda. Oni grupišu povezane komponente kao što su kontroleri, provajderi (servisi), repozitorijumi i drugi moduli u logične jedinice. Moduli se definišu pomoću @Module() dekoratora.

Polja Modula:
  • imports: Lista modula koji su uvezeni u trenutni modul. Ovi moduli su dostupni unutar modula.
  • controllers: Lista kontrolera definisanih u modulu. Kontroleri su zaduženi za rukovanje HTTP zahtevima.
  • providers: Lista provajdera (servisa) definisanih u modulu. Provajderi obavljaju poslovnu logiku i mogu biti injektovani u kontrolere ili druge provajdere.
  • exports: Lista provajdera koji su eksportovani iz modula i mogu biti korišćeni u drugim modulima.

Kreiranje modula

Korišćenjem Nest CLI, možete brzo i jednostavno kreirati module u vašoj Nest.js aplikaciji. Da biste kreirali novi modul, možete koristiti nest generate (ili skraćeno nest g) komandu. Na primer, da biste kreirali modul pod nazivom cats, koristite sledeću komandu:

Ova komanda će generisati novu datoteku cats.module.ts u src/cats direktorijumu, koja izgleda ovako:

Primer Modula

Evo kako se definiše jednostavan modul u Nest.js:

Glavni Modul (App Module)

Svaka Nest.js aplikacija ima glavni modul, obično nazvan AppModule, koji je korenski modul aplikacije. On može uvoziti druge module i služi kao ulazna tačka za aplikaciju.

Controllers (Kontroleri)

Kontroleri su odgovorni za rukovanje HTTP zahtevima i vraćanje odgovarajućih odgovora klijentima. U Nest.js, kontroleri služe kao posrednici između klijenta i servisa. Oni definišu rute i metode koje se aktiviraju kada se određene rute pogode. Kontroleri se obeležavaju pomoću @Controller() dekoratora. Dekorartori se takodje koriste i u okviru samog kontrolera da obeleže specifične metode ili rute kao što su: @Get(), @Post(), @Put(), @Delete(), itd.

U ovom primeru, CatsController ima jednu rutu koja odgovara na GET zahteve na /cats i vraća string ‘This action returns all cats’.

Dodavanje kontrolera u modul

Nakon kreiranja kontrolera ili servisa, potrebno je ažurirati modul da ih uključi:

Primer

Services (Servisi)

Servisi predstavljaju sloj aplikacije koji obavlja poslovnu logiku i obezbeđuje podatke za kontrolere. Servisi obično sadrže metode koje se koriste za obavljanje različitih zadataka kao što su pristup bazi podataka, rad sa API-jevima trećih strana, obrada podataka i sl.

  • Definisanje servisa: Servisi se definišu kao klase i obično koriste @Injectable() dekorator kako bi ih Nest.js mogao injektovati u kontrolere ili druge servise.
  • Injekcija zavisnosti: Servisi se mogu ubaciti (injektovati) u kontrolere ili druge servise koristeći konstruktor.

Kreiranje servisa

Da biste dodali novi servis, koristite nest generate service (ili skraćeno nest g service) komandu.

Ova komanda će generisati cats.service.ts datoteku u src/cats direktorijumu sa osnovnom implementacijom servisa:

Dodavanje servisa u modul

Kada kreirate novi servis pomoću komande nest generate service cats, Nest CLI će automatski ažurirati odgovarajući modul da uključi novokreirani servis u providers polje tog modula. Ovo omogućava da servis bude dostupan u okviru modula bez dodatne manuelne intervencije.

Primer:

U ovom primeru, UsersService ima metodu findAll koja vraća listu korisnika.

Middleware

Middleware su funkcije koje se izvršavaju tokom obrade HTTP zahteva. Middleware funkcioniše u prostoru između primanja zahteva i povratka odgovora, omogućavajući modifikaciju zahteva i odgovora, preusmeravanje toka ili završavanje zahteva. U Nest.js, middleware se definiše kao klase koje implementiraju NestMiddleware interfejs ili kao obične funkcije. Middleware se može primeniti na određene rute ili globalno na sve rute.

Kreiranje middleware-a

Da biste dodali novi middleware, koristite nest generate middleware (ili skraćeno nest g middleware) komandu.

Ova komanda će generisati logger.middleware.ts datoteku u src direktorijumu sa osnovnom implementacijom middleware-a:

U ovom primeru, LoggerMiddleware loguje svaki zahtev koji prolazi kroz aplikaciju.

Registrovanje middleware-a u modul:

Da biste registrovali middleware, potrebno je da ga dodate u odgovarajući modul.

U ovom primeru, LoggerMiddleware će se primenjivati na sve zahteve koji idu na /users rutu.

Providers (Provajderi)

Nest.js ima ugrađen mehanizam za injektiranje zavisnosti, koji olakšava upravljanje zavisnostima i testiranje koda. Ovo znači da komponente kao što su usluge (services) mogu biti automatski ubačene (injected) tamo gde su potrebne, umesto da ih eksplicitno instancirate. Više o dependency injection-u pročitajte u članku “Šta je Dependency Injection”.

Provajderi su osnovni koncept u Nest.js koji omogućavaju kreiranje i deljenje instanci objekata. Obično se koriste za implementaciju servisa, ali mogu takođe obuhvatati bilo koju klasu koju želite da bude dostupna putem Dependency Injection (DI) mehanizma tj. provajderi mogu biti servisi, repozitorijumi, fabričke funkcije, itd.

Obležavanje provajdera

Provajderi se obeležavaju kao klase koje koriste @Injectable() dekorator.

Primer

U ovom primeru, CatsService je provajder definisan sa @Injectable() dekoratorom.

Registrovanje provajdera

U ovom primeru, CatsService je registrovan kao provajder u CatsModule.

Injectovanje provajdera

Provajderi se mogu ubaciti (injektovati) u druge klase ili provajdere koristeći konstruktor.

Primer

Repozitorijum

Repozitorijumi su sloj koji omogućava pristup podacima i upravljanje njima. Oni apstrahuju interakciju sa bazom podataka ili bilo kojim drugim izvorom podataka, čime omogućavaju čistiji i konzistentniji kod. Koriste se za obavljanje CRUD operacija (kreiranje, čitanje, ažuriranje, brisanje).

Primer

U ovom primeru, UserRepository koristi TypeORM repozitorijum za interakciju sa User entitetom.

Exception Filters

Exception filters su kao sigurnosne mreže u programu koje hvataju greške i odlučuju šta da urade s njima. Kada se nešto neočekivano desi u aplikaciji, exception filteri omogućavaju da se uhvate greške i vrati odgovarajuća poruka korisniku. Exception filters omogućavaju da centralizovano rukujemo greškama i ukidaju potrebu da se svuda po kodu pišu akcije koje bi hendlovale greške.

Korak 1: Definisanje Exception Filtera

Definišemo filter koristeći @Catch() dekorator. Ovo je jednostavan primer filtera koji hvata sve greške:

Korak 2: Korišćenje Exception Filtera

Možemo primeniti filter na različitim nivoima: globalno (za celu aplikaciju), na nivou kontrolera ili na nivou pojedinačnih ruta.

Primena na Globalnom Nivou

Da bi filter radio za celu aplikaciju, dodaćemo ga u glavni fajl aplikacije (npr. main.ts):

Primena na Nivou Kontrolera

Da bi filter radio samo za određeni kontroler, dodamo @UseFilters dekorator iznad kontrolera:

Primena na Nivou Pojedinačnih Ruta

Da bi filter radio samo za određenu rutu, dodamo @UseFilters dekorator iznad te rute:

Pipes

Pipes u Nest.js su moćan alat koji omogućava transformaciju i validaciju podataka. Pipes mogu da transformišu dolazne podatke, verifikuju ih i čak odbace nevažeće podatke. To omogućava da se logika za transformaciju i validaciju centralizuje i lako ponovo koristi.

Kreiranje Pipes-a

Pipe se kreira implementirajući PipeTransform interfejs i definišući metodu transform koja će obraditi podatke.

Primer

U ovome primeru pipe koji konvertuje dolazni string u broj:

Korišćenje Pipes-a

Pipes možete primeniti na globalnom nivou, nivou kontrolera ili nivou rute.

Globalna Primena

Globalno primenjivanje pipes-a koristi se u glavnom fajlu aplikacije (npr. main.ts):

Primena na Kontroleru

Možete primeniti pipes na specifičan kontroler koristeći @UsePipes() dekorator:

Primena na Ruti

Možete primeniti pipes na specifičnu rutu: