Wat is NestJS?
NestJS is een modern NodeJS-framework dat onder de motorkap gebruik maakt van populaire NodeJS-frameworks zoals Express en Fastify. NestJS is grotendeels geïnspireerd door Angular en als gevolg daarvan maakt het gebruik van een Angular-stijl modulesysteem. NestJS is geschreven in TypeScript, hoewel het ook native JavaScript ondersteunt.
Vereisten
Om deze tutorial te volgen, moet je aan de volgende vereisten voldoen
- Competentie in PostMan of een andere API-testtool.
- Basiskennis van NodeJS- en Express-apps.
- Basiskennis van TypeScript.
- Competentie in MongoDB(Mongoose).
Het volgende moet op uw systeem zijn geïnstalleerd
- NodeJS v.14 en hoger.
- Visual Studio-code (aanbevolen) of een andere IDE.
- PostMan of een andere API-testtool.
Veelgebruikte terminologieën in NestJS;
Hier zijn enkele van de meest gebruikte termen in NestJS die je veel zult tegenkomen in dit artikel.
Interfaces
Een interface is een typedefinitie. Als gevolg hiervan wordt het gebruikt als een typecontrole / afdwinger in functies, klassen, enz.
interface humanInterface{
name:string;
gender:string;
age:number;
}
const kevin: humanInterface={
name:'Kevin Sunders',
gender:'Male',
age: 25,
}
De humanInterface
hierboven voert een strikte typecontrole uit op de kevin
voorwerp. Typescript zou een foutmelding geven als u een ander veld zou toevoegen of het type van een van de objecteigenschappen zou wijzigen.
Controllers
Controllers zijn verantwoordelijk voor het ontvangen van inkomende verzoeken en het reageren op de klant. Een verwerkingsverantwoordelijke werkt samen met de bijbehorende dienst.
Diensten
Een service is een provider die gegevens opslaat en ophaalt en wordt gebruikt met de bijbehorende controller.
Decorateurs
Een decorateur is een functie-terugkerende expressie die een target
. accepteert , name
, en property descriptor
als optionele argumenten. Decorateurs worden geschreven als @decorator-name
. Ze zijn meestal gekoppeld aan klassedeclaraties, methoden en parameters.
@Get()
getAll(): Model[] {
return this.testService.getAll();
}
De @Get
decorateur hierboven markeert het codeblok eronder als een GET
verzoek. Daarover later meer.
-module
Een module is een onderdeel van een programma dat een bepaalde taak afhandelt. Een module in NestJS wordt gemarkeerd door een klasse te annoteren met de @Module()
decorateur. Nest gebruikt de metadata van de @Module()
decorateur om de applicatiestructuur te organiseren.
De CLI installeren
Om te beginnen moet je de NestJS CLI ****met npm
. installeren . Je kunt deze stap overslaan als je de NestJS CLI al op je systeem hebt geïnstalleerd.
npm i -g @nestjs/cli
Dit codeblok hierboven zal de nest CLI wereldwijd op uw systeem installeren.
Een nieuw project maken
Om een nieuw project te genereren, voer nest new
uit gevolgd door uw gewenste projectnaam. Voor dit artikel schrijven we een eenvoudige blog-API met CRUD-functionaliteit terwijl we ons houden aan RESTful-normen.
nest new Blog-Api
Deze opdracht zal u vragen om een pakketbeheerder te selecteren, kies npm
.
Dit zal dan de hele projectstructuur ondersteunen met een test-API-eindpunt waarvan de poort is ingesteld op 3000
standaard. Je kunt het testen op http://localhost:3000
na het uitvoeren van de npm run start:dev
commando dat de server in de kijkmodus start, vergelijkbaar met wat nodemon doet in express-apps.
Nadat u het eindpunt hebt getest, moet u enkele van de standaardbestanden verwijderen omdat u ze niet meer nodig hebt. Om dit te doen;
- open de src-map en naar binnen,
- verwijder
app.controller.spec.ts
, - verwijder
app.controller.ts
, - verwijder
app.service.ts
, - Open
app.module.ts
, - Verwijder de verwijzing naar
AppController
in decontrollers
array en de invoer, - Verwijder de verwijzing naar
AppService
in deproviders
array en de invoer.
Mogelijk moet u ook de README.md
. wijzigen om aan uw specificaties te voldoen.
Uw app.module.ts
bestand zou er zo uit moeten zien,
//app.module.ts
import { Module } from '@nestjs/common';
@Module({
imports: [],
controllers: [],
providers: [],
})
export class AppModule {}
Omgevingsvariabelen
Het is een goede gewoonte om bepaalde gevoelige informatie in uw code niet openbaar te maken. Bijvoorbeeld uw PORT
en uw MongoDB URI
.
Laten we dit in je code oplossen.
Op uw terminal uitvoeren
npm i dotenv
Maak vervolgens een .env
bestand in je directory en voeg het toe aan je .gitignore
het dossier. Bewaar uw PORT
variabele, moet u ook uw MongoDB URI
. opslaan later op dezelfde plaats. Vervang nu de blootgestelde PORT
in uw main.ts
het dossier. Importeer hiervoor de dotenv
pakket en roep de .config()
methode erop.
import * as dotenv from 'dotenv';
dotenv.config();
Dit moet uw main.ts
. zijn bestand nadat u de bovenstaande stappen hebt gevolgd.
//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();
Modules genereren
Voer het onderstaande codefragment uit om een NestJS-module te genereren met behulp van de NestJS CLI.
nest generate module blogs
Deze opdracht maakt een blogs
map die een blogs.module.ts
. bevat bestand en registreert BlogsModule
in uw app.module.ts
bestand.
Interfaces genereren
Laten we een interface genereren met behulp van de NestJS CLI om de typecontrole uit te voeren voor het object dat uw blogposts vertegenwoordigt. Om dit te bereiken moet je eerst cd
in de blogs
map omdat het wordt aanbevolen ze op te slaan in de buurt van de domeinobjecten waaraan ze zijn gekoppeld.
cd src/blogs
Voer vervolgens het onderstaande codefragment uit om de interface te genereren.
nest generate interface blogs
dit creëert een blogs.interface.ts
het dossier. Dit is waar we onze interface zullen definiëren. we noemen de interface BlogsInterface
.
export interface BlogsInterface {
title: string;
body: string;
category: string;
dateCreated: Date;
}
Denk eraan om cd
. te doen voordat u meer opdrachten op uw terminal uitvoert uit de src
map en terug naar uw hoofdmap door uit te voeren
cd ../..
Diensten en controllers genereren
U moet een serviceklasse genereren om gegevens op te slaan en op te halen en alle logica en een controllerklasse af te handelen om alle inkomende verzoeken en uitgaande reacties af te handelen.
Dienst
Voer de onderstaande opdracht uit om een service te genereren,
nest generate service blogs
Met deze opdracht worden twee bestanden gemaakt, de blogs.service.spec.ts
en de blogs.service.ts
en registreert de dienst bij de providers
array in de blogs.module.ts
.
Controller
Voer de onderstaande opdracht uit om een controller te genereren,
nest generate controller blogs
Deze opdracht maakt twee bestanden de blogs.controller.spec.ts
en de blogs.controller.ts
en registreert de controller in de controllers
array in de blogs.module.ts
.
Hiermee is je blogstructuur bijna compleet, je hoeft alleen maar de BlogsService
. te maken toegankelijk zijn voor andere delen van uw programma. U kunt dit bereiken door een exports
. aan te maken array in de blogs.module.ts
bestand en het registreren van de BlogsService
in dat rijtje.
//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).
Installeer mangoest door te rennen,
npm install --save @nestjs/mongoose mongoose
Importeer na de installatie {MongooseModule}
van '@nestjs/mongoose’
in uw app.module.ts
het dossier. Pak dan je MongoDB URI
en sla het op in uw .env
het dossier. Herhaal de stappen om dotenv
. te importeren in de app.module.ts
het dossier. Dan in de imports
array roept de .forRoot()
. aan methode die uw MongoDB URI
. neemt als argument op de MongooseModule
. Vergelijkbaar met de mongoose.connect()
in reguliere express-apps.
@Module({
imports: [BlogsModule, MongooseModule.forRoot(process.env.MONGODB_URI)],
Een schema maken.
Laten we een schema maken om de vorm van de blogs in onze collectie te definiëren. Om dit te doen,
- Maak een map in uw
blogs
map, noem hetschemas
, - Binnen de
schemas
map, maak een bestand en noem hetblogs.schema.ts
.
Dan,
Ten eerste moet je,
- Importeer de
prop
binnenhuisarchitect, hetSchema
decorateur, en deSchemaFactory
van@nestjs/mongoose
, - Maak een klas
Blog
en exporteer het, - Verander de klas in een Schema door de
@Schema()
. te plaatsen binnenhuisarchitect boven de klas, - Maak een constante
BlogSchema
, wijs de retourwaarde toe van het aanroepen van de.createForClass(Blog)
met de naam van je klas als argument opSchemaFactory
die je eerder hebt geïmporteerd.
//blogs.schema.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
@Schema()
export class Blog {}
export const BlogSchema = SchemaFactory.createForClass(Blog);
Vervolgens moet u de eigenschappen van het schema definiëren.
Om een eigenschap in het schema te definiëren, moet je ze allemaal markeren met de @prop()
decorateur. De @prop
decorateur accepteert een optie-object of een complexe typeverklaring. De complexe typedeclaraties kunnen arrays en geneste objecttypedeclaraties zijn.
//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);
Volgende import { Document }
van 'mongoose'
.
Maak vervolgens een unietype met de Schema-klasse en het geïmporteerde Document
. zoals zo,
//blogs.schema.ts
import { Document } from 'mongoose';
export type BlogDocument = Blog & Document;
Je laatste blogs.schema.ts
bestand zou er zo uit moeten zien,
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);
Schema registreren
Je moet alles importeren in je blogs.module.ts
het dossier. Om dit te bereiken moet je,
- Importeer
{MongooseModule}
van'@nestjs/mongoose’
, - Importeer
{Blog, BlogSchema}
van'./schemas/blogs.schema’
- Maak een
imports
array binnen de@module
binnenhuisarchitect - Bel de
.forFeature()
methode op deMongooseModule
. Dit neemt een array in met een object dat eenname
definieert en eenschema
eigenschap die moet worden ingesteld op uwBlog.name
en jeBlogSchema
respectievelijk.
@Module({
imports: [
MongooseModule.forFeature([{ name: Blog.name, schema: BlogSchema }]),
],
Schema injecteren
U moet de Blog
. injecteren model in de blogs.service.ts
met behulp van de @InjectModel()
decorateur. Om dit te bereiken moet je
- importeer
{ Model }
van'mongoose'
, - importeer
{ InjectModel }
van'@nestjs/mongoose’
, - Importeer
{Blog, BlogDocument}
van'./schemas/blogs.schema’
, - Maak een
constructor
binnen deBlogsService
klas, - Declareer een
private
variabele en noem hetblogModel
en wijs een typeModel<BlogDocument>
. toe ernaar toe. Alle mangoestmethoden worden op deze variabele aangeroepen.
Bedenk dat, BlogDocument
is het verenigingstype van de Blog
klasse en het Mongoose Model
die u eerder hebt gemaakt. Het wordt gebruikt als het generieke type voor uw variabele.
- Versier
blogModel
met@InjectModel()
en geefBlog.name
door als argument.
constructor(
@InjectModel(Blog.name)
private blogModel: Model<BlogDocument>,
) {}
Hoe routering werkt
Het zal je inmiddels zijn opgevallen dat de @Controller
decorateur heeft de string 'blogs'
erin overgegaan. Dit betekent dat de controller alle antwoorden verzendt en alle verzoeken afhandelt die zijn gedaan op http://localhost/3000/blogs
.
Vervolgens implementeer je de service- en controllerlogica.
Service- en controllerlogica.
Het is eindelijk tijd om uw CRUD-functionaliteit te implementeren.
Voordat we aan de slag gaan, moet je je controller instellen. Begin met het importeren van een aantal HTTP
methode decorateurs in uw controller.
//blogs.controller.ts
import {
Controller,
Body,
Delete,
Get,
Post,
Put,
Param,
} from '@nestjs/common';
Vervolgens moet u de service importeren en registreren, zodat u er toegang toe hebt en de interface kunt importeren voor typecontrole.
//blogs.controller.ts
import { BlogsInterface } from './blogs.interface';
import { BlogsService } from './blogs.service';
Om uw service te registreren, maakt u een constructor
in de BlogsController
class en declareer een private readonly
variabele service
en stel het type in op BlogsService
.
constructor(private readonly service: BlogsService) {}
Nu je helemaal klaar bent, gaan we aan de slag.
Maken
Servicelogica
Importeer { BlogsInterface }
van './blogs.interface'
en voeg een async
toe functie naar de BlogsService
klasse genaamd createBlog
, waarvoor één parameter blog
. nodig is , met als type BlogInterface
, en het retourtype als een Promise
met een generieke <Blog>
type.
async createBlog(blog: BlogsInterface): Promise<Blog> {
return await new this.blogModel({
...blog,
dateCreated: new Date(),
}).save();
}
Controllerlogica
In je BlogsController
class voeg een async
toe functie voor de klas. Noem het createBlog
en markeer het met de @Post
decorateur die het definieert als een POST
request.createBlog
neemt één parameter blog
, met als type BlogInterface
. Markeer de parameter met @Body
decorateur die de hele body
. extraheert object van de req
object en vult de versierde parameter met de waarde van body
.
@Post()
async createBlog(
@Body()
blog: BlogsInterface,
) {
return await this.service.createBlog(blog);
}
Lees
Voeg twee async
. toe methoden, een om een enkele blogpost te retourneren en de tweede om alle blogposts te retourneren.
Servicelogica
async getAllBlogs(): Promise<Blog[]> {
return await this.blogModel.find().exec();
}
async getBlog(id: string): Promise<Blog> {
return await this.blogModel.findById(id);
}
Controllerlogica
@Get()
async getAllBlogs() {
return await this.service.getAllBlogs();
}
@Get(':id')
async getBlog(@Param('id') id: string) {
return await this.service.getBlog(id);
}
De async
functies zijn gemarkeerd met de @Get
decorateur die het definieert als een GET
verzoek.
De tweede async
de decorateur van de functie heeft een argument ':id'
. Dat is wat u doorgeeft aan de @Param
decorateur. De parameter is gemarkeerd met de @Param('id')
die de params
. extraheert eigenschap van de req
object en vult de versierde parameter met de waarde van params
.
Bijwerken
Laten we de logica implementeren voor de PUT
verzoek.
Servicelogica
async updateBlog(id: string, body: BlogsInterface): Promise<Blog> {
return await this.blogModel.findByIdAndUpdate(id, body);
}
Controllerlogica
@Put(':id')
async updateBlog(
@Param('id')
id: string,
@Body()
blog: BlogsInterface,
) {
return await this.service.updateBlog(id, blog);
}
De async
de tweede parameter van de functie is gemarkeerd met de @Body()
decorateur die de hele body
. extraheert object van de req
object en vult de versierde parameter met de waarde van body
.
Verwijderen
Laten we de logica voor delete
implementeren verzoeken.
Servicelogica
async deleteBlog(id: string): Promise<void> {
return await this.blogModel.findByIdAndDelete(id);
}
De Promise
generiek type is void
omdat een Delete
verzoek retourneert een loze belofte.
Controllerlogica
@Delete(':id')
async deleteBlog(@Param('id') id: string) {
return await this.service.deleteBlog(id);
}
De API testen
Om deze API te testen, moet u een API-testtool gebruiken. Voor dit artikel gebruik ik een populaire API-testtool genaamd Postman. Ik gebruik willekeurige gegevens over populaire onderwerpen om te testen.
Maken
Maak een POST
verzoek aan http://localhost/3000/blogs
met de volgende JSON-objecten, zal dit alle gegevens aan uw database toevoegen.
{
"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"
}
Je zou een 201
. moeten krijgen reactie en de gemaakte blog met een datum en een _id
toegevoegd.
Lees
Maak een GET
verzoek aan http://localhost/3000/blogs
. Dit zou een
200
antwoord met een array van alle gegevens die u eerder hebt toegevoegd. Kopieer de _id
eigenschap van een van de array-objecten.
Maak nog een GET
verzoek aan http://localhost/3000/blogs/id
met de eerder gekopieerde id. Dit zou een 200
. moeten opleveren antwoord met de gegevens van het object waarvan de id is gebruikt om het verzoek te doen.
Bijwerken
Maak een PUT
verzoek aan http://localhost/3000/blogs/id
met onderstaande gegevens. De id
moet worden vervangen door degene die u eerder hebt gekopieerd. Dit zou een 200
. moeten opleveren antwoord en werkt het object bij met de id
Achter de schermen. als je een andere GET
. uitvoert verzoek moet u het bijgewerkte object krijgen.
{
"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"
}
Verwijderen
Maak een DELETE
verzoek aan http://localhost/3000/blogs/id
.Dit zou een 200
moeten opleveren antwoord en verwijdert het object met de id
Achter de schermen. als je een andere GET
. uitvoert verzoek zult u het verwijderde object niet zien.
Conclusie
Dus we zijn eindelijk aan het einde van dit artikel. Laten we samenvatten wat je hebt behandeld.
- Wat NestJS is,
- Terminologieën in NestJS,
- Een NestJS-app maken,
- MongoDB integreren in een NestJS-app,
- Manipuleren en NestJS-app,
Dat is best veel, gefeliciteerd dat je zo ver bent gekomen.
Je kunt de code vinden op github.
Veel succes op je NestJS-reis!