├── .editorconfig ├── .env.example ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── README.md ├── nest-cli.json ├── package-lock.json ├── package.json ├── src ├── app.module.ts ├── app │ └── users │ │ ├── dto │ │ ├── create-user.dto.ts │ │ └── update-user.dto.ts │ │ ├── users.controller.spec.ts │ │ ├── users.controller.ts │ │ ├── users.entity.ts │ │ ├── users.module.ts │ │ ├── users.service.spec.ts │ │ └── users.service.ts ├── auth │ ├── auth.controller.spec.ts │ ├── auth.controller.ts │ ├── auth.module.ts │ ├── auth.service.spec.ts │ ├── auth.service.ts │ └── strategies │ │ ├── jwt.strategy.ts │ │ └── local.strategy.ts ├── helpers │ ├── messages.helper.ts │ └── regex.helper.ts └── main.ts ├── test ├── app.e2e-spec.ts └── jest-e2e.json ├── tsconfig.build.json └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = false 12 | insert_final_newline = false -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | JWT_SECRET_KEY= 2 | 3 | TYPEORM_CONNECTION= 4 | TYPEORM_HOST= 5 | TYPEORM_PORT= 6 | TYPEORM_USERNAME= 7 | TYPEORM_PASSWORD= 8 | TYPEORM_DATABASE= 9 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | project: 'tsconfig.json', 5 | sourceType: 'module', 6 | }, 7 | plugins: ['@typescript-eslint/eslint-plugin'], 8 | extends: [ 9 | 'plugin:@typescript-eslint/recommended', 10 | 'plugin:prettier/recommended', 11 | ], 12 | root: true, 13 | env: { 14 | node: true, 15 | jest: true, 16 | }, 17 | ignorePatterns: ['.eslintrc.js'], 18 | rules: { 19 | '@typescript-eslint/interface-name-prefix': 'off', 20 | '@typescript-eslint/explicit-function-return-type': 'off', 21 | '@typescript-eslint/explicit-module-boundary-types': 'off', 22 | '@typescript-eslint/no-explicit-any': 'off', 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # OS 14 | .DS_Store 15 | 16 | # Tests 17 | /coverage 18 | /.nyc_output 19 | 20 | # IDEs and editors 21 | /.idea 22 | .project 23 | .classpath 24 | .c9/ 25 | *.launch 26 | .settings/ 27 | *.sublime-workspace 28 | 29 | # IDE - VSCode 30 | .vscode/* 31 | !.vscode/settings.json 32 | !.vscode/tasks.json 33 | !.vscode/launch.json 34 | !.vscode/extensions.json 35 | 36 | .env 37 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Nest Logo 3 |

4 | 5 | [circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456 6 | [circleci-url]: https://circleci.com/gh/nestjs/nest 7 | 8 |

A progressive Node.js framework for building efficient and scalable server-side applications.

9 |

10 | NPM Version 11 | Package License 12 | NPM Downloads 13 | CircleCI 14 | Coverage 15 | Discord 16 | Backers on Open Collective 17 | Sponsors on Open Collective 18 | 19 | Support us 20 | 21 |

22 | 24 | 25 | ## Description 26 | 27 | [Nest](https://github.com/nestjs/nest) framework TypeScript starter repository. 28 | 29 | ## Installation 30 | 31 | ```bash 32 | $ npm install 33 | ``` 34 | 35 | ## Running the app 36 | 37 | ```bash 38 | # development 39 | $ npm run start 40 | 41 | # watch mode 42 | $ npm run start:dev 43 | 44 | # production mode 45 | $ npm run start:prod 46 | ``` 47 | 48 | ## Test 49 | 50 | ```bash 51 | # unit tests 52 | $ npm run test 53 | 54 | # e2e tests 55 | $ npm run test:e2e 56 | 57 | # test coverage 58 | $ npm run test:cov 59 | ``` 60 | 61 | ## Support 62 | 63 | Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support). 64 | 65 | ## Stay in touch 66 | 67 | - Author - [Kamil Myśliwiec](https://kamilmysliwiec.com) 68 | - Website - [https://nestjs.com](https://nestjs.com/) 69 | - Twitter - [@nestframework](https://twitter.com/nestframework) 70 | 71 | ## License 72 | 73 | Nest is [MIT licensed](LICENSE). 74 | -------------------------------------------------------------------------------- /nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "@nestjs/schematics", 3 | "sourceRoot": "src" 4 | } 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nestjs-jwt-app", 3 | "version": "0.0.1", 4 | "description": "", 5 | "author": "", 6 | "private": true, 7 | "license": "UNLICENSED", 8 | "scripts": { 9 | "prebuild": "rimraf dist", 10 | "build": "nest build", 11 | "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", 12 | "start": "nest start", 13 | "start:dev": "nest start --watch", 14 | "start:debug": "nest start --debug --watch", 15 | "start:prod": "node dist/main", 16 | "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", 17 | "test": "jest", 18 | "test:watch": "jest --watch", 19 | "test:cov": "jest --coverage", 20 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", 21 | "test:e2e": "jest --config ./test/jest-e2e.json" 22 | }, 23 | "dependencies": { 24 | "@nestjs/common": "^7.6.15", 25 | "@nestjs/config": "^1.0.1", 26 | "@nestjs/core": "^7.6.15", 27 | "@nestjs/jwt": "^8.0.0", 28 | "@nestjs/passport": "^8.0.1", 29 | "@nestjs/platform-express": "^7.6.15", 30 | "@nestjs/typeorm": "^8.0.2", 31 | "bcrypt": "^5.0.1", 32 | "class-transformer": "^0.4.0", 33 | "class-validator": "^0.13.1", 34 | "mariadb": "^2.5.4", 35 | "mysql": "^2.18.1", 36 | "passport": "^0.4.1", 37 | "passport-jwt": "^4.0.0", 38 | "passport-local": "^1.0.0", 39 | "reflect-metadata": "^0.1.13", 40 | "rimraf": "^3.0.2", 41 | "rxjs": "^7.3.0", 42 | "typeorm": "^0.2.37" 43 | }, 44 | "devDependencies": { 45 | "@nestjs/cli": "^7.6.0", 46 | "@nestjs/schematics": "^7.3.0", 47 | "@nestjs/testing": "^7.6.15", 48 | "@types/express": "^4.17.11", 49 | "@types/jest": "^26.0.22", 50 | "@types/node": "^14.14.36", 51 | "@types/passport-jwt": "^3.0.6", 52 | "@types/passport-local": "^1.0.34", 53 | "@types/supertest": "^2.0.10", 54 | "@typescript-eslint/eslint-plugin": "^4.19.0", 55 | "@typescript-eslint/parser": "^4.19.0", 56 | "eslint": "^7.22.0", 57 | "eslint-config-prettier": "^8.1.0", 58 | "eslint-plugin-prettier": "^3.3.1", 59 | "jest": "^26.6.3", 60 | "prettier": "^2.2.1", 61 | "supertest": "^6.1.3", 62 | "ts-jest": "^26.5.4", 63 | "ts-loader": "^8.0.18", 64 | "ts-node": "^9.1.1", 65 | "tsconfig-paths": "^3.9.0", 66 | "typescript": "^4.2.3" 67 | }, 68 | "jest": { 69 | "moduleFileExtensions": [ 70 | "js", 71 | "json", 72 | "ts" 73 | ], 74 | "rootDir": "src", 75 | "testRegex": ".*\\.spec\\.ts$", 76 | "transform": { 77 | "^.+\\.(t|j)s$": "ts-jest" 78 | }, 79 | "collectCoverageFrom": [ 80 | "**/*.(t|j)s" 81 | ], 82 | "coverageDirectory": "../coverage", 83 | "testEnvironment": "node" 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/app.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { ConfigModule } from '@nestjs/config'; 3 | import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm'; 4 | import { UsersModule } from './app/users/users.module'; 5 | import { AuthModule } from './auth/auth.module'; 6 | 7 | @Module({ 8 | imports: [ 9 | ConfigModule.forRoot(), 10 | TypeOrmModule.forRoot({ 11 | type: process.env.TYPEORM_CONNECTION, 12 | host: process.env.TYPEORM_HOST, 13 | port: process.env.TYPEORM_PORT, 14 | username: process.env.TYPEORM_USERNAME, 15 | password: process.env.TYPEORM_PASSWORD, 16 | database: process.env.TYPEORM_DATABASE, 17 | entities: [__dirname + '/**/*.entity{.js,.ts}'], 18 | synchronize: true, 19 | } as TypeOrmModuleOptions), 20 | UsersModule, 21 | AuthModule, 22 | ], 23 | controllers: [], 24 | providers: [], 25 | }) 26 | export class AppModule {} 27 | -------------------------------------------------------------------------------- /src/app/users/dto/create-user.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsEmail, IsNotEmpty, Matches } from 'class-validator'; 2 | import { MessagesHelper } from '../../../helpers/messages.helper'; 3 | import { RegExHelper } from '../../../helpers/regex.helper'; 4 | 5 | export class CreateUserDto { 6 | @IsNotEmpty() 7 | firstName: string; 8 | 9 | @IsNotEmpty() 10 | lastName: string; 11 | 12 | @IsNotEmpty() 13 | @IsEmail() 14 | email: string; 15 | 16 | @IsNotEmpty() 17 | @Matches(RegExHelper.password, { message: MessagesHelper.PASSWORD_VALID }) 18 | password: string; 19 | } 20 | -------------------------------------------------------------------------------- /src/app/users/dto/update-user.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsNotEmpty } from 'class-validator'; 2 | 3 | export class UpdateUserDto { 4 | @IsNotEmpty() 5 | firstName: string; 6 | 7 | @IsNotEmpty() 8 | lastName: string; 9 | } 10 | -------------------------------------------------------------------------------- /src/app/users/users.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { UsersController } from './users.controller'; 3 | 4 | describe('UsersController', () => { 5 | let controller: UsersController; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | controllers: [UsersController], 10 | }).compile(); 11 | 12 | controller = module.get(UsersController); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(controller).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/app/users/users.controller.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Body, 3 | Controller, 4 | Delete, 5 | Get, 6 | HttpCode, 7 | HttpStatus, 8 | Param, 9 | ParseUUIDPipe, 10 | Post, 11 | Put, 12 | UseGuards, 13 | } from '@nestjs/common'; 14 | import { AuthGuard } from '@nestjs/passport'; 15 | import { CreateUserDto } from './dto/create-user.dto'; 16 | import { UpdateUserDto } from './dto/update-user.dto'; 17 | import { UsersService } from './users.service'; 18 | 19 | @Controller('api/v1/users') 20 | @UseGuards(AuthGuard('jwt')) 21 | export class UsersController { 22 | constructor(private readonly usersService: UsersService) {} 23 | 24 | @Get() 25 | async index() { 26 | return await this.usersService.findAll(); 27 | } 28 | 29 | @Post() 30 | async store(@Body() body: CreateUserDto) { 31 | return await this.usersService.store(body); 32 | } 33 | 34 | @Get(':id') 35 | async show(@Param('id', new ParseUUIDPipe()) id: string) { 36 | return await this.usersService.findOneOrFail({ id }); 37 | } 38 | 39 | @Put(':id') 40 | async update( 41 | @Param('id', new ParseUUIDPipe()) id: string, 42 | @Body() body: UpdateUserDto, 43 | ) { 44 | return await this.usersService.update(id, body); 45 | } 46 | 47 | @Delete(':id') 48 | @HttpCode(HttpStatus.NO_CONTENT) 49 | async destroy(@Param('id', new ParseUUIDPipe()) id: string) { 50 | await this.usersService.destroy(id); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/app/users/users.entity.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BeforeInsert, 3 | Column, 4 | CreateDateColumn, 5 | DeleteDateColumn, 6 | Entity, 7 | PrimaryGeneratedColumn, 8 | UpdateDateColumn, 9 | } from 'typeorm'; 10 | import { hashSync } from 'bcrypt'; 11 | 12 | @Entity({ name: 'users' }) 13 | export class UsersEntity { 14 | @PrimaryGeneratedColumn('uuid') 15 | id: string; 16 | 17 | @Column({ name: 'first_name' }) 18 | firstName: string; 19 | 20 | @Column({ name: 'last_name' }) 21 | lastName: string; 22 | 23 | @Column() 24 | email: string; 25 | 26 | @Column() 27 | password: string; 28 | 29 | @CreateDateColumn({ name: 'created_at' }) 30 | createdAt: string; 31 | 32 | @UpdateDateColumn({ name: 'updated_at' }) 33 | updatedAt: string; 34 | 35 | @DeleteDateColumn({ name: 'deleted_at' }) 36 | deletedAt: string; 37 | 38 | @BeforeInsert() 39 | hashPassword() { 40 | this.password = hashSync(this.password, 10); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/app/users/users.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { TypeOrmModule } from '@nestjs/typeorm'; 3 | import { UsersController } from './users.controller'; 4 | import { UsersEntity } from './users.entity'; 5 | import { UsersService } from './users.service'; 6 | 7 | @Module({ 8 | imports: [TypeOrmModule.forFeature([UsersEntity])], 9 | controllers: [UsersController], 10 | providers: [UsersService], 11 | exports: [UsersService], 12 | }) 13 | export class UsersModule {} 14 | -------------------------------------------------------------------------------- /src/app/users/users.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { UsersService } from './users.service'; 3 | 4 | describe('UsersService', () => { 5 | let service: UsersService; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [UsersService], 10 | }).compile(); 11 | 12 | service = module.get(UsersService); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(service).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/app/users/users.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, NotFoundException } from '@nestjs/common'; 2 | import { InjectRepository } from '@nestjs/typeorm'; 3 | import { FindConditions, FindOneOptions, Repository } from 'typeorm'; 4 | import { CreateUserDto } from './dto/create-user.dto'; 5 | import { UpdateUserDto } from './dto/update-user.dto'; 6 | import { UsersEntity } from './users.entity'; 7 | 8 | @Injectable() 9 | export class UsersService { 10 | constructor( 11 | @InjectRepository(UsersEntity) 12 | private readonly usersRepository: Repository, 13 | ) {} 14 | 15 | async findAll() { 16 | return await this.usersRepository.find({ 17 | select: ['id', 'firstName', 'lastName', 'email'], 18 | }); 19 | } 20 | 21 | async findOneOrFail( 22 | conditions: FindConditions, 23 | options?: FindOneOptions, 24 | ) { 25 | try { 26 | return await this.usersRepository.findOneOrFail(conditions, options); 27 | } catch (error) { 28 | throw new NotFoundException(error.message); 29 | } 30 | } 31 | 32 | async store(data: CreateUserDto) { 33 | const user = this.usersRepository.create(data); 34 | return await this.usersRepository.save(user); 35 | } 36 | 37 | async update(id: string, data: UpdateUserDto) { 38 | const user = await this.findOneOrFail({ id }); 39 | this.usersRepository.merge(user, data); 40 | return await this.usersRepository.save(user); 41 | } 42 | 43 | async destroy(id: string) { 44 | await this.usersRepository.findOneOrFail({ id }); 45 | this.usersRepository.softDelete({ id }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/auth/auth.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AuthController } from './auth.controller'; 3 | 4 | describe('AuthController', () => { 5 | let controller: AuthController; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | controllers: [AuthController], 10 | }).compile(); 11 | 12 | controller = module.get(AuthController); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(controller).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/auth/auth.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Post, Req, UseGuards } from '@nestjs/common'; 2 | import { AuthGuard } from '@nestjs/passport'; 3 | import { AuthService } from './auth.service'; 4 | 5 | @Controller('api/auth') 6 | export class AuthController { 7 | constructor(private readonly authService: AuthService) {} 8 | 9 | @UseGuards(AuthGuard('local')) 10 | @Post('login') 11 | async login(@Req() req: any) { 12 | return await this.authService.login(req.user); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/auth/auth.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { ConfigModule } from '@nestjs/config'; 3 | import { JwtModule } from '@nestjs/jwt'; 4 | import { PassportModule } from '@nestjs/passport'; 5 | import { UsersModule } from '../app/users/users.module'; 6 | import { AuthService } from './auth.service'; 7 | import { AuthController } from './auth.controller'; 8 | import { LocalStrategy } from './strategies/local.strategy'; 9 | import { JwtStrategy } from './strategies/jwt.strategy'; 10 | 11 | @Module({ 12 | imports: [ 13 | ConfigModule.forRoot(), 14 | UsersModule, 15 | PassportModule, 16 | JwtModule.register({ 17 | privateKey: process.env.JWT_SECRET_KEY, 18 | signOptions: { expiresIn: '60s' }, 19 | }), 20 | ], 21 | controllers: [AuthController], 22 | providers: [AuthService, LocalStrategy, JwtStrategy], 23 | }) 24 | export class AuthModule {} 25 | -------------------------------------------------------------------------------- /src/auth/auth.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AuthService } from './auth.service'; 3 | 4 | describe('AuthService', () => { 5 | let service: AuthService; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [AuthService], 10 | }).compile(); 11 | 12 | service = module.get(AuthService); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(service).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/auth/auth.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { UsersEntity } from '../app/users/users.entity'; 3 | import { UsersService } from '../app/users/users.service'; 4 | import { compareSync } from 'bcrypt'; 5 | import { JwtService } from '@nestjs/jwt'; 6 | 7 | @Injectable() 8 | export class AuthService { 9 | constructor( 10 | private readonly userService: UsersService, 11 | private readonly jwtService: JwtService, 12 | ) {} 13 | 14 | async login(user) { 15 | const payload = { sub: user.id, email: user.email }; 16 | 17 | return { 18 | token: this.jwtService.sign(payload), 19 | }; 20 | } 21 | 22 | async validateUser(email: string, password: string) { 23 | let user: UsersEntity; 24 | try { 25 | user = await this.userService.findOneOrFail({ email }); 26 | } catch (error) { 27 | return null; 28 | } 29 | 30 | const isPasswordValid = compareSync(password, user.password); 31 | if (!isPasswordValid) return null; 32 | 33 | return user; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/auth/strategies/jwt.strategy.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { PassportStrategy } from '@nestjs/passport'; 3 | import { ExtractJwt, Strategy } from 'passport-jwt'; 4 | 5 | @Injectable() 6 | export class JwtStrategy extends PassportStrategy(Strategy) { 7 | constructor() { 8 | super({ 9 | jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), 10 | ignoreExpiration: false, 11 | secretOrKey: process.env.JWT_SECRET_KEY, 12 | }); 13 | } 14 | 15 | async validate(payload: any) { 16 | return { id: payload.sub, email: payload.email }; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/auth/strategies/local.strategy.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, UnauthorizedException } from '@nestjs/common'; 2 | import { PassportStrategy } from '@nestjs/passport'; 3 | import { Strategy } from 'passport-local'; 4 | import { MessagesHelper } from '../../helpers/messages.helper'; 5 | import { AuthService } from '../auth.service'; 6 | 7 | @Injectable() 8 | export class LocalStrategy extends PassportStrategy(Strategy) { 9 | constructor(private authService: AuthService) { 10 | super({ usernameField: 'email' }); 11 | } 12 | 13 | async validate(email: string, password: string) { 14 | const user = await this.authService.validateUser(email, password); 15 | 16 | if (!user) 17 | throw new UnauthorizedException(MessagesHelper.PASSWORD_OR_EMAIL_INVALID); 18 | 19 | return user; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/helpers/messages.helper.ts: -------------------------------------------------------------------------------- 1 | export const MessagesHelper = { 2 | PASSWORD_VALID: 3 | 'A senha deve conter letras maiúsculas minúsculas, números e caracteres especiais', 4 | PASSWORD_OR_EMAIL_INVALID: 'E-mail e/ou senha são inválidos', 5 | }; 6 | -------------------------------------------------------------------------------- /src/helpers/regex.helper.ts: -------------------------------------------------------------------------------- 1 | const password = 2 | /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$ %^&*-]).{8,}$/; 3 | 4 | export const RegExHelper = { 5 | password, 6 | }; 7 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { ValidationPipe } from '@nestjs/common'; 2 | import { NestFactory } from '@nestjs/core'; 3 | import { AppModule } from './app.module'; 4 | 5 | async function bootstrap() { 6 | const app = await NestFactory.create(AppModule); 7 | app.useGlobalPipes( 8 | new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true }), 9 | ); 10 | await app.listen(3000); 11 | } 12 | bootstrap(); 13 | -------------------------------------------------------------------------------- /test/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { INestApplication } from '@nestjs/common'; 3 | import * as request from 'supertest'; 4 | import { AppModule } from './../src/app.module'; 5 | 6 | describe('AppController (e2e)', () => { 7 | let app: INestApplication; 8 | 9 | beforeEach(async () => { 10 | const moduleFixture: TestingModule = await Test.createTestingModule({ 11 | imports: [AppModule], 12 | }).compile(); 13 | 14 | app = moduleFixture.createNestApplication(); 15 | await app.init(); 16 | }); 17 | 18 | it('/ (GET)', () => { 19 | return request(app.getHttpServer()) 20 | .get('/') 21 | .expect(200) 22 | .expect('Hello World!'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "target": "es2017", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "baseUrl": "./", 13 | "incremental": true 14 | } 15 | } 16 | --------------------------------------------------------------------------------