Hvad er NestJS?
NestJS er et moderne NodeJS-framework, der gør brug af populære NodeJS-frameworks som Express og Fastify under motorhjelmen. NestJS var i høj grad inspireret af Angular, og som et resultat anvender det et modulsystem i Angular-stil. NestJS er skrevet i TypeScript, selvom det også understøtter indbygget JavaScript.
Forudsætninger
For at følge denne vejledning skal du opfylde følgende krav
- Kompetence i PostMan eller ethvert andet API-testværktøj.
- Grundlæggende viden om NodeJS- og Express-apps.
- Grundlæggende kendskab til TypeScript.
- Kompetence i MongoDB(Mongoose).
Følgende skal være installeret på dit system
- NodeJS v.14 og nyere.
- Visual Studio Code (anbefales) eller enhver anden IDE.
- PostMan eller ethvert andet API-testværktøj.
Almindelige terminologier brugt i NestJS;
Her er nogle af de mest almindeligt brugte termer i NestJS, som du vil støde på meget i denne artikel.
Grænseflader
En grænseflade er en typedefinition. Som et resultat bliver det brugt som en typekontrol/enforcer i funktioner, klasser osv.
interface humanInterface{
name:string;
gender:string;
age:number;
}
const kevin: humanInterface={
name:'Kevin Sunders',
gender:'Male',
age: 25,
}
humanInterface
ovenfor udfører streng typekontrol på kevin
objekt. Typescript ville give en fejl, hvis du tilføjede et andet felt eller ændrede typen af en af objektegenskaberne.
Controllere
Controllere er ansvarlige for at modtage indgående forespørgsler og svare på klienten. En controller samarbejder med dens tilknyttede tjeneste.
Tjenester
En tjeneste er en udbyder, der gemmer og henter data og bruges sammen med dens tilsvarende controller.
Dekoratører
En dekoratør er et funktionsreturnerende udtryk, der accepterer et target
, name
, og property descriptor
som valgfrie argumenter. Dekoratorer skrives som @decorator-name
. De er normalt knyttet til klasseerklæringer, metoder og parametre.
@Get()
getAll(): Model[] {
return this.testService.getAll();
}
@Get
decorator ovenfor markerer kodeblokken under den som en GET
anmodning. Mere om det senere.
Modul
Et modul er en del af et program, der håndterer en bestemt opgave. Et modul i NestJS er markeret ved at kommentere en klasse, der er kommenteret med @Module()
dekoratør. Nest bruger de metadata, der leveres af @Module()
dekoratør til at organisere applikationsstrukturen.
Installation af CLI
For at komme i gang skal du installere NestJS CLI ****med npm
. Du kan springe dette trin over, hvis du allerede har NestJS CLI installeret på dit system.
npm i -g @nestjs/cli
Denne kodeblok ovenfor installerer nest CLI globalt på dit system.
Oprettelse af et nyt projekt
For at generere et nyt projekt køres nest new
efterfulgt af dit ønskede projektnavn. Til denne artikel vil vi skrive en simpel blog API med CRUD-funktionalitet, mens vi overholder RESTful-standarder.
nest new Blog-Api
Denne kommando vil bede dig om at vælge en pakkehåndtering, vælg npm
.
Dette vil derefter stilladsere hele projektstrukturen med et test API-slutpunkt, hvis port er indstillet til 3000
som standard. Du kan teste det på http://localhost:3000
efter at have kørt npm run start:dev
kommando, som starter serveren i overvågningstilstand svarende til, hvad nodemon gør i ekspres-apps.
Efter at have testet slutpunktet, bliver du nødt til at slette nogle af standardfilerne, fordi du ikke har brug for dem længere. For at gøre dette;
- åbn src-mappen og inde,
- slet
app.controller.spec.ts
, - slet
app.controller.ts
, - slet
app.service.ts
, - Åbn
app.module.ts
, - Fjern referencen til
AppController
icontrollers
array og importerne, - Fjern referencen til
AppService
iproviders
array og importerne.
Du skal muligvis også ændre README.md
for at opfylde dine specifikationer.
Din app.module.ts
filen skal se sådan ud,
//app.module.ts
import { Module } from '@nestjs/common';
@Module({
imports: [],
controllers: [],
providers: [],
})
export class AppModule {}
Miljøvariabler
Som god praksis bør nogle følsomme oplysninger i din kode ikke offentliggøres. For eksempel din PORT
og din MongoDB URI
.
Lad os rette dette i din kode.
Kør på din terminal
npm i dotenv
Opret derefter en .env
fil i din mappe og tilføj den til din .gitignore
fil. Gem din PORT
variabel, skal du også gemme din MongoDB URI
senere samme sted. Udskift nu den synlige PORT
i din main.ts
fil. For at gøre dette skal du importere dotenv
pakke og kald .config()
metode på det.
import * as dotenv from 'dotenv';
dotenv.config();
Dette bør være din main.ts
fil, når du har fulgt ovenstående trin.
//main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as dotenv from 'dotenv';
dotenv.config();
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(process.env.PORT);
}
bootstrap();
Generering af moduler
For at generere et NestJS-modul ved hjælp af NestJS CLI skal du køre kodestykket nedenfor.
nest generate module blogs
Denne kommando opretter en blogs
mappe, der indeholder en blogs.module.ts
fil og registrerer BlogsModule
i din app.module.ts
fil.
Generering af grænseflader
Lad os generere en grænseflade ved hjælp af NestJS CLI til at udføre typekontrol for det objekt, der repræsenterer dine blogindlæg. For at opnå dette skal du først cd
ind i blogs
mappe, fordi det anbefales, at de opbevares i nærheden af domæneobjekterne, som de er knyttet til.
cd src/blogs
Kør derefter kodestykket nedenfor for at generere grænsefladen.
nest generate interface blogs
dette opretter en blogs.interface.ts
fil. Det er her, vi vil definere vores grænseflade. vi navngiver grænsefladen BlogsInterface
.
export interface BlogsInterface {
title: string;
body: string;
category: string;
dateCreated: Date;
}
før du kører flere kommandoer på din terminal, skal du huske at cd
ud af src
mappe og tilbage til din rodmappe ved at køre
cd ../..
Generering af tjenester og controllere
Du skal generere en serviceklasse for at gemme og hente data og håndtere al logikken og en controllerklasse til at håndtere alle indgående anmodninger og udgående svar.
Service
For at generere en tjeneste skal du køre kommandoen nedenfor,
nest generate service blogs
Denne kommando opretter to filer, blogs.service.spec.ts
og blogs.service.ts
og registrerer tjenesten i providers
array i blogs.module.ts
.
Controller
For at generere en controller skal du køre kommandoen nedenfor,
nest generate controller blogs
Denne kommando opretter to filer, blogs.controller.spec.ts
og blogs.controller.ts
og registrerer controlleren i controllers
array i blogs.module.ts
.
Med disse er din blogstruktur næsten komplet, du skal bare lave BlogsService
tilgængelig for andre dele af dit program. Du kan opnå dette ved at oprette en exports
array i blogs.module.ts
fil og registrering af BlogsService
i det array.
//blogs.module.ts
import { Module } from '@nestjs/common';
import { BlogsService } from './blogs.service';
import { BlogsController } from './blogs.controller';
@Module({
providers: [BlogsService],
controllers: [BlogsController],
exports: [BlogsService],
})
export class BlogsModule {}
MongoDB(Mongoose).
Installer mongoose ved at køre,
npm install --save @nestjs/mongoose mongoose
Efter installationen skal du importere {MongooseModule}
fra '@nestjs/mongoose’
ind i din app.module.ts
fil. Grib derefter din MongoDB URI
og gem det i din .env
fil. Gentag trinene for at importere dotenv
i app.module.ts
fil. Derefter i imports
array kalder .forRoot()
metode, som tager din MongoDB URI
som et argument på MongooseModule
. Svarende til mongoose.connect()
i almindelige ekspres-apps.
@Module({
imports: [BlogsModule, MongooseModule.forRoot(process.env.MONGODB_URI)],
Oprettelse af et skema.
Lad os oprette et skema til at definere formen på bloggene i vores samling. For at gøre dette,
- Opret en mappe i dine
blogs
mappe, navngiv denschemas
, - Inde i
schemas
mappe, opret en fil og kald denblogs.schema.ts
.
Så,
For det første skal du,
- Importer
prop
dekorator,Schema
decorator ogSchemaFactory
fra@nestjs/mongoose
, - Opret en klasse
Blog
og eksporter det, - Gør klassen til et skema ved at placere
@Schema()
dekoratør over klassen, - Opret et konstant
BlogSchema
, tildel returværdien for at kalde.createForClass(Blog)
med navnet på din klasse som argument påSchemaFactory
som du importerede tidligere.
//blogs.schema.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
@Schema()
export class Blog {}
export const BlogSchema = SchemaFactory.createForClass(Blog);
Derefter skal du definere egenskaberne for skemaet.
For at definere en egenskab i skemaet skal du markere hver af dem med @prop()
dekoratør. @prop
dekoratør accepterer et optionobjekt eller en kompleks typeerklæring. De komplekse typeerklæringer kunne være arrays og indlejrede objekttypeerklæringer.
//blogs.schema.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
@Schema()
export class Blog {
@Prop({ required: true })
title: string;
@Prop({ required: true })
body: string;
@Prop({ required: true })
category: string;
@Prop({ required: true })
dateCreated: Date;
}
export const BlogSchema = SchemaFactory.createForClass(Blog);
Næste import { Document }
fra 'mongoose'
.
Opret derefter en unionstype med Schema-klassen og det importerede Document
. Ligesom,
//blogs.schema.ts
import { Document } from 'mongoose';
export type BlogDocument = Blog & Document;
Dine sidste blogs.schema.ts
filen skal se sådan ud,
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';
export type BlogDocument = Blog & Document;
@Schema()
export class Blog {
@Prop({ required: true })
title: string;
@Prop({ required: true })
body: string;
@Prop({ required: true })
category: string;
@Prop({ required: true })
dateCreated: Date;
}
export const BlogSchema = SchemaFactory.createForClass(Blog);
Registrering af skema
Du skal importere alt til din blogs.module.ts
fil. For at opnå dette skal du,
- Importer
{MongooseModule}
fra'@nestjs/mongoose’
, - Importer
{Blog, BlogSchema}
fra'./schemas/blogs.schema’
- Opret en
imports
array inde i@module
dekoratør - Kald
.forFeature()
metode påMongooseModule
. Dette tager et array ind, der indeholder et objekt, der definerer etname
og etschema
egenskab, som skal indstilles til ditBlog.name
og ditBlogSchema
hhv.
@Module({
imports: [
MongooseModule.forFeature([{ name: Blog.name, schema: BlogSchema }]),
],
Injektionsskema
Du skal injicere Blog
model til blogs.service.ts
ved hjælp af @InjectModel()
dekoratør. For at opnå dette skal du
- importer
{ Model }
fra'mongoose'
, - importer
{ InjectModel }
fra'@nestjs/mongoose’
, - Importer
{Blog, BlogDocument}
fra'./schemas/blogs.schema’
, - Opret en
constructor
inde iBlogsService
klasse, - Erklær en
private
variabel og kald denblogModel
og tildel en typeModel<BlogDocument>
til det. Alle mongoose-metoder vil blive kaldt på denne variabel.
Husk det, BlogDocument
er foreningstypen for Blog
klasse og Mongoose Model
som du har oprettet tidligere. Den bruges som generisk type for din variabel.
- Dekorer
blogModel
med@InjectModel()
og sendBlog.name
som et argument.
constructor(
@InjectModel(Blog.name)
private blogModel: Model<BlogDocument>,
) {}
Sådan fungerer routing
Nu må du have bemærket, at @Controller
decorator har strengen 'blogs'
gik ind i det. Det betyder, at controlleren sender alle svar og håndterer alle anmodninger på http://localhost/3000/blogs
.
Dernæst skal du implementere service- og controllerlogikken.
Service- og controllerlogik.
Det er endelig tid til at implementere din CRUD-funktionalitet.
Før vi går i gang, skal du konfigurere din controller. Start med at importere noget HTTP
metode dekoratorer ind i din controller.
//blogs.controller.ts
import {
Controller,
Body,
Delete,
Get,
Post,
Put,
Param,
} from '@nestjs/common';
Derefter skal du importere tjenesten og registrere den, så du kan få adgang til den og importere grænsefladen til typekontrol.
//blogs.controller.ts
import { BlogsInterface } from './blogs.interface';
import { BlogsService } from './blogs.service';
For at registrere din tjeneste skal du oprette en constructor
inde i BlogsController
klasse og erklære en private readonly
variabel service
og indstil dens type til BlogsService
.
constructor(private readonly service: BlogsService) {}
Nu hvor du er klar, lad os komme i gang.
Opret
Servicelogik
Importer { BlogsInterface }
fra './blogs.interface'
og tilføje en async
funktion til BlogsService
klasse kaldet createBlog
, som tager én parameter Blog
, med dens type som BlogInterface
, og dens returtype som et Promise
med en generisk <Blog>
type.
async createBlog(blog: BlogsInterface): Promise<Blog> {
return await new this.blogModel({
...blog,
dateCreated: new Date(),
}).save();
}
Controller Logic
I din BlogsController
klasse tilføje en async
funktion til klassen. Kald det createBlog
og marker det med @Post
dekorator, der definerer det som en POST
anmodning.createBlog
tager én parameter Blog
, med dens type som BlogInterface
. Marker parameteren med @Body
dekorator, som udtrækker hele body
objekt fra req
objekt og udfylder den dekorerede parameter med værdien body
.
@Post()
async createBlog(
@Body()
blog: BlogsInterface,
) {
return await this.service.createBlog(blog);
}
Læs
Tilføj to async
metoder, en til at returnere et enkelt blogindlæg og den anden til at returnere alle blogindlæg.
Servicelogik
async getAllBlogs(): Promise<Blog[]> {
return await this.blogModel.find().exec();
}
async getBlog(id: string): Promise<Blog> {
return await this.blogModel.findById(id);
}
Controller Logic
@Get()
async getAllBlogs() {
return await this.service.getAllBlogs();
}
@Get(':id')
async getBlog(@Param('id') id: string) {
return await this.service.getBlog(id);
}
async
funktioner er markeret med @Get
dekorator, der definerer det som en GET
anmodning.
Den anden async
funktions dekorator har et argument ':id'
. Hvilket er, hvad du vil overføre til @Param
dekoratør. Parameteren er markeret med @Param('id')
som udtrækker params
egenskab fra req
objekt og udfylder den dekorerede parameter med værdien params
.
Opdatering
Lad os implementere logikken for PUT
anmodning.
Servicelogik
async updateBlog(id: string, body: BlogsInterface): Promise<Blog> {
return await this.blogModel.findByIdAndUpdate(id, body);
}
Controller Logic
@Put(':id')
async updateBlog(
@Param('id')
id: string,
@Body()
blog: BlogsInterface,
) {
return await this.service.updateBlog(id, blog);
}
async
funktions anden parameter er markeret med @Body()
dekorator, som udtrækker hele body
objekt fra req
objekt og udfylder den dekorerede parameter med værdien body
.
Slet
Lad os implementere logikken for delete
anmodninger.
Servicelogik
async deleteBlog(id: string): Promise<void> {
return await this.blogModel.findByIdAndDelete(id);
}
Promise
generisk type er void
fordi en Delete
anmodning returnerer et tomt løfte.
Controller Logic
@Delete(':id')
async deleteBlog(@Param('id') id: string) {
return await this.service.deleteBlog(id);
}
Test af API
For at teste denne API skal du bruge et API-testværktøj. Til denne artikel vil jeg bruge et populært API-testværktøj kaldet Postman. Jeg vil bruge tilfældige data om populære emner til at teste.
Opret
Lav en POST
anmodning til http://localhost/3000/blogs
med følgende JSON-objekter vil dette tilføje alle data til din database.
{
"title": "jeen-yuhs",
"body": "The life of superstar rapper Kanye West is currently streaming on Netflix - and according to our jeen-yuhs review, it's a fascinating watch. -credit:Radio Times",
"category":"Music"
}
{
"title": "Why You Should Always Wash Your Hands",
"body": "Germs from unwashed hands can be transferred to other objects, like handrails, tabletops, or toys, and then transferred to another person's hands.-credit cdc.gov",
"category":"Health"
}
{
"title": "Why You Should Follow me on Twitter",
"body": "Well, Because I asked nicely",
"category":"Random"
}
Du bør få en 201
svar og den oprettede blog med en dato og et _id
tilføjet.
Læs
Lav en GET
anmodning til http://localhost/3000/blogs
. Dette skulle returnere en
200
svar med en række af alle de data, du tidligere har tilføjet. Kopiér _id
egenskab for et af array-objekterne.
Lav endnu en GET
anmodning til http://localhost/3000/blogs/id
med det tidligere kopierede id. Dette skulle returnere en 200
svar med dataene for det objekt, hvis id blev brugt til at lave anmodningen.
Opdatering
Lav en PUT
anmodning til http://localhost/3000/blogs/id
med nedenstående data. id
bør erstattes med den, du kopierede tidligere. Dette skulle returnere en 200
svar og opdaterer objektet, der bærer id
bag scenen. hvis du kører en anden GET
anmode om, at du skal få det opdaterede objekt.
{
"title": "why you Should Cut your Nails",
"body": "It's important to trim your nails regularly. Nail trimming together with manicures makes your nails look well-groomed, neat, and tidy.- credit:WebMD",
"category":"Health"
}
Slet
Lav en DELETE
anmodning til http://localhost/3000/blogs/id
.Dette skulle returnere en 200
svar og sletter objektet, der bærer id
bag scenen. hvis du kører en anden GET
anmode om, at du ikke vil se det slettede objekt.
Konklusion
Så er vi endelig ved slutningen af denne artikel. Lad os opsummere, hvad du har dækket.
- Hvad NestJS er,
- Terminologier i NestJS,
- Oprettelse af en NestJS-app,
- Integration af MongoDB i en NestJS-app,
- Manipulation og NestJS-app,
Det er ret meget, tillykke med at du er nået så langt.
Du kan finde koden på github.
Held og lykke på din NestJS-rejse!