$ npm i -g @nestjs/cli
$ nest new project-name
DTO is the short name of Data Transfer Object. DTO is used in order to validate incoming requests.
There are a few other important concepts in Nest. js: DTO: Data transfer object is an object that defines how data will be sent over the network. Interfaces: TypeScript interfaces are used for type-checking and defining the types of data that can be passed to a controller or a Nest service.
Nest works well with the class-validator library. This powerful library allows you to use decorator-based validation. Decorator-based validation is extremely powerful, especially when combined with Nest's Pipe capabilities since we have access to the metatype of the processed property. Before we start, we need to install the required packages:
npm i --save class-validator class-transformer
import { IsNotEmpty, IsInt } from 'class-valIdator'
import { Type } from 'class-transformer'
export class addCatDTO {
@IsNotEmpty()
name: string;
@IsNotEmpty()
@IsInt()
@Type(() => Number)
age: number;
@IsNotEmpty()
skinColor: string;
@IsNotEmpty()
@IsInt()
@Type(() => Number)
weight: number;
}
in the main.ts file addded:
import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
# TODO: added app.useGlobalPipes(new ValidationPipe());
app.useGlobalPipes(new ValidationPipe());
await app.listen(3000);
}
bootstrap();
you can actually create specific validation to some specific routes also. in your controller.ts file added:
@Post('/addCat')
# TODO: added UsePipes Decorator
@UsePipes(ValidationPipe)
addedCat(
@Res() res: Response,
@Body() payload: addCatDTO): object {
const id = uuidv4()
this.catService.addCat(id, payload)
return res.status(201).json({ message: `successfully added cat with id:${id}` })
}
Prisma is an open source next-generation ORM. installation:
npm install prisma --save-dev
npx prisma init
You can Syncrhonize the database schema to the prisma model
npx prisma db pull
added @prisma/client:
npm i @prisma/client
You can creating prisma schema and injected it to the database
npx prisma db push
npx prisma generate
nest g service prisma
in prisma.service.ts file, setup the database connection:
import { Injectable, INestApplication, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
async onModuleInit() {
await this.$connect();
}
async enableShutdownHooks(app: INestApplication) {
this.$on('beforeExit', async () => {
await app.close();
});
}
}
then creating the prisma module:
nest g module prisma
in prisma module you can setup like this:
import { Module } from '@nestjs/common';
import { PrismaService } from './prisma.service';
@Module({
providers: [PrismaService],
exports: [PrismaService]
})
export class PrismaModule { }
JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.
- Authorization: This is the most common scenario for using JWT. Once the user is logged in, each subsequent request will include the JWT, allowing the user to access routes, services, and resources that are permitted with that token. Single Sign On is a feature that widely uses JWT nowadays, because of its small overhead and its ability to be easily used across different domains.
- Information Exchange: JSON Web Tokens are a good way of securely transmitting information between parties. Because JWTs can be signed—for example, using public/private key pairs—you can be sure the senders are who they say they are. Additionally, as the signature is calculated using the header and the payload, you can also verify that the content hasn't been tampered with.
In its compact form, JSON Web Tokens consist of three parts separated by dots (.), which are:
- Header. The header typically consists of two parts: the type of the token, which is JWT, and the signing algorithm being used, such as HMAC SHA256 or RSA. Note: this JSON is Base64Url encoded to form the first part of the JWT. For Example:
{
"alg": "HS256",
"typ": "JWT"
}
- Payload. The second part of the token is the payload, which contains the claims. Claims are statements about an entity (typically, the user) and additional data. There are three types of claims: registered, public, and private claims. Note that for signed tokens this information, though protected against tampering, is readable by anyone. Do not put secret information in the payload or header elements of a JWT unless it is encrypted. Note: The payload is then Base64Url encoded to form the second part of the JSON Web Token. for Example:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
- Signature. To create the signature part you have to take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign that. For example if you want to use the HMAC SHA256 algorithm. Note: The signature is used to verify the message wasn't changed along the way, and, in the case of tokens signed with a private key, it can also verify that the sender of the JWT is who it says it is.. the signature will be created in the following way:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
In authentication, when the user successfully logs in using their credentials, a JSON Web Token will be returned. Since tokens are credentials, great care must be taken to prevent security issues. In general, you should not keep tokens longer than required.
Whenever the user wants to access a protected route or resource, the user agent should send the JWT, typically in the Authorization header using the Bearer schema. The content of the header should look like the following:
Authorization: Bearer <token>
The lifetime of a refresh token is much longer compared to the lifetime of an access token. Refresh tokens can also expire but are quiet long-lived. When current access tokens expire or become invalid, the authorization server provides refresh tokens to the client to obtain new access token. if Refresh token was expired, then it will be automatically redirect user to the login area.
npm install @nestjs/passport @nestjs/jwt passport passport-jwt
- Create the JWT configuration file:
import { JwtModuleOptions } from "@nestjs/jwt";
export const jwtConfig: JwtModuleOptions = {
secret: process.env.SECRET_KEY,
signOptions: {
expiresIn: 60
}
}
- in auth.module.ts, setup the file:
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt/dist';
import { jwtConfig } from 'config/jwt.config';
import { AuthService } from './auth.service';
@Module({
imports: [JwtModule.register(jwtConfig)],
providers: [AuthService]
})
export class AuthModule { }
- inject the jwtService in auth.service.ts file:
import { JwtService } from '@nestjs/jwt';
@Injectable()
export class AuthService {
constructor(private readonly jwtService: JwtService) { }
}
- Create new file for the jwt strategy:
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
import { jwtConfig } from 'config/jwt.config';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: true,
secretOrKey: jwtConfig.secret,
});
}
async validate(payload: any) {
return { userId: payload.sub, username: payload.username };
}
}
- In module file, added jwtStrategy:
@Module({
providers: [ JwtStrategy],
})
export class someModule { }
- Finally, creating Guard in some route endpoint:
@Get('/findCat/:catId')
@UseGuards(AuthGuard('jwt'))
@HttpCode(200)
async findCatbyId(@Param('catId') catId: string, @Res() res: Response): Promise<object> {
const catById = await this.catService.getCatbyId(catId)
return res.json(catById)
}