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 https://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
AppControllerin decontrollersarray en de invoer, - Verwijder de verwijzing naar
AppServicein deprovidersarray 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
blogsmap, noem hetschemas, - Binnen de
schemasmap, maak een bestand en noem hetblogs.schema.ts.
Dan,
Ten eerste moet je,
- Importeer de
propbinnenhuisarchitect, hetSchemadecorateur, en deSchemaFactoryvan@nestjs/mongoose, - Maak een klas
Blogen 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 opSchemaFactorydie 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
importsarray binnen de@modulebinnenhuisarchitect - Bel de
.forFeature()methode op deMongooseModule. Dit neemt een array in met een object dat eennamedefinieert en eenschemaeigenschap die moet worden ingesteld op uwBlog.nameen jeBlogSchemarespectievelijk.
@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
constructorbinnen deBlogsServiceklas, - Declareer een
privatevariabele en noem hetblogModelen 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
blogModelmet@InjectModel()en geefBlog.namedoor 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 https://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 https://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 https://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 https://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 https://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 https://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!