Getting started with NESTJS
NestJS is a sever side framework based on node.js used to build efficient and scalable server-side application .It uses Javascript and comes along with build in Typescript support
NestJS uses express.js as a default HTTP server frameworks and can be optionally configured to use Fastify
Installation
To create a project from CLI install the nest package globally
$ npm i -g @nestjs/cli
Creating a new project
$ nest new project-name
After scaffolding your project directory should more or less look similar to the below image
Starting point of the application
Main.ts is the staring point of the application which used port 3000 in mycase to listen for api endpoints
The main.ts file will bootstrap the application .All the dependency will be pointed in App module and that module will be imported to the main.ts file
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
bootstrap();
Before divining further we need to know about controller, provider and module in NestJS
Module
It's a good practice to separate each functionality into a module . For example a user module all the functionality like creating / updating /deleting the user will go into this module . Like this we can separate each module
The below command will will generate a module through CLI
nest generate module moduleName
Controller and Provider(Service)
The controller is the point where we write our Api methods like get,put ,post api methods. Below cmd will create a controller from Nest CLI.
nest g controller directory/controller_name
Inorder to delegate the task of database logic we separately write a service to handle the interaction with DB . Below cmd will create a service from Nest CLI.
nest g service directory/service_name
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MongooseModule } from '@nestjs/mongoose';
import { LeagueModule } from './league/league.module';
@Module({
imports: [
MongooseModule.forRoot(
'mongodb+srv://practice:Mongo7$@practice.a2eyo.mongodb.net/League?retryWrites=true&w=majority',
),
LeagueModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
In the above image you can see we have imports , controller , providers We have configure our MongoDB connection in imports .The @nestjs/mongoose package is a NestJS wrapper for mongoDB it work's just like mongoose.connect() express
npm i @nestjs/mongoose mongoose
This below is the schema for the League Model . The Schema is created using the nestjs/mongoose but you can create it using the mongoose ORM as well.
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { HydratedDocument } from 'mongoose';
import * as mongoose from 'mongoose';
export type LeagueDocument = HydratedDocument<LeagueModel>;
const title = new mongoose.Schema({
UCL: { type: Number, require: true },
League: { type: Number, require: true },
});
@Schema({ timestamps: true })
export class LeagueModel {
@Prop({ required: true })
Team: string;
@Prop({ type: title, required: true })
title: typeof title;
@Prop({ required: true })
League: string;
@Prop({ required: true })
marqueePlayer: string;
}
export const LeagueSchema = SchemaFactory.createForClass(LeagueModel);
Explanation about my crud App
Method: Get() ,Post(:id),Put(:id),Delete(:id)
Endpoint:http://localhost:3000/league
Body:
{
"Team": "Real Madrid",
"title": {
"UCL": 14,
"_id": "637a7387c07ba7d9309b386a"
},
"marqueePlayer": "Karim Benzema",
},
This will be JSON data for our endpoint to create the record in the DB .
Wiring up
One import factor to note is the wiring of all controller ,Schema ,Service in League Model.
The league model imports the MongoDB model for this module . The LeagueSchema is being fed to the module to make use of the model
Module is also provided with the controller and provider(the service). Here the module doesn't know about the controller and service to use .We have include the appropriate controller and service in the module
LeagueModel.ts
import { Module } from '@nestjs/common';
import { LeagueControllerController } from './controller/league-controller/league-controller.controller';
import { LeagueServiceService } from './services/league-service/league-service.service';
import { MongooseModule } from '@nestjs/mongoose';
import { LeagueSchema } from '../MongoSchema/League';
@Module({
imports: [
MongooseModule.forFeature([{ name: 'LeagueSchema', schema: LeagueSchema }]),
],
controllers: [LeagueControllerController],
providers: [LeagueServiceService],
})
export class LeagueModule {}
The controller will be the point to get the request object and there after will delegate it to service to handle the DB logic and if everything goes well the controllers will return result with apropriate status code.
league.controller.ts
import {
Controller,
Post,
Body,
HttpStatus,
HttpException,
Delete,
Param,
ParseIntPipe,
Put,
Get,
} from '@nestjs/common';
import { LeagueServiceService } from '../../services/league-service/league-service.service';
import { League } from '../../Dto/league.dto';
import { ValidationPipe } from '../../validation/validation.pipe';
@Controller('league')
export class LeagueControllerController {
constructor(private readonly LeagueServiceService: LeagueServiceService) {}
@Get()
async querydata() {
try {
const data = await this.LeagueServiceService.queryall();
if (data) {
return data;
} else {
throw new HttpException(
{ message: 'Something went wrong! failed to fetch' },
HttpStatus.FAILED_DEPENDENCY,
);
}
} catch (error) {
return { error };
}
}
@Post('/create')
async create(@Body(new ValidationPipe()) league: League) {
try {
const leaguerespose = await this.LeagueServiceService.create(league);
if (leaguerespose) {
return {
messgae: 'created succuessfully',
status: HttpStatus.CREATED,
};
} else {
throw new HttpException('Creation failed', HttpStatus.BAD_REQUEST);
}
} catch (error) {
return { error: error };
}
}
@Delete('remove/:id')
async removeTeam(@Param('id') id: string) {
try {
console.log(id);
const removedStatus = await this.LeagueServiceService.remove(id);
//console.log(removedStatus);
if (removedStatus) {
return {
message: 'Delete successfully',
status: HttpStatus.ACCEPTED,
};
} else {
throw new HttpException(
{ message: 'Failed to delete' },
HttpStatus.BAD_REQUEST,
);
}
} catch (error) {
return new HttpException({ error }, HttpStatus.BAD_REQUEST);
}
}
@Put('/edit/:id')
async Modify(
@Body(new ValidationPipe()) league: League,
@Param('id') id: string,
) {
try {
console.log(league, id);
const modify = await this.LeagueServiceService.modify(id, league);
if (modify) {
return {
message: 'Updates successfully',
status: HttpStatus.ACCEPTED,
};
}
} catch (error) {
return { error: error };
}
}
}
Service(Provider) This acts as a service that will handle to Database logic to write/put to database
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { League } from '../../Dto/league.dto';
import { Connection, Model, sanitizeFilter } from 'mongoose';
import { InjectConnection, InjectModel } from '@nestjs/mongoose';
import { stat } from 'fs';
@Injectable()
export class LeagueServiceService {
constructor(
@InjectModel('LeagueSchema') private readonly LeagueModel: Model<League>,
) {}
async queryall() {
try {
const data = await this.LeagueModel.find();
return data;
} catch (error) {
throw new HttpException(
{ message: 'failed to query data' },
HttpStatus.EXPECTATION_FAILED,
);
}
}
async create(league: League): Promise<League> {
try {
const createLeague = new this.LeagueModel(league);
return await createLeague.save();
} catch (error) {
throw new Error();
}
}
///Get method
async remove(id: string) {
try {
const status = await this.LeagueModel.findByIdAndDelete(id);
// console.log(status + 'Jii');
return status;
} catch (error) {
throw new Error(error);
}
}
async modify(id: string, body: League) {
try {
const data = await this.LeagueModel.findById(id);
const updated = await this.LeagueModel.updateOne({ _id: id }, body);
return updated;
} catch (error) {
throw new HttpException(
{ message: 'Failed to Update' },
HttpStatus.NOT_MODIFIED,
);
}
}
}
Dependency Injection
Dependency injection is basically providing the objects that an object needs (its dependencies) instead of having it construct them itself. It's a very useful technique for testing, since it allows dependencies to be mocked or stubbed out.
NestJS runtime has IOC container where we will be delegating our dependencies and through constructor of class we will use these instance instead of creating a instance with new Keyword.
For more on dependency injection go through the below