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å http://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
AppController
icontrollers
array och importerna, - Ta bort referensen till
AppService
iproviders
array 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
blogs
mapp, döp den tillschemas
, - Inuti
schemas
mapp, skapa en fil och kalla denblogs.schema.ts
.
Sedan,
För det första måste du,
- Importera
prop
dekoratör,Schema
decorator ochSchemaFactory
från@nestjs/mongoose
, - Skapa en klass
blogs
och 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åSchemaFactory
som 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
imports
array inuti@module
dekoratör - Anropa
.forFeature()
metod påMongooseModule
. Detta tar in en array som innehåller ett objekt som definierar ettname
och ettschema
egenskap som ska ställas in på dittBlog.name
och dittBlogSchema
respektive.
@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
constructor
inutiBlogsService
klass, - Deklarera en
private
variabel och kalla denblogModel
och 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
blogModel
med@InjectModel()
och skickaBlog.name
som 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å http://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 http://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 http://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 http://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 http://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 http://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!