Gids voor Nest.js - Een REST API bouwen met Nest en Node PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.

Gids voor Nest.js – Een REST API bouwen met Nest en Node

Als backend-ontwikkelaar van Node.js zult u het ermee eens zijn dat Node.js standaard zeer eenvoudig is en geen aannames doet over wat u nodig heeft tijdens het bouwen van een app. Als gevolg hiervan bent u verantwoordelijk voor het instellen van alles wat u in een app wilt gebruiken, inclusief het afhandelen van routering, het uitvoeren van API-aanroepen, het instellen van TypeScript of Web Sockets, of zelfs fundamentele zaken zoals code-organisatie, bestandsstructuur en naamgevingsconventies. .

Het beheren van een grootschalige applicatie kan een moeilijke taak zijn, vooral als deze niet is ontworpen met een duidelijke structuur en strikte richtlijnen voor de organisatie van code.

Nest.js probeert een aantal van deze problemen aan te pakken door een abstractie rond Node.js te creëren, zodat jij als ontwikkelaar zich kunt concentreren op het applicatieprobleem in plaats van op andere kleine implementatiedetails.

In deze handleiding leert u de kernbeginselen van Nest.js van boven tot onder, zodat u snel aan de slag kunt met het bouwen van Node.js-applicaties op bedrijfsniveau met behulp van Nest.js.

Alles wat we door deze gids zullen leren, zal stapsgewijs zijn; waarbij veel aandacht wordt besteed aan inleidende concepten. Om het meeste uit deze handleiding te halen, helpt het om mee te coderen.

Laten we er meteen in duiken, mensen!

Broncode: Zoals gewoonlijk kunt u sleutelen aan de broncode die wordt gehost GitHub.

Opmerking: We zullen Postman gebruiken om de API in onze demo te testen. Je kunt het downloaden op de Postbode Download pagina. U kunt ook gewoon de browser gebruiken, de opdrachtregel curl tool of een andere tool die u misschien kent.

Wat is Nest.js

Beschouw Nest.js als een superset van Node.js die moeilijke taken, tools en standaardcode abstraheert, en tegelijkertijd een volwaardige toolkit toevoegt voor de ontwikkeling van uw applicaties met behulp van modern JavaScript en TypeScript.

Nest.js biedt een kant-en-klare applicatiearchitectuur waarmee ontwikkelaars en teams zeer schaalbare, testbare, losjes gekoppelde en gemakkelijk te onderhouden applicaties kunnen creëren, door gebruik te maken van direct beschikbare en prominente opties en modules in de community, zoals die beschikbaar zijn in Express.js-toepassingen. U kunt zelfs Express (dat standaard onder de motorkap wordt gebruikt) omwisselen voor Fastify, maar als u dit doet, moet u mogelijk verschillende Fastify-compatibele bibliotheken in uw toepassing gebruiken.

Het combineert de kenmerken van functioneel programmeren, objectgeoriënteerd programmeren en functioneel reactief programmeren, en met meer dan 52.4k sterren en 6.2k vorken op GitHub en een wekelijkse downloadtelling van maximaal 1,784,004, is het vooruitstrevende Node.js-framework een populaire keuze voor het maken van efficiënte, schaalbare en ondernemingswaardige serverapplicaties.

Kenmerken van Nest.js

Dit zijn redenen waarom Nest.js is uitgegroeid tot zo’n populair Node.js-framework:

  1. Nest.js is gemaakt om ontwikkelaars te helpen zowel monolithische applicaties als microservices te bouwen.
  2. Hoewel het krachtig is, is het ook ontwikkelaarsvriendelijk om mee te werken; gemakkelijk te gebruiken, snel te leren en gemakkelijk toe te passen.
  3. Het maakt gebruik van TypeScript (een superset van JavaScript) en maakt ruimte voor ontwikkelaars om onderhoudbare code te schrijven zonder runtimefouten.
  4. Het beschikt over een opdrachtregelinterface die de productiviteit van ontwikkelaars en het ontwikkelingsgemak helpt verhogen.
  5. Wanneer u met Nest.js bouwt, worden de ontwikkelingsprocessen verbeterd en wordt er tijd bespaard, of u nu een Minimum Viable Product aan het opstarten bent of aan een applicatie werkt, omdat Nest standaard wordt geleverd met een geweldige projectmappenstructuur.
  6. Het ondersteunt een verscheidenheid aan Nest-specifieke modules die helpen bij de integratie van algemene concepten en technologieën, waaronder TypeORM, GraphQL, logboekregistratie, validatie, Mongoose, WebSockets, caching, enz.
  7. Nest.js kan bogen op de beste documentatie voor elk raamwerk dat er is. De documentatie is grondig, gemakkelijk te begrijpen en nuttig bij het besparen van tijd voor het opsporen van fouten, omdat deze moeiteloos doorkomt wanneer er behoefte is aan een oplossing voor een probleem.
  8. Nest.js kan worden geïntegreerd met Jest, waardoor het eenvoudig is om unit-tests voor uw applicaties te schrijven.
  9. Het is gebouwd voor zowel kleine als grootschalige bedrijfstoepassingen.

Een Nest.js-project maken

Om aan de slag te gaan met Nest.js op je lokale computer, moet je eerst de Nest Command Line Interface (CLI) installeren. Hiermee kun je een nieuwe Nest.js-projectmap opzetten en de map vullen met kernbestanden en modules die nodig zijn voor een Nest.js-app.

Voer de volgende opdracht uit om de Nest.js-opdrachtregelinterface te installeren:

$ npm i -g @nestjs/cli
// Or
$ yarn global add @nestjs/cli
// Or
$ pnpm add -g @nestjs/cli

Zodra je de Nest.js CLI wereldwijd met succes op je lokale computer hebt geïnstalleerd, kun je deze uitvoeren nest op de opdrachtregel om verschillende opdrachten te zien die we kunnen gebruiken:

$ nest

Resulteert in:

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                 │
      └───────────────┴─────────────┴──────────────────────────────────────────────┘

Hier wordt u getoond hoe u gebruik kunt maken van de opdrachten en kunt u nu gebruikmaken van de new|n [options] [name] opdracht om je allereerste Nest.js-project te maken:

$ nest new getting-started-with-nestjs
// Or
$ nest n getting-started-with-nestjs

Vervolgens wordt u gevraagd welke pakketbeheerder u wilt gebruiken:

? Which package manager would you ❤️ to use? (Use arrow keys)
  npm
  yarn
> pnpm

Kies gerust de pakketbeheerder van jouw keuze, ik ga mee pnpm. Dit komt omdat het ongeveer drie keer efficiënter en sneller is dan NPM, en met een snel cachesysteem is PNPM ook sneller dan Yarn.

Nadat je een pakketbeheerder hebt gekozen, gaat het installatieproces verder, waarna de Nest.js-app wordt gemaakt.

Nu, kunt u cd in het nieuw gemaakte project en open het met een editor naar keuze:

$ cd getting-started-with-nestjs

Nu het project is gemaakt, kunnen we het uitvoeren met een van de volgende opdrachten:

$ npm run start
// Or
$ yarn start
// Or
$ pnpm run start

Als je het package.json bestand, ziet u in het scriptsegment de waarde voor pnpm run start is nest start:


    
"start": "nest start",

Dit betekent dat je de Nest.js-app ook kunt gebruiken door:

$ nest start

Een blik op de Nest.js-projectstructuur

Laten we eens goed bekijken hoe een Nest-app is gestructureerd:

/package.json

De package.json -bestand is het hart van het Node.js- en bij uitbreiding het Nest.js-project. Het bevat alle metagegevens over het project en definieert verschillende functionele eigenschappen van het project die nodig zijn om applicatie-afhankelijkheden te installeren of projectscripts uit te voeren.

We hebben al gezien wat de mogelijkheden zijn van de start scripts.

De start:dev profiel maakt het mogelijk om te kijken naar veranderingen in de applicatie en deze automatisch opnieuw te laden, zonder de noodzaak om de applicatie te stoppen en opnieuw te starten – en het is bedoeld voor ontwikkeling. De start:prod script is handig wanneer u wilt testen of uw applicatie gereed is voor productie en wanneer u deze in productie implementeert, samen met andere scripts voor het testen van de Nest.js-app.

@nestjs/platform-express definieert express als de standaard HTTP-server in een Nest-app.

/tsconfig.json

De tsconfig.json bestand is een bestand geschreven in JSON (JavaScript Object Notation) dat TypeScript-gerelateerde opties definieert die nodig zijn om de Nest-app te compileren.

/nest-cli.json

Dit bevat metadata die nodig zijn om Nest-apps te bouwen, organiseren of implementeren.

/test

Deze map bevat alle bestanden die nodig zijn om Nest-tests uit te voeren. Nest gebruikt het Jest-framework voor het testen met de Jest-configuratie in de jest-e2e.json bestand.

/src

De src directory is de bovenliggende map voor de kern van het Nest-project. Het houdt de main.ts bestand. Dit is het bestand waarin de Nest-app wordt gestart. De taak van de main.ts bestand moet worden geladen AppModule waaruit wordt geïmporteerd /src/app.module.ts.

Verderop in deze handleiding zullen we meer leren over modules; een van de belangrijkste componenten van een Nest.js-applicatie.

De AppModule is een klasse die als module is gemaakt met behulp van de @Module decorateur. In de app.module.ts bestand AppService oppompen van ./app.service en AppController oppompen van ./app.controller worden ook geïmporteerd.

De AppController is ook een klasse die is gemaakt met behulp van de @Controller decorateur, terwijl de AppService is een klasse die is gemaakt met behulp van de @Injectable annotatie.

Het leuke van Nest is dat er maar heel weinig decorateurs zijn die metadata aan een klasse toevoegen en dat metadata het doel van die klasse definieert, zodat:

  • @Controller()transformeert een klasse in een controller.
  • @Module() transformeert een klasse in een module.
  • @Injectable() transformeert een klasse in een aanbieder.

Ook in de src map is de app.controller.spec.ts bestand, een testbestand voor controllers.

We kunnen de app uitvoeren met behulp van nest start.

De app wordt gestart om http://localhost:3000 in uw browser:

Gids voor Nest.js - Een REST API bouwen met Nest en Node PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.

We kunnen de inhoud wijzigen die wordt weergegeven op http://localhost:3000, door naar de app.service.ts bestand, waarin de provider voor de indexroute is gedefinieerd.

De bouwstenen van een Nest.js-app

Er zijn drie belangrijke componenten van een Nest.js-app:

  1. Modules
  2. Controllers
  3. Providers

Laten we, als we meer te weten komen over de bouwstenen van een Nest-app, eerst het Nest-project opruimen door de app.controller.spec.ts, ./app.service, app.module.ts en ./app.controller bestanden; gewoon weggaan main.ts, om een ​​ontwikkelingslevenscyclus vanaf het begin te emuleren.

Op dit punt, wanneer we het geïmporteerde AppModule bestand van main.ts, wordt ons gevraagd dat er geen argument voor 'module' is opgegeven.

Om de bouwstenen van een Nest-app te demonstreren, zullen we kijken naar een eenvoudige implementatie van een gebruikersprofiel, door een REST API te bouwen om CRUD-bewerkingen op een object uit te voeren.

Modules

In het src map maak een nieuwe app.module.ts bestand en maak vervolgens een AppModule klasse, die we exporteren.

Importeer vervolgens de AppModule klasse in main.ts, en loop nest start.

Navigeer naar http://localhost:3000 in uw browser en u krijgt een 404-foutmelding:

Gids voor Nest.js - Een REST API bouwen met Nest en Node PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.

Dit komt omdat we nog geen route hebben gedefinieerd voor de basis-URL van de Nest-app.

Terug in app.module.ts, we hebben de AppModule klasse die wij hebben is nog geen Nest-module. Om er een Nest-module van te maken, voegen we de @Module() decorateur waaruit wordt geïmporteerd @nestjs/commondan passeren we een leeg object.



import { Module } from '@nestjs/common';
@Module({})

export class AppModule {}

Nu hebben we een Nest.js-module!

Opmerking: Een module is een klasse die is geannoteerd met a @Module() decorateur.

Elke Nest-applicatie heeft een rootmodule die als toegangspunt dient om de structuur en relaties van een Nest-applicatie op te lossen.

Het wordt sterk aanbevolen om meerdere modules te gebruiken om de componenten van uw applicatie te organiseren.

De @Module() decorateur maakt het mogelijk dat ontwikkelaars metadata over een klas kunnen definiëren in de Nest-app.

In het geval dat er meerdere modules zijn, zoals een gebruikersmodule, bestelmodule, chatmodule, enz., wordt de app.module.ts moet worden gebruikt om alle andere modules van de Nest-app te registreren.

Routes creëren; Controleurs

Om routes te maken in Nest-applicaties zijn controllers nodig. Het doel van een verwerkingsverantwoordelijke is het ontvangen van specifieke verzoeken voor een Nest-applicatie; het beheersen van de aanvraag- en antwoordcyclus voor verschillende routes binnen de applicatie.

Wanneer er een HTTP-verzoek wordt gedaan van de client naar de Nest-app, wordt het verzoek afgehandeld door de route die overeenkomt met de route waarin het verzoek wordt gedaan, en wordt het juiste antwoord geretourneerd.

Om een ​​controller in een Nest-app te maken, moeten we gebruik maken van de @Controller() decorateur.

In het src map, maak een nieuw bestand app.contoller.ts, en daarin kunnen we een Nest-controller definiëren:

import { Controller } from '@nestjs/common';

@Controller({})

export class AppController {}

Dat is het! We hebben een hele mooie controller, maar om een ​​nieuwe route te maken, moeten we eerst onze Nest-app op de hoogte stellen van de aangemaakte controller.

Om dit te bereiken, zorgen we ervoor dat we importeren AppController in app.module.ts en definieer informatie over de controllers in @Module() decorateur – als een reeks controllers:



import { Module } from '@nestjs/common';
import { AppController } from './app.controller';

@Module({
  controllers: [AppController],
})

export class AppModule {}

GET-verzoeken afhandelen

Vervolgens definiëren we een eenvoudig getUser() traject (met de @Get() decorateur gebruikt voor het verwerken van HTTP GET-verzoeken naar een opgegeven pad) om als basisroute te dienen, we hebben toegang tot hetzelfde in de browser op https://localhost:3000:



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

@Controller({})

export class AppController {
  @Get()
  getUser() {
    return 'I am a great person';
  }
}

Dit resulteert in:

Gids voor Nest.js - Een REST API bouwen met Nest en Node PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.

Hmm, hier retourneren we slechts een string, maar wat als we een object willen retourneren? In plaats van een string kunnen we een object definiëren:



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

@Controller({})

export class AppController {
  @Get()
  getUser() {
    return { name: 'Uchechukwu Azubuko', country: 'Nigeria' };
  }
}

Navigeer naar http://localhost:3000 in uw browser en u ziet het object:

Gids voor Nest.js - Een REST API bouwen met Nest en Node PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.

Wat dacht je ervan om, buiten de basisroute, een route te maken die vergelijkbaar is met http://localhost:3000/user voor het ophalen van alle gebruikers?

We kunnen een controller maken die een dergelijke route op een aantal manieren kan afhandelen.

Eén manier zou zijn om een ​​nieuwe methode te definiëren, met behulp van de @Get() decorateur/handler.

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

@Controller({})

export class AppController {
  @Get()
  getUser() {
    return { name: 'Uchechukwu Azubuko', country: 'Nigeria' };
  }
}

Nest.js biedt decorateurs of handlers voor alle verschillende HTTP-methoden, inclusief @Get(), @Post(), @Put(), @Delete(), @Patch(), @Options() en @Head().

De @All() decorateur definieert een eindpunt dat alle verschillende methoden afhandelt.

POST-aanvragen afhandelen

We kunnen ook POST-verzoeken definiëren voor het opslaan van gegevens in de database, met behulp van de @Post() decorateur:

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

@Controller({})
export class AppController {
  @Post()
  store() {
    return 'Post request successful';
  }
}

Vervolgens testen we het POST-verzoek met Postman en merken we dat de string met succes wordt geretourneerd zoals gedefinieerd.

Gids voor Nest.js - Een REST API bouwen met Nest en Node PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.

U vraagt ​​zich misschien af: wat als ik ook meer wil doen dan alleen gegevens retourneren? Misschien om gegevens te verzenden.

Daarvoor moet je de gegevens in de routemethode injecteren, zoals weergegeven:

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

@Controller({})
export class AppController {
  @Post()
  store(@Req() req: Request) {
    return req.body;
  }
}

Wanneer we nu het POST-verzoek testen met Postman, kunnen we de gegevens bekijken die worden verzonden. In dit geval is het gewoon een leeg object:

Bekijk onze praktische, praktische gids voor het leren van Git, met best-practices, door de industrie geaccepteerde normen en bijgevoegd spiekbriefje. Stop met Googlen op Git-commando's en eigenlijk leren het!

Gids voor Nest.js - Een REST API bouwen met Nest en Node PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.

Dynamische routering met routeparameters

Stel dat u dynamische gegevens wilt accepteren als onderdeel van een verzoek. Eerst moeten we het token in het pad van de route definiëren, om de dynamische positie op de route/URL te noteren, en vervolgens de @Param() decorateur, kan de routeparameter als volgt worden benaderd:

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

@Controller({})
export class AppController {
  @Get('/:userId')
  getUser(@Param() userId: number) {
    return userId;
  }
}

De userId is succesvol geretourneerd:

Gids voor Nest.js - Een REST API bouwen met Nest en Node PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.

Asynchrone verzoeken afhandelen

Nest.js kan asynchrone verzoeken die een belofte opleveren, op verschillende manieren afhandelen:

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

@Controller({})
export class AppController {
  @Get()
  async findAll(): Promise {
    return [];
  }
}

In de bovenstaande benadering wordt asynchroniciteit afgehandeld met behulp van de async trefwoord. Een andere benadering is het retourneren van waarneembare RxJS-streams:

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

@Controller({})
export class AppController {
  @Get()
  findAll(): Observable {
    return of([]);
  }
}

Hier abonneert Nest.js zich op de bron onder de motorkap en wanneer de stream is voltooid, neemt deze automatisch de laatst uitgezonden waarde over.

Omleidingen verwerken in Nest

De @Redirect() decorateur wordt gebruikt om een ​​antwoord om te leiden naar een andere URL. De @Redirect() decorateur accepteert twee argumenten: de URL waarnaar moet worden doorverwezen en de statuscode bij doorverwijzing, die beide optioneel zijn:

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

@Controller({})
export class AppController {
  @Get()
  @Redirect('https://www.ucheazubuko.com', 302)
  getSite() {
    return { url: 'https://stackabuse.com' };
  }
}

Statuscode retourneren

Om de statuscode te retourneren voor elk verzoek dat op de Nest.js-server wordt afgehandeld, moet de @HttpCode(…) komt er makkelijk doorheen.

In Nest is de standaardstatuscode voor GET-verzoeken 200, een POST-verzoek is 201 en een foutverzoek is 304

De statuscode voor een serververzoek kan worden gedefinieerd zoals hieronder weergegeven:

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.';
  }
}

Het afhandelen van DELETE-verzoeken

Net als bij het indienen van een POST-verzoek, kan een verwijderverzoek als volgt worden afgehandeld:

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

@Controller({})
export class AppController {
  @Delete('/:userId')
  delete(@Param() params: { userId: number }) {
    return params;
  }
}

UPDATE-verzoeken afhandelen

Een verzoek om specifieke gegevens op de server bij te werken kan worden afgehandeld met behulp van de @Patch() decorateur:

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

@Controller({})
export class AppController {
  @Patch('/:userId')
  update(@Req() req: Request) {
    return req.body;
  }
}

Nu we verschillende manieren hebben gezien om typische controllers te definiëren die we vaak op een robuuste server zouden hebben, is het belangrijk op te merken dat de controller per gebruiksgeval lean, clean en gedefinieerd moet zijn, zodat als er een andere controller is voor het definiëren user routes, dan moet er een aparte map worden aangemaakt en gereserveerd voor het afhandelen ervan – weg van de AppController.

Dan in user.controller.ts, kunnen we alle route-handlers daarin configureren zodat ze worden voorafgegaan door /user/ door code te schrijven zoals hieronder weergegeven:



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

@Controller('/user')
export class UserController {
  @Get()
  getUser() {
    return 'I am from the user controller';
  }
}

Registreer u vervolgens UserController in de arrays van de controllers in 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 {}

Wanneer we navigeren naar https:localhost:3000/user, het keert succesvol terug:

Gids voor Nest.js - Een REST API bouwen met Nest en Node PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.

Om de projectmap nog netter te houden dan hij nu is, kunnen we een user.module.ts bestand waarin we de UserController:

import { Module } from '@nestjs/common';
import { UserController } from './user.controller';

@Module({
  controllers: [UserController],
})

export class UserModule {}

Importeer vervolgens UserModule in 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 {}

Hiermee kunnen we hetzelfde effect bereiken als voorheen.

Opmerking: Nest maakt het eenvoudig om (mo)dules en (co)ntrollers te (g)enereren met behulp van de nest g mo en nest g co opdrachten. Specifieke modules, zoals de user Module en controllers kunnen ook snel worden gemaakt met behulp van de Nest CLI, door de volgende opdrachten uit te voeren: nest g mo user – om een ​​gebruikersmodule aan te maken, en nest g co user – om een ​​gebruikerscontroller aan te maken.

Providers

Het ophalen van gegevens uit een database moet worden afgehandeld door providers in plaats van door beheerders, om een ​​abstractielaag te creëren tussen de op de gebruiker gerichte code en de code die interageert met potentieel gevoelige gegevens. Tussen deze lagen kan validatie worden ingesteld om een ​​goede verwerking van de database te garanderen. Met de Nest CLI kunnen we providers creëren door services te genereren:

$ nest g s user

Dit creëert een UserService waarin we alle bedrijfslogica voor de UserController, Zodat UserController behandelt alleen verzoeken en antwoorden. In user.service.ts, we zien dat de @Injectable() decorateur wordt gebruikt om de klasse te definiëren. In Nest is het gebruik van de @Injectable() decorateur is om services, opslagplaatsen of helpersklasse te transformeren in een provider.

Providers worden via de constructor in een klasse geïnjecteerd. Laten we een voorbeeld eens goed bekijken.

Eerder, in user.controller.ts, hadden we de bedrijfslogica gedefinieerd voor het verkrijgen van het gebruikersobject, maar nu zouden we hetzelfde moeten definiëren in de UserService:



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

@Controller({})

export class AppController {
  @Injectable()
  get() {
    return { name: 'Uchechukwu Azubuko', country: 'Nigeria'; };
  }
}

Vervolgens in de user.controller.ts bestand, laten we een constructor definiëren in het UserController klas. In deze constructor bieden wij een privé userService, wat een type is van de UserService klas. Met deze privé kunnen we gebruik maken van de bedrijfslogica die we eerder hadden gedefinieerd voor het ophalen van de gebruikers:



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();
  }
}

Dus de UserController klasse, hangt nu af van de UserService klasse in een concept dat bekend staat als
afhankelijkheid injectie.

Op dezelfde manier, de logica in beide user.controller.ts en user.service.ts bestanden worden dienovereenkomstig bijgewerkt:



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;
  }
}

Laten we nu verifiëren dat de eindpunten werken zoals ze zouden moeten, met behulp van Postman.

Demystificatie van afhankelijkheidsinjectie in Nest.js

Bij het bouwen van kleinere componenten van een applicatie, zoals een klasse of module, kan uw klasse afhankelijk zijn van de functionaliteit van een andere klasse of module, bijvoorbeeld de noodzaak om gebruik te maken van een HTTP-service die door een andere klasse wordt geleverd om API-aanroepen te doen, of servicelagen die interageren met de persistentielaag.

Afhankelijkheden kunnen binnen controllers worden voorzien via afhankelijkheidsinjectie.

Afhankelijkheidsinjectie is een programmeerconcept en -patroon dat uitdrukt hoe delen van een applicatie worden geleverd aan andere delen van de applicatie die deze nodig hebben, op een manier die zorgt voor een hoge cohesie maar losse koppeling.

Nest ondersteunt afhankelijkheidsinjectie en u kunt het in uw Nest-toepassingen gebruiken om de modulariteit van uw project te verbeteren.

Een praktische illustratie wordt als volgt weergegeven:

Stel dat klasse A een bepaalde functionaliteit van klasse B gebruikt. Dan wordt er gezegd dat klasse A afhankelijk is van klasse B. Om klasse B in klasse A te kunnen gebruiken, moeten we dus eerst een instantie van klasse B maken (dat wil zeggen, een Klasse B-object): const b = new B ().
Het overbrengen van de taak van het maken van een instantie van een klasse naar een andere klasse en het rechtstreeks gebruiken van de afhankelijkheid in de klasse waarin wordt voorzien (de injectorcomponent) staat bekend als afhankelijkheidsinjectie.

Advies: Dependency injection, of DI, is een van de fundamentele concepten in frameworks als Spring Boot, Nest.js en Angular.js. Als je er meer over wilt lezen, kun je de officiële Angular-documentatie.

Normaal gesproken zou een klasse zich uitsluitend moeten concentreren op het vervullen van zijn functies, in plaats van te worden gebruikt om verschillende objecten te maken die hij al dan niet nodig heeft.

Voordelen van afhankelijkheidsinjectie.

  1. Het helpt bij het testen van eenheden.
  2. Met afhankelijkheidsinjectie wordt de standaardcode verminderd, omdat het initialiseren van afhankelijkheden wordt gedaan door de injectorcomponent.
  3. Het proces van het verlengen van een aanvraag wordt eenvoudiger.
  4. Afhankelijkheidsinjectie helpt losse koppeling mogelijk te maken.

Verzoekladingen verkennen

Houd er rekening mee dat we met verschillende verzoekbehandelaars, zoals POST en PATCH, gebruik konden maken van het verzoek dat door de server werd verzonden met behulp van de @Req() decorateur. Er is echter meer aan de hand.

In plaats van het volledige verzoekobject op te halen, kunnen we alleen gebruik maken van specifieke delen van het verzoekobject die we nodig hebben.
Nest biedt dus verschillende decorateurs die kunnen worden gebruikt met de HTTP-routehandlers om toegang te krijgen tot Express of Fastify-objecten:

Nestdecorateurs Fastify- of Express-object waartoe toegang wordt verkregen
`@Request(), @Req()` `verzoek`
`@Reactie(), @Res()` 're's'
`@Volgende()` `volgende`
`@Sessie()` `verzoek.sessie`
`@Param(param?:string)` `req.params` / `req.params[param]`
`@Body(param?:string)` `req.body` / `req.body[param]`
`@Query(param?:string)` `req.query` / `req.query[param]`
`@Headers(param?:string)` `req.headers` / `req.headers[param]`
`@Ip()` `req.ip`
`@HostParam()` `req.hosts`

Een typisch voorbeeld is het vervangen van de @Req() decorateur die we eerder gebruikten om toegang te krijgen tot de hoofdtekst van het resultaat, met de @Body() waarmee we al directe toegang kunnen krijgen tot de hoofdtekst van een verzoek zonder te boren:



@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 };
}

In sommige gevallen wilt u mogelijk alleen specifieke eigenschappen van een aanvraagpayload ophalen. In dat geval moet u een Data Transfer Object (DTO)-schema definiëren. Het Data Transfer Schema is een object dat een kopie definieert van het object dat wordt opgehaald, maar wordt voornamelijk gebruikt om de gegevens over te dragen tussen het object dat moet worden opgeslagen of opgehaald, en de persistentielaag. Omdat dit proces kwetsbaarder is voor aanvallen, bevat de DTO doorgaans niet zoveel gevoelige gegevenspunten. Dankzij deze eigenschap kunt u ook alleen bepaalde velden van een object ophalen.

In Nest wordt aanbevolen om klassen te gebruiken om een ​​Data Transfer Object te definiëren, omdat de waarde van klassen tijdens de compilatie behouden blijft.

Stel dat de hoofdtekst van het verzoek een token bevat en u dergelijke gegevens niet wilt ophalen of bijwerken, dan kan een DTO worden gedefinieerd zoals hieronder weergegeven:



@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 };
}

U zult echter merken dat we het type voor hebben gedefinieerd updateUserDto tweemaal; in user.service.ts en in user.controller.ts, maar we moeten onze codes DRY (Don't Repeat Yourself) houden, zodat we onszelf niet herhalen rond de codebase.

Hiervoor in een nieuwe map /user/dto in de /user directory, moeten we een bestand maken /update-user.dto.ts met de .dto.ts extensie waar we het UpdateUserDto klasse voor gebruik in de user.service.ts en user.controller.ts bestanden:



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 };
}

Pipe en validatie

Stel dat het nodig is om de gegevens te valideren die worden verkregen wanneer er een verzoek via de server is gedaan.

In Nest kunnen we de juistheid van alle gegevens die de applicatie binnenkomen of verlaten, testen door gebruik te maken van pipelines die twee afhankelijkheden installeren: class-validator en class-transformer.

Een pipe is een klasse die wordt gedefinieerd met de @Injectable() decorateur (pijpen zijn dus aanbieders), die de uitvoering uitvoert PipeTransform koppel. Ze transformeren gegevens naar het gewenste formaat en evalueren gegevens zodanig dat als de gegevens geldig worden bevonden, deze onveranderd worden doorgegeven, anders wordt er een uitzondering gegenereerd. Om een ​​pipe te gebruiken, moet u een instantie van de specifieke pipe-klasse aan de juiste context binden.

De class-validator pakket maakt het mogelijk om decorateurs en niet-decorateurs te valideren met behulp van validator.js intern. Terwijl de class-transformer package maakt het mogelijk om objecten te transformeren in een instantie van een klasse, een klasse in een object te transformeren en objecten te serialiseren of te deserialiseren op basis van bepaalde criteria.

De acht door Nest geleverde leidingen zijn:

  • ValidationPipe
  • ParseArrayPipe
  • ParseIntPipe
  • ParseUUIDPipe
  • ParseBoolPipe
  • DefaultValuePipe
  • ParseEnumPipe
  • ParseFloatPipe

Om de validatie in Nest in deze handleiding aan te tonen, gebruiken we de ingebouwde ValidationPipe dat het mogelijk maakt om validatie op verzoek van payloads af te dwingen en goed combineert met de class-validator pakket; specifieke regels worden gedeclareerd met eenvoudige annotaties in de declaraties van Data Transfer Object/lokale klassen in elke module.

Om te beginnen met het gebruik van de ingebouwde ValidationPipe waaruit wordt geëxporteerd @nestjs/common, laten we de class-validator en class-transformer pakketjes:

$ npm i --save class-validator class-transformer
# Or
$ yarn add class-validator class-transformer
# Or
$ pnpm install class-validator class-transformer

Navigeer vervolgens naar main.ts waar we zullen binden ValidationPipe op het rootniveau van de applicatie om ervoor te zorgen dat alle eindpunten in onze app beschermd zijn tegen het ophalen van ongeldige gegevens:



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();

Vervolgens voegen we in de Data Transfer Object-declaraties van elke module een paar validatieregels toe door de juiste gegevenscontroles voor elke afzonderlijke gegevens te declareren. In ons geval zouden we passende validatieregels definiëren voor name en email in UpdateUserDto:



import { IsEmail, IsString } from 'class-validator';

export class UpdateUserDto {
  @IsString()
  name: string;

  @IsEmail()
  email: string;
}

De @IsString() decorateur controleert of bepaalde gegevens een echte string zijn, en de @IsEmail() validator controleert of bepaalde gegevens een e-mail zijn, anders retourneert deze false en genereert een uitzondering.

Als we nu proberen een PATCH verzoek aan een gebruikersprofiel en voer een nummer in in plaats van een geldig e-mailadres; er wordt bijvoorbeeld een uitzondering gegenereerd:

Gids voor Nest.js - Een REST API bouwen met Nest en Node PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.

Hiermee hebben we een hele mooie validatie in onze Nest-app.

Tijdens het valideren met ValidationPipe, is het ook mogelijk om onze eigenschappen te filteren waarvan we niet willen dat onze methode-handler deze ontvangt. Bijvoorbeeld als onze begeleider alleen maar verwacht name en email eigenschappen, maar een verzoek omvat ook a country eigendom, kunnen we de country eigenschap van het resulterende object door instelling whitelist naar true wanneer we instantiëren 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();

Bindende pijpen op methodeparameterniveau

Er kunnen ook leidingen worden gedefinieerd params, ook. Hiervoor binden we de pijp op het parameterniveau van de methode.

Vroeger, ook al definieerden we de userId om een ​​nummer te zijn, zou je merken dat als we een verzoek indienen bij de userId als string blijkt het succesvol, ongeacht:

Gids voor Nest.js - Een REST API bouwen met Nest en Node PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.

Om ervoor te zorgen dat de waarde van userId moet altijd een getal zijn, wij verklaren dat dit bindend is getUser() methodehandler met een validatiecontrole die hetzelfde garandeert:


...
import { ParseIntPipe } from '@nestjs/common';

@Get('/:userId')
getUser(@Param('userId', ParseIntPipe) userId: number) {
  return this.userService.getUser(userId);
}


getUser(userId: number) {
  return { userId };
}

De ParseIntPipe definieert de ingebouwde ParseInt Pipe en zorgt ervoor dat de gegevens waarmee het wordt uitgevoerd een geheel getal moeten zijn.

Wanneer we nu een GET verzoek aan een invalide userId van string “ab”, mislukt de validatie en wordt er een uitzondering gegenereerd met a 400 status code:

Gids voor Nest.js - Een REST API bouwen met Nest en Node PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.

Maar met een numerieke waarde verloopt de validatie met succes:

Gids voor Nest.js - Een REST API bouwen met Nest en Node PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.

We kunnen ook andere methodehandlers dienovereenkomstig bijwerken om een ​​goede validatie te garanderen:



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 };
  }
}

Nu hebben we gezorgd voor de beste praktijktechniek voor het valideren van gegevens die op elk moment in onze applicatie binnenkomen, misschien vanuit een externe bron.

Conclusie

In deze gids heb je meer te weten kunnen komen over het nieuwste kind in het Node.js-blok; Nest.js, en alles wat nodig is om u op weg te helpen als u er een applicatie mee wilt bouwen. Je hebt geleerd wat Nest is, wat de functies ervan zijn, hoe je een Nest-project maakt, hoe je binnenkomende gegevens in een Nest-app verwerkt en hoe je de binnenkomende gegevens valideert. Al met al heb je kennis gemaakt met de bouwstenen van elke Nest-app en de waarde die elk onderdeel toevoegt aan een Nest.js-app.

Vanaf dit punt valt er nog zoveel te leren over het bouwen van een applicatie op bedrijfsniveau met Nest, maar je hebt met succes fundamentele concepten kunnen behandelen die je op weg kunnen helpen met alles wat je te wachten staat.

Kijk uit naar een nieuwe gids in de toekomst, waarin we leren hoe we een rustgevende API kunnen bouwen met Nest en MySQL.

Bedankt voor het lezen!

Aanvullende informatiebronnen

Nest.js Documenten
Hoekige documenten

Tijdstempel:

Meer van Stapelmisbruik