Vad är NestJS?
NestJS är ett modernt NodeJS-ramverk som använder sig av populära NodeJS-ramverk som Express och Fastify under huven. NestJS var till stor del inspirerad av Angular, och som ett resultat använder det ett modulsystem i Angular-stil. NestJS är skrivet i TypeScript, även om det också stöder inbyggt JavaScript.
Förutsättningar
För att följa denna handledning måste du uppfylla följande krav
- Kompetens i PostMan eller något annat API-testverktyg.
- Grundläggande kunskaper om NodeJS- och Express-appar.
- Grundläggande kunskaper om TypeScript.
- Kompetens i MongoDB(Mongoose).
Följande bör installeras på ditt system
- NodeJS v.14 och högre.
- Visual Studio Code (rekommenderas) eller någon annan IDE.
- PostMan eller något annat API-testverktyg.
Vanliga terminologier som används i NestJS;
Här är några av de mest använda termerna i NestJS som du kommer att stöta på mycket i den här artikeln.
Gränssnitt
Ett gränssnitt är en typdefinition. Som ett resultat används den som en typkontroll/enforcer i funktioner, klasser etc.
interface humanInterface{
name:string;
gender:string;
age:number;
}
const kevin: humanInterface={
name:'Kevin Sunders',
gender:'Male',
age: 25,
}
humanInterface ovan utför strikt typkontroll på kevin objekt. Typescript skulle ge ett felmeddelande om du lade till ett annat fält eller ändrade typen av någon av objektegenskaperna.
Styrenheter
Controllers ansvarar för att ta emot inkommande förfrågningar och svara på klienten. En styrenhet samarbetar med sin tillhörande tjänst.
Tjänster
En tjänst är en leverantör som lagrar och hämtar data och som används med dess motsvarande kontrollant.
Dekoratörer
En dekoratör är ett funktionsreturnerande uttryck som accepterar ett target , name och property descriptor som valfria argument. Dekoratörer skrivs som @decorator-name . De är vanligtvis kopplade till klassdeklarationer, metoder och parametrar.
@Get()
getAll(): Model[] {
return this.testService.getAll();
}
@Get decorator ovan markerar kodblocket under det som en GET begäran. Mer om det senare.
Modul
En modul är en del av ett program som hanterar en viss uppgift. En modul i NestJS markeras genom att kommentera en klass som är kommenterad med @Module() dekoratör. Nest använder metadata som tillhandahålls av @Module() dekoratör för att organisera applikationsstrukturen.
Installera CLI
För att komma igång måste du installera NestJS CLI ****med npm . Du kan hoppa över det här steget om du redan har NestJS CLI installerat på ditt system.
npm i -g @nestjs/cli
Detta kodblock ovan kommer att installera Nest CLI globalt på ditt system.
Skapa ett nytt projekt
För att skapa ett nytt projekt kör nest new följt av ditt önskade projektnamn. För den här artikeln kommer vi att skriva ett enkelt blogg-API med CRUD-funktionalitet samtidigt som vi följer RESTful-standarderna.
nest new Blog-Api
Detta kommando kommer att uppmana dig att välja en pakethanterare, välj npm .
Detta kommer sedan att bygga hela projektstrukturen med en test-API-slutpunkt vars port är inställd på 3000 som standard. Du kan testa det på https://localhost:3000 efter att ha kört npm run start:dev kommando som startar servern i bevakningsläge liknande vad nodemon gör i expressappar.
Efter att ha testat slutpunkten måste du ta bort några av standardfilerna eftersom du inte kommer att behöva dem längre. För att göra detta;
- öppna src-mappen och inuti,
- ta bort
app.controller.spec.ts, - ta bort
app.controller.ts, - ta bort
app.service.ts, - Öppna
app.module.ts, - Ta bort referensen till
AppControllericontrollersarray och importerna, - Ta bort referensen till
AppServiceiprovidersarray och importerna.
Du kan också behöva ändra README.md för att uppfylla dina specifikationer.
Din app.module.ts filen ska se ut så här,
//app.module.ts
import { Module } from '@nestjs/common';
@Module({
imports: [],
controllers: [],
providers: [],
})
export class AppModule {}
Miljövariabler
Som god praxis bör viss känslig information i din kod inte offentliggöras. Till exempel din PORT och din MongoDB URI .
Låt oss fixa detta i din kod.
Kör på din terminal
npm i dotenv
Skapa sedan en .env filen i din katalog och lägg till den i din .gitignore fil. Lagra din PORT variabel måste du också lagra din MongoDB URI senare på samma plats. Byt nu ut den exponerade PORT i din main.ts fil. För att göra detta, importera dotenv paketera och anropa .config() metod på det.
import * as dotenv from 'dotenv';
dotenv.config();
Detta bör vara din main.ts fil efter att du följt stegen ovan.
//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();
Generera moduler
För att generera en NestJS-modul med NestJS CLI, kör kodavsnittet nedan.
nest generate module blogs
Detta kommando skapar en blogs mapp som innehåller en blogs.module.ts fil och registrerar BlogsModule i din app.module.ts fil.
Generera gränssnitt
Låt oss skapa ett gränssnitt med NestJS CLI för att göra typkontrollen för objektet som kommer att representera dina blogginlägg. För att uppnå detta måste du först cd i blogs mapp eftersom det rekommenderas att de lagras nära domänobjekten som de är kopplade till.
cd src/blogs
Kör sedan kodavsnittet nedan för att generera gränssnittet.
nest generate interface blogs
detta skapar en blogs.interface.ts fil. Det är här vi kommer att definiera vårt gränssnitt. vi kommer att döpa gränssnittet till BlogsInterface .
export interface BlogsInterface {
title: string;
body: string;
category: string;
dateCreated: Date;
}
innan du kör några fler kommandon på din terminal, kom ihåg att cd ur src mapp och tillbaka till din rotmapp genom att köra
cd ../..
Generera tjänster och kontroller
Du måste skapa en serviceklass för att lagra och hämta data och hantera all logik och en kontrollklass för att hantera alla inkommande förfrågningar och utgående svar.
Tjänst
För att generera en tjänst kör kommandot nedan,
nest generate service blogs
Detta kommando skapar två filer blogs.service.spec.ts och blogs.service.ts och registrerar tjänsten i providers array i blogs.module.ts .
Styrenhet
För att generera en styrenhet kör kommandot nedan,
nest generate controller blogs
Detta kommando skapar två filer blogs.controller.spec.ts och blogs.controller.ts och registrerar styrenheten i controllers array i blogs.module.ts .
Med dessa är din bloggstruktur nästan komplett, du behöver bara göra BlogsService tillgänglig för andra delar av ditt program. Du kan uppnå detta genom att skapa en exports array i blogs.module.ts fil och registrera BlogsService i den uppsättningen.
//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(Mongos).
Installera mongoose genom att köra,
npm install --save @nestjs/mongoose mongoose
Efter installationen, importera {MongooseModule} från '@nestjs/mongoose’ till din app.module.ts fil. Ta sedan din MongoDB URI och lagra den i din .env fil. Upprepa stegen för att importera dotenv i app.module.ts fil. Sedan i imports array anropar .forRoot() metod som tar din MongoDB URI som ett argument på MongooseModule . Liknar mongoose.connect() i vanliga expressappar.
@Module({
imports: [BlogsModule, MongooseModule.forRoot(process.env.MONGODB_URI)],
Skapa ett schema.
Låt oss skapa ett schema för att definiera formen på bloggarna i vår samling. För att göra detta,
- Skapa en mapp i dina
blogsmapp, döp den tillschemas, - Inuti
schemasmapp, skapa en fil och kalla denblogs.schema.ts.
Sedan,
För det första måste du,
- Importera
propdekoratör,Schemadecorator ochSchemaFactoryfrån@nestjs/mongoose, - Skapa en klass
blogsoch exportera den, - Förvandla klassen till ett schema genom att placera
@Schema()dekoratör ovanför klassen, - Skapa ett konstant
BlogSchema, tilldela returvärdet för att anropa.createForClass(Blog)med namnet på din klass som argument påSchemaFactorysom du importerade tidigare.
//blogs.schema.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
@Schema()
export class Blog {}
export const BlogSchema = SchemaFactory.createForClass(Blog);
Sedan måste du definiera egenskaperna för schemat.
För att definiera en egenskap i schemat måste du markera var och en av dem med @prop() dekoratör. @prop decorator accepterar ett alternativobjekt eller en komplex typdeklaration. De komplexa typdeklarationerna kan vara arrayer och kapslade objekttypsdeklarationer.
//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ästa import { Document } från 'mongoose' .
Skapa sedan en fackföreningstyp med Schema-klassen och det importerade Document . Såhär,
//blogs.schema.ts
import { Document } from 'mongoose';
export type BlogDocument = Blog & Document;
Din sista blogs.schema.ts filen ska se ut så här,
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);
Registreringsschema
Du måste importera allt till din blogs.module.ts fil. För att uppnå detta måste du,
- Importera
{MongooseModule}från'@nestjs/mongoose’, - Importera
{Blog, BlogSchema}från'./schemas/blogs.schema’ - Skapa en
importsarray inuti@moduledekoratör - Anropa
.forFeature()metod påMongooseModule. Detta tar in en array som innehåller ett objekt som definierar ettnameoch ettschemaegenskap som ska ställas in på dittBlog.nameoch dittBlogSchemarespektive.
@Module({
imports: [
MongooseModule.forFeature([{ name: Blog.name, schema: BlogSchema }]),
],
Injektionsschema
Du måste injicera Blog modell till blogs.service.ts med @InjectModel() dekoratör. För att uppnå detta måste du
- importera
{ Model }från'mongoose', - importera
{ InjectModel }från'@nestjs/mongoose’, - Importera
{Blog, BlogDocument}från'./schemas/blogs.schema’, - Skapa en
constructorinutiBlogsServiceklass, - Deklarera en
privatevariabel och kalla denblogModeloch tilldela en typ avModel<BlogDocument>till det. Alla mongoose-metoder kommer att anropas på denna variabel.
Kom ihåg det, BlogDocument är fackföreningstypen för Blog klass och Mongoose Model som du skapade tidigare. Den används som generisk typ för din variabel.
- Dekorera
blogModelmed@InjectModel()och skickaBlog.namesom argument.
constructor(
@InjectModel(Blog.name)
private blogModel: Model<BlogDocument>,
) {}
Hur routing fungerar
Vid det här laget måste du ha märkt att @Controller decorator har strängen 'blogs' gått in i det. Detta innebär att kontrollern kommer att skicka alla svar och hantera alla förfrågningar som görs på https://localhost/3000/blogs .
Nästa upp kommer du att implementera tjänsten och styrenhetens logik.
Service- och kontrolllogik.
Det är äntligen dags att implementera din CRUD-funktionalitet.
Innan vi börjar måste du konfigurera din kontroller. Börja med att importera lite HTTP metoddekoratörer i din handkontroll.
//blogs.controller.ts
import {
Controller,
Body,
Delete,
Get,
Post,
Put,
Param,
} from '@nestjs/common';
Sedan måste du importera tjänsten och registrera den så att du kan komma åt den och importera gränssnittet för typkontroll.
//blogs.controller.ts
import { BlogsInterface } from './blogs.interface';
import { BlogsService } from './blogs.service';
Skapa en constructor för att registrera din tjänst inuti BlogsController klass och deklarera en private readonly variabel service och ställ in dess typ till BlogsService .
constructor(private readonly service: BlogsService) {}
Nu när du är klar, låt oss komma igång.
Skapa
Servicelogik
Importera { BlogsInterface } från './blogs.interface' och lägg till en async funktion till BlogsService klass som heter createBlog , som tar en parameter blogs , med dess typ som BlogInterface , och dess returtyp som ett Promise med en generisk <Blog> typ.
async createBlog(blog: BlogsInterface): Promise<Blog> {
return await new this.blogModel({
...blog,
dateCreated: new Date(),
}).save();
}
Controller Logic
I din BlogsController klass lägga till en async funktion till klassen. Kalla det createBlog och markera den med @Post dekorator som definierar det som ett POST begäran.createBlog tar en parameter blogs , med dess typ som BlogInterface . Markera parametern med @Body dekoratör som extraherar hela body objekt från req objekt och fyller i den dekorerade parametern med värdet body .
@Post()
async createBlog(
@Body()
blog: BlogsInterface,
) {
return await this.service.createBlog(blog);
}
Läs
Lägg till två async metoder, en för att returnera ett enda blogginlägg och den andra för att returnera alla blogginlägg.
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 är markerade med @Get dekorator som definierar det som en GET begäran.
Den andra async funktionens dekorator har ett argument ':id' . Vilket är vad du skickar till @Param dekoratör. Parametern är markerad med @Param('id') som extraherar params egenskap från req objekt och fyller i den dekorerade parametern med värdet för params .
Uppdatera
Låt oss implementera logiken för PUT begäran.
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 andra parameter är markerad med @Body() dekoratör som extraherar hela body objekt från req objekt och fyller i den dekorerade parametern med värdet body .
Ta bort
Låt oss implementera logiken för delete förfrågningar.
Servicelogik
async deleteBlog(id: string): Promise<void> {
return await this.blogModel.findByIdAndDelete(id);
}
Promise generisk typ är void eftersom en Delete begäran returnerar ett tomt löfte.
Controller Logic
@Delete(':id')
async deleteBlog(@Param('id') id: string) {
return await this.service.deleteBlog(id);
}
Testar API
För att testa detta API bör du använda ett API-testverktyg. För den här artikeln kommer jag att använda ett populärt API-testverktyg som heter Postman. Jag kommer att använda slumpmässig information om populära ämnen för att testa.
Skapa
Gör ett POST begäran till https://localhost/3000/blogs med följande JSON-objekt kommer detta att lägga till all data till din databas.
{
"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 och den skapade bloggen med ett datum och ett _id lagt till.
Läs
Gör en GET begäran till https://localhost/3000/blogs . Detta bör returnera en
200 svar med en uppsättning av all data du tidigare lagt till. Kopiera _id egenskap hos ett av arrayobjekten.
Gör en annan GET begäran till https://localhost/3000/blogs/id med det tidigare kopierade id. Detta bör returnera en 200 svar med data för objektet vars id användes för att göra begäran.
Uppdatera
Gör en PUT begäran till https://localhost/3000/blogs/id med uppgifterna nedan. id bör ersättas med den du kopierade tidigare. Detta bör returnera en 200 svar och uppdaterar objektet som bär id bakom kulisserna. om du kör en annan GET begäran bör du få det uppdaterade objektet.
{
"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"
}
Ta bort
Gör en DELETE begäran till https://localhost/3000/blogs/id .Detta bör returnera en 200 svar och tar bort objektet som bär id bakom kulisserna. om du kör en annan GET begäran kommer du inte att se det borttagna objektet.
Slutsats
Så vi är äntligen i slutet av den här artikeln. Låt oss sammanfatta vad du har täckt.
- Vad NestJS är,
- Terminologier i NestJS,
- Skapa en NestJS-app,
- Integrera MongoDB i en NestJS-app,
- Manipulation och NestJS-app,
Det är ganska mycket, grattis till att du har kommit så långt.
Du kan hitta koden på github.
Lycka till på din NestJS-resa!