Co je NestJS?
NestJS je moderní framework NodeJS, který pod kapotou využívá populární frameworky NodeJS, jako jsou Express a Fastify. NestJS byl z velké části inspirován Angularem, a proto využívá modulový systém ve stylu Angular. NestJS je napsán v TypeScript, i když také podporuje nativní JavaScript.
Předpoklady
Abyste mohli postupovat podle tohoto návodu, musíte splnit následující požadavky
- Kompetence v PostMan nebo jiném testovacím nástroji API.
- Základní znalost aplikací NodeJS a Express.
- Základní znalost TypeScript.
- Kompetence v MongoDB (Mongoose).
Na vašem systému by mělo být nainstalováno následující
- NodeJS v.14 a vyšší.
- Kód Visual Studio (doporučeno) nebo jakékoli jiné IDE.
- PostMan nebo jakýkoli jiný testovací nástroj API.
Běžné terminologie používané v NestJS;
Zde jsou některé z nejčastěji používaných výrazů v NestJS, se kterými se v tomto článku budete často setkávat.
Rozhraní
Rozhraní je definice typu. V důsledku toho se používá jako kontrola/vynucování typu ve funkcích, třídách atd.
interface humanInterface{
name:string;
gender:string;
age:number;
}
const kevin: humanInterface={
name:'Kevin Sunders',
gender:'Male',
age: 25,
}
humanInterface
výše provádí přísnou kontrolu typu na kevin
objekt. Typescript by vyvolal chybu, pokud byste přidali další pole nebo změnili typ některé z vlastností objektu.
Ovladače
Kontroloři mají na starosti přijímání příchozích požadavků a odpovídání klientovi. Řadič spolupracuje se svou přidruženou službou.
Služby
Služba je poskytovatel, který ukládá a získává data a používá se s odpovídajícím správcem.
Dekoratéři
Dekorátor je výraz vracející funkci, který přijímá target
, name
a property descriptor
jako volitelné argumenty. Dekorátoři se píší jako @decorator-name
. Obvykle jsou připojeny k deklaracím tříd, metodám a parametrům.
@Get()
getAll(): Model[] {
return this.testService.getAll();
}
@Get
dekorátor výše označí blok kódu pod ním jako GET
žádost. Více o tom později.
Modul
Modul je část programu, která zpracovává konkrétní úlohu. Modul v NestJS je označen anotací třídy anotované pomocí @Module()
dekoratér. Nest používá metadata poskytnutá @Module()
dekoratér pro uspořádání struktury aplikace.
Instalace CLI
Chcete-li začít, musíte nainstalovat NestJS CLI ****s npm
. Tento krok můžete přeskočit, pokud již máte v systému nainstalováno rozhraní NestJS CLI.
npm i -g @nestjs/cli
Tento blok kódu výše nainstaluje vnořené CLI globálně do vašeho systému.
Vytvoření nového projektu
Chcete-li vygenerovat nový projekt, spusťte nest new
následovaný požadovaným názvem projektu. Pro tento článek napíšeme jednoduché blogové API s funkcí CRUD při dodržení standardů RESTful.
nest new Blog-Api
Tento příkaz vás vyzve k výběru správce balíčků, zvolte npm
.
Tím se celá struktura projektu vytvoří s koncovým bodem testovacího rozhraní API, jehož port je nastaven na 3000
ve výchozím stavu. Můžete to otestovat na http://localhost:3000
po spuštění npm run start:dev
příkaz, který spustí server v režimu sledování podobného tomu, co dělá nodemon v expresních aplikacích.
Po otestování koncového bodu budete muset odstranit některé z výchozích souborů, protože je již nebudete potřebovat. Chcete-li to provést;
- otevřete složku src a uvnitř
- smažte
app.controller.spec.ts
, - smazat
app.controller.ts
, - smazat
app.service.ts
, - Otevřete
app.module.ts
, - Odstraňte odkaz na
AppController
v částicontrollers
pole a importy, - Odstraňte odkaz na
AppService
vproviders
pole a importy.
Možná budete muset změnit soubor README.md
aby splňovaly vaše specifikace.
Váš app.module.ts
soubor by měl vypadat takto,
//app.module.ts
import { Module } from '@nestjs/common';
@Module({
imports: [],
controllers: [],
providers: [],
})
export class AppModule {}
Proměnné prostředí
Je dobrým zvykem, že některé citlivé informace ve vašem kódu by neměly být zveřejňovány. Například váš PORT
a váš MongoDB URI
.
Pojďme to opravit ve vašem kódu.
Při běhu terminálu
npm i dotenv
Poté vytvořte .env
ve vašem adresáři a přidejte jej do .gitignore
soubor. Uložte si PORT
proměnnou, budete muset také uložit svůj MongoDB URI
později na stejném místě. Nyní nahraďte vystavený PORT
ve vašem main.ts
soubor. Chcete-li to provést, importujte dotenv
balíček a zavolejte .config()
metoda na to.
import * as dotenv from 'dotenv';
dotenv.config();
Mělo by to být vaše main.ts
po provedení výše uvedených kroků.
//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();
Generování modulů
Chcete-li vygenerovat modul NestJS pomocí rozhraní CLI NestJS, spusťte níže uvedený fragment kódu.
nest generate module blogs
Tento příkaz vytvoří blogs
složku, která obsahuje blogs.module.ts
soubor a registry BlogsModule
ve vašem app.module.ts
soubor.
Rozhraní pro generování
Pojďme vygenerovat rozhraní pomocí NestJS CLI k provedení kontroly typu objektu, který bude reprezentovat vaše blogové příspěvky. Abyste toho dosáhli, musíte nejprve cd
do blogs
složku, protože se doporučuje, aby byly uloženy v blízkosti objektů domény, ke kterým jsou přidruženy.
cd src/blogs
Poté spusťte níže uvedený fragment kódu a vygenerujte rozhraní.
nest generate interface blogs
tím se vytvoří blogs.interface.ts
soubor. Zde budeme definovat naše rozhraní. rozhraní pojmenujeme BlogsInterface
.
export interface BlogsInterface {
title: string;
body: string;
category: string;
dateCreated: Date;
}
před spuštěním dalších příkazů na vašem terminálu nezapomeňte cd
mimo src
a zpět do kořenové složky spuštěním
cd ../..
Generování služeb a ovladačů
Budete muset vygenerovat třídu služeb pro ukládání a načítání dat a zpracovávat veškerou logiku a třídu řadiče pro zpracování všech příchozích požadavků a odchozích odpovědí.
Služba
Chcete-li vygenerovat službu, spusťte příkaz níže,
nest generate service blogs
Tento příkaz vytvoří dva soubory blogs.service.spec.ts
a blogs.service.ts
a zaregistruje službu u providers
pole v blogs.module.ts
.
Ovladač
Chcete-li vygenerovat ovladač, spusťte příkaz níže,
nest generate controller blogs
Tento příkaz vytvoří dva soubory blogs.controller.spec.ts
a blogs.controller.ts
a zaregistruje ovladač v controllers
pole v blogs.module.ts
.
Díky tomu je struktura vašich blogů téměř kompletní, stačí vytvořit BlogsService
přístupné dalším částem vašeho programu. Můžete toho dosáhnout vytvořením exports
pole v blogs.module.ts
a registraci BlogsService
v tom poli.
//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(Mongus).
Nainstalujte mongoose spuštěním,
npm install --save @nestjs/mongoose mongoose
Po instalaci importujte {MongooseModule}
od '@nestjs/mongoose’
do vašeho app.module.ts
soubor. Poté si vezměte MongoDB URI
a uložte jej do .env
soubor. Opakujte kroky pro import dotenv
v app.module.ts
soubor. Poté v imports
pole volání .forRoot()
metoda, která vezme váš MongoDB URI
jako argument na MongooseModule
. Podobné jako mongoose.connect()
v běžných expresních aplikacích.
@Module({
imports: [BlogsModule, MongooseModule.forRoot(process.env.MONGODB_URI)],
Vytvoření schématu.
Vytvořme schéma, které definuje tvar blogů v naší sbírce. Chcete-li to provést,
- Vytvořte složku ve svých
blogs
složku, pojmenujte jischemas
, - Uvnitř
schemas
vytvořte soubor a nazvěte jejblogs.schema.ts
.
Potom,
Za prvé, budete muset,
- Importujte
prop
dekoratér,Schema
dekoratér aSchemaFactory
od@nestjs/mongoose
, - Vytvořte
Blog
třídy a exportovat, - Změňte třídu na schéma umístěním
@Schema()
dekoratér nad třídou, - Vytvořte konstantní
BlogSchema
, přiřaďte návratovou hodnotu volání.createForClass(Blog)
s názvem vaší třídy jako argumentem naSchemaFactory
které jste importovali dříve.
//blogs.schema.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
@Schema()
export class Blog {}
export const BlogSchema = SchemaFactory.createForClass(Blog);
Poté budete muset definovat vlastnosti schématu.
Chcete-li definovat vlastnost ve schématu, musíte každou z nich označit pomocí @prop()
dekoratér. @prop
dekorátor přijímá objekt options nebo deklaraci komplexního typu. Deklarace komplexních typů mohou být pole a deklarace typu vnořených objektů.
//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);
Další import { Document }
z 'mongoose'
.
Poté vytvořte sjednocovací typ s třídou Schema a importovaným Document
. Jako tak,
//blogs.schema.ts
import { Document } from 'mongoose';
export type BlogDocument = Blog & Document;
Vaše konečné blogs.schema.ts
soubor by měl vypadat takto,
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);
Registrační schéma
Vše budete muset importovat do blogs.module.ts
soubor. Abyste toho dosáhli, musíte,
- Importujte
{MongooseModule}
od'@nestjs/mongoose’
, - Importujte
{Blog, BlogSchema}
z'./schemas/blogs.schema’
- Vytvořte
imports
pole uvnitř@module
dekoratér - Zavolejte
.forFeature()
metoda naMongooseModule
. To zahrnuje pole obsahující objekt, který definujename
aschema
vlastnost, která by měla být nastavena na vášBlog.name
a vašeBlogSchema
respektive.
@Module({
imports: [
MongooseModule.forFeature([{ name: Blog.name, schema: BlogSchema }]),
],
Schéma vstřikování
Budete muset vložit Blog
modelovat do blogs.service.ts
pomocí @InjectModel()
dekoratér. Abyste toho dosáhli, musíte
- importovat
{ Model }
z'mongoose'
, - importujte
{ InjectModel }
od'@nestjs/mongoose’
, - Importujte
{Blog, BlogDocument}
z'./schemas/blogs.schema’
, - Vytvořte
constructor
uvnitřBlogsService
třída, - Prohlásit za
private
proměnnou a nazvěte jiblogModel
a přiřadit typModel<BlogDocument>
k tomu. Na tuto proměnnou budou volány všechny metody mongoose.
Připomeňme si to, BlogDocument
je sjednocený typ Blog
třídy a Model
Mongoose které jste vytvořili dříve. Používá se jako obecný typ pro vaši proměnnou.
- Ozdobte
blogModel
pomocí@InjectModel()
a předejteBlog.name
jako argument.
constructor(
@InjectModel(Blog.name)
private blogModel: Model<BlogDocument>,
) {}
Jak funguje směrování
Nyní jste si museli všimnout, že @Controller
dekoratér má řetězec 'blogs'
přešel do toho. To znamená, že kontrolér odešle všechny odpovědi a zpracuje všechny požadavky provedené na http://localhost/3000/blogs
.
Dále implementujete logiku služeb a ovladače.
Logika služby a řadiče.
Je konečně čas implementovat vaši funkcionalitu CRUD.
Než začneme, budete muset nastavit ovladač. Začněte importem nějakého HTTP
metoda dekoratérů do vašeho ovladače.
//blogs.controller.ts
import {
Controller,
Body,
Delete,
Get,
Post,
Put,
Param,
} from '@nestjs/common';
Poté budete muset službu importovat a zaregistrovat, abyste k ní měli přístup a importovali rozhraní pro kontrolu typu.
//blogs.controller.ts
import { BlogsInterface } from './blogs.interface';
import { BlogsService } from './blogs.service';
Chcete-li zaregistrovat svou službu, vytvořte constructor
uvnitř BlogsController
třídy a deklarujte private readonly
proměnná service
a nastavte jeho typ na BlogsService
.
constructor(private readonly service: BlogsService) {}
Nyní, když je vše nastaveno, můžeme začít.
Vytvořit
Servisní logika
Importujte { BlogsInterface }
z './blogs.interface'
a přidejte async
funkce do BlogsService
třída s názvem createBlog
, který převezme jeden parametr blog
s typem BlogInterface
a jeho návratový typ jako Promise
s obecným <Blog>
typ.
async createBlog(blog: BlogsInterface): Promise<Blog> {
return await new this.blogModel({
...blog,
dateCreated: new Date(),
}).save();
}
Logika řadiče
Ve vašem BlogsController
třídy přidat async
funkce do třídy. Říkejte tomu createBlog
a označte jej pomocí @Post
dekoratér, který jej definuje jako POST
request.createBlog
má jeden parametr blog
s typem BlogInterface
. Označte parametr pomocí @Body
dekoratér, který vyjme celé body
objekt z req
objekt a vyplní dekorovaný parametr hodnotou body
.
@Post()
async createBlog(
@Body()
blog: BlogsInterface,
) {
return await this.service.createBlog(blog);
}
Číst
Přidejte dva async
Metody, jedna pro vrácení jednoho blogového příspěvku a druhá pro vrácení všech blogových příspěvků.
Servisní logika
async getAllBlogs(): Promise<Blog[]> {
return await this.blogModel.find().exec();
}
async getBlog(id: string): Promise<Blog> {
return await this.blogModel.findById(id);
}
Logika řadiče
@Get()
async getAllBlogs() {
return await this.service.getAllBlogs();
}
@Get(':id')
async getBlog(@Param('id') id: string) {
return await this.service.getBlog(id);
}
async
funkce jsou označeny @Get
dekoratér, který jej definuje jako GET
žádost.
Druhý async
dekorátor funkce má argument ':id'
. Což je to, co předáte do @Param
dekoratér. Parametr je označen @Param('id')
který extrahuje params
vlastnost z req
objekt a vyplní dekorovaný parametr hodnotou params
.
Aktualizovat
Pojďme implementovat logiku pro PUT
žádost.
Servisní logika
async updateBlog(id: string, body: BlogsInterface): Promise<Blog> {
return await this.blogModel.findByIdAndUpdate(id, body);
}
Logika řadiče
@Put(':id')
async updateBlog(
@Param('id')
id: string,
@Body()
blog: BlogsInterface,
) {
return await this.service.updateBlog(id, blog);
}
async
druhý parametr funkce je označen @Body()
dekoratér, který vyjme celé body
objekt z req
objekt a vyplní dekorovaný parametr hodnotou body
.
Smazat
Pojďme implementovat logiku pro delete
požadavky.
Servisní logika
async deleteBlog(id: string): Promise<void> {
return await this.blogModel.findByIdAndDelete(id);
}
Promise
generický typ je void
protože Delete
request vrátí prázdný slib.
Logika řadiče
@Delete(':id')
async deleteBlog(@Param('id') id: string) {
return await this.service.deleteBlog(id);
}
Testování rozhraní API
Chcete-li otestovat toto rozhraní API, měli byste použít nástroj pro testování rozhraní API. Pro tento článek použiji populární testovací nástroj API s názvem Postman. K testování budu používat náhodná data o oblíbených tématech.
Vytvořit
Proveďte POST
požadavek na http://localhost/3000/blogs
s následujícími objekty JSON to přidá všechna data do vaší databáze.
{
"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"
}
Měli byste dostat 201
odpověď a vytvořený blog s datem a _id
přidáno.
Číst
Proveďte GET
požadavek na http://localhost/3000/blogs
. To by mělo vrátit a
200
odpověď s polem všech dat, která jste dříve přidali. Zkopírujte _id
vlastnost jednoho z objektů pole.
Vytvořte další GET
požadavek na http://localhost/3000/blogs/id
s dříve zkopírovaným ID. To by mělo vrátit 200
odpověď s daty objektu, jehož ID bylo použito k vytvoření požadavku.
Aktualizovat
Proveďte PUT
požadavek na http://localhost/3000/blogs/id
s níže uvedenými údaji. id
by měl být nahrazen tím, který jste zkopírovali dříve. To by mělo vrátit 200
odpověď a aktualizuje objekt nesoucí id
v zákulisí. pokud spustíte další GET
žádost, měli byste získat aktualizovaný 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"
}
Smazat
Proveďte DELETE
požadavek na http://localhost/3000/blogs/id
.To by mělo vrátit 200
odpověď a odstraní objekt nesoucí id
v zákulisí. pokud spustíte další GET
požadavek, že smazaný objekt neuvidíte.
Závěr
Tak jsme konečně na konci tohoto článku. Pojďme si zrekapitulovat, co jste probrali.
- Co je NestJS,
- Terminologie v NestJS,
- Vytvoření aplikace NestJS,
- Integrace MongoDB do aplikace NestJS,
- Manipulace a aplikace NestJS,
To je docela hodně, gratuluji, že jste to dotáhli tak daleko.
Kód najdete na github.
Hodně štěstí na vaší cestě NestJS!