Valentin Kononov
Full Stack Developer, Speaker
@ValentinKononov
@ValentinKononov
@ValentinKononov
@ValentinKononov
Typescript
Framework
Out-Of-The-Box Features
Inspired by Angular
Same Look and Feel as Angular
Decorators usage to define Metadata
@ValentinKononov
npm install -g @nestjs/cli
npm run start
install node v8.9.0 or higher
nest new Angular-Belarus-Meetup-App
@ValentinKononov
@ValentinKononov
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule, {
logger: new WinstonLogger(),
cors: true,
});
// app configuration here
await app.listen(3001);
}
bootstrap();
@ValentinKononov
import { Module } from '@nestjs/common';
@Module({
imports: [
AuthModule,
UserModule,
MongooseModule.forRoot(
'mongodb://localhost:27017/bundle-node-nest'),
WinstonModule.forRoot({ }),
],
exports: [...],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
@ValentinKononov
Modules
Controllers
Routing
Dependency Injection
Middleware
Pipes
Guards
Exceptions
Interceptors
@ValentinKononov
import { Controller, Get, Post, Put, Delete, Body, Param, Req }
from '@nestjs/common';
@Controller('api/users')
export class UserController {
constructor(private readonly userService: UserService) {}
@Get(':id')
async getById(@Req() req, @Param() id: string) {
return await this.userService.findById(id);
}
@Post()
async create(@Body() user: User) {
return await this.userService.create(user);
}
}
@ValentinKononov
import { Injectable, Scope } from '@nestjs/common';
@Injectable({ scope: Scope.REQUEST })
export class UserService {
public async create(user: any): Promise<UserDto> {
return await createdUser.save();
}
public async findById(id: string): Promise<UserDto> {
return await repository.findById(id);
}
}
Module.exports
Module.providers
Put To
@ValentinKononov
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> {
const request = context.switchToHttp().getRequest();
return validateRequest(request);
}
}
@Controller('api/users')
@UseGuards(AuthGuard)
export class UserController {
...
}
// main.ts
const app = await NestFactory.create(AppModule);
app.useGlobalGuards(new AuthGuard());
@ValentinKononov
@Injectable()
export class TrackInterceptor implements NestInterceptor {
intercept(
context: ExecutionContext, next: CallHandler
): Observable<any> {
logger.log(`Request Started`);
return next.handle()
.pipe(
tap(() => logger.log(`Request completed`)),
);
}
}
@Controller('api/users')
@UseInterceptors(TimeTrackingInterceptor)
export class UserController {
...
}
// main.ts
const app = await NestFactory.create(AppModule);
app.useGlobalInterceptors(new TimeTrackingInterceptor());
@ValentinKononov
import { ExtractJwt, Strategy } from 'passport-jwt';
...
import { PassportStrategy } from '@nestjs/passport';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private readonly authService: AuthService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: process.env.AUTH_JWT_SECRET,
});
}
async validate(payload: JwtPayload) {
const user = await this.authService.validateUser(payload);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
@ValentinKononov
import { JwtModule } from '@nestjs/jwt';
...
import { PassportModule } from '@nestjs/passport';
@Module({
imports: [
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.register({
secretOrPrivateKey: config.auth.jwt.secret,
signOptions: {
expiresIn: config.auth.jwt.ttl,
},
}),
],
controllers: [AuthController],
providers: [AuthService, JwtStrategy],
exports: [PassportModule, AuthService],
})
export class AuthModule {}
@ValentinKononov
import { Controller } from '@nestjs/common';
import { UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Controller('api/users')
@UseGuards(AuthGuard('jwt'))
export class UserController {
...
}
@ValentinKononov
import { JwtService } from '@nestjs/jwt';
private getTokenPayload(user: User): JwtPayload {
return {
email: user.email,
role: user.role,
id: user.id,
};
}
public async signIn(user): Promise<Token> {
const expiresIn = config.auth.jwt.ttl;
const token = this.jwtService.sign(
this.getTokenPayload(user),
{ expiresIn });
return { token };
}
Code Organization
Out of the Box feature
Same Look and Feel as Angular
Real code sharing
Compatibility with TS and JS
Good Documentation
@ValentinKononov
or instead of cons
SOLID node framework based on Express
but you need to follow the structure
If you don't like Angular it might be hard
Could be excess for pure node developer
See you again!
@ValentinKononov
By Valentin Kononov
Presentation about NestJS framework, how it naturally fits Angular frontend