Skip to content

Commit f56a6ac

Browse files
joi pipe validations
1 parent 6e94694 commit f56a6ac

File tree

11 files changed

+188
-21
lines changed

11 files changed

+188
-21
lines changed

package-lock.json

Lines changed: 52 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
"migrations:generate": "npm run typeorm -- migration:generate -n",
1111
"migrations:run": "npm run typeorm -- migration:run",
1212
"migrations:show": "npm run typeorm -- migration:show",
13-
1413
"prebuild": "rimraf dist",
1514
"build": "nest build",
1615
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
@@ -32,6 +31,7 @@
3231
"@nestjs/platform-express": "^7.6.15",
3332
"@nestjs/typeorm": "^7.1.5",
3433
"dotenv": "^10.0.0",
34+
"joi": "^17.4.0",
3535
"pg": "^8.6.0",
3636
"reflect-metadata": "^0.1.13",
3737
"rimraf": "^3.0.2",
@@ -44,6 +44,7 @@
4444
"@nestjs/testing": "^7.6.15",
4545
"@types/express": "^4.17.11",
4646
"@types/jest": "^26.0.22",
47+
"@types/joi": "^17.2.3",
4748
"@types/node": "^14.14.36",
4849
"@types/pg": "^8.6.0",
4950
"@types/supertest": "^2.0.10",
@@ -78,4 +79,4 @@
7879
"coverageDirectory": "../coverage",
7980
"testEnvironment": "node"
8081
}
81-
}
82+
}
Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1-
import { Controller, Res, Get, Post, Param, Query, Body, Put, Delete, HttpStatus, HttpCode } from '@nestjs/common';
2-
import { Response } from "express"
1+
import {
2+
Controller, Get, Post, Param, Query, Body, Put, Delete, HttpStatus, HttpCode
3+
, ParseIntPipe, UsePipes
4+
} from '@nestjs/common';
5+
//import { Response } from "express"
6+
import { JoiValidationPipe } from '../../pipe/joi-validation.pipe'
37
import { DatabaseService } from './../../services/database/database.service';
8+
import { projectSchema } from './../../schemas/project.schema';
9+
10+
411
@Controller('project')
512
export class ProjectsController {
613
constructor(private databaseService: DatabaseService) { }
714
@Get(":projectID")
815
@HttpCode(HttpStatus.FOUND)
9-
async get(@Param("projectID") projectID: number): Promise<object> {
16+
async get(@Param("projectID", ParseIntPipe) projectID: number): Promise<object> {
1017
return { data: await this.databaseService.getProject(projectID) }//AppService.getProject(projectID);
1118
}
1219
@Get()
@@ -16,6 +23,7 @@ export class ProjectsController {
1623
}
1724
@Post()
1825
@HttpCode(HttpStatus.CREATED)
26+
@UsePipes(new JoiValidationPipe(projectSchema))
1927
async create(@Body() payload: any): Promise<object> {
2028
const { name, description, location } = payload
2129
let newProduct = await this.databaseService.createProject(name, description, location)
@@ -24,18 +32,12 @@ export class ProjectsController {
2432
}
2533
@Put(":projectID")
2634
@HttpCode(HttpStatus.ACCEPTED)
27-
async update(@Param("projectID") projectID: number, @Body() payload: any): Promise<object> {
35+
async update(@Param("projectID", ParseIntPipe) projectID: number, @Body(new JoiValidationPipe(projectSchema)) payload: any): Promise<object> {
2836
return { msg: "updated", data: await this.databaseService.updateProject(projectID, payload) }
2937
}
3038
@Delete(":projectID")
31-
async delete(@Res() response: Response, @Param("projectID") projectID: number) {
39+
async delete(@Param("projectID", ParseIntPipe) projectID: number): Promise<object> {
3240
let deleted = await this.databaseService.deleteProject(projectID)
33-
let status = HttpStatus.OK,
34-
res = { msg: "deleted" }
35-
if (!deleted) {
36-
res.msg = "not found"
37-
status = HttpStatus.NOT_FOUND
38-
}
39-
response.status(status).send(res)
41+
return { msg: "deleted" }
4042
}
4143
}

src/entities/language.entity.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import {
2+
PrimaryGeneratedColumn,
3+
Column,
4+
Entity,
5+
CreateDateColumn,
6+
UpdateDateColumn
7+
} from 'typeorm';
8+
9+
@Entity()
10+
export class Language {
11+
@PrimaryGeneratedColumn()
12+
id: number;
13+
14+
@Column({ type: 'varchar', length: 50, unique: true })
15+
name: string;
16+
17+
@CreateDateColumn({ type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
18+
creationDate: string;
19+
20+
@UpdateDateColumn({ type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
21+
upadatenDate: string;
22+
}

src/entities/user.entity.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import {
2+
PrimaryGeneratedColumn,
3+
Column,
4+
Entity,
5+
CreateDateColumn,
6+
UpdateDateColumn
7+
} from 'typeorm';
8+
9+
@Entity()
10+
export class User {
11+
@PrimaryGeneratedColumn()
12+
id: number;
13+
14+
@Column({ type: 'varchar', length: 50, unique: true })
15+
username: string;
16+
17+
@Column({ type: 'varchar', length: 50, unique: true })
18+
email: string;
19+
20+
@CreateDateColumn({ type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
21+
creationDate: string;
22+
23+
@UpdateDateColumn({ type: 'timestamptz', default: () => 'CURRENT_TIMESTAMP' })
24+
upadatenDate: string;
25+
}

src/modules/database/database.module.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Module } from '@nestjs/common';
22
import { Client } from "pg";
33
import { TypeOrmModule } from '@nestjs/typeorm';
4-
import { Project } from './../../entities/project.entity';
4+
import { Project } from '../../entities/project.entity';
55
import { ConfigType } from '@nestjs/config';
66
import config from '../../config';
77
/*const client = new Client(dbConfig);

src/pipe/joi-validation.pipe.spec.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { JoiValidationPipe } from './joi-validation.pipe';
2+
3+
describe('JoiValidationPipe', () => {
4+
it('should be defined', () => {
5+
expect(new JoiValidationPipe()).toBeDefined();
6+
});
7+
});

src/pipe/joi-validation.pipe.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
2+
import { ObjectSchema } from 'joi';
3+
4+
5+
@Injectable()
6+
export class JoiValidationPipe implements PipeTransform {
7+
constructor(private schema: ObjectSchema) { }
8+
9+
transform(value: any, metadata: ArgumentMetadata) {
10+
const { error } = this.schema.validate(value);
11+
if (error) {
12+
console.log(error);
13+
console.log(value);
14+
15+
16+
throw new BadRequestException('Validation failed:' + error.message);
17+
}
18+
return value;
19+
}
20+
}

src/schemas/project.schema.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const Joi = require('joi');
2+
3+
export const projectSchema = Joi.object({
4+
name: Joi.string()
5+
.regex(/^\w+(?:\s+\w+)*$/)
6+
.min(3)
7+
.max(30)
8+
.required(),
9+
10+
description: Joi.string()
11+
.regex(/^\w+(?:\s+\w+)*$/)
12+
.max(300),
13+
14+
location: Joi.string()
15+
.min(1)
16+
.max(100)
17+
.required(),
18+
19+
})

src/schemas/user.schema.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
const Joi = require('joi');
2+
3+
export const createUserSchema = Joi.object({
4+
username: Joi.string()
5+
.alphanum()
6+
.min(3)
7+
.max(30)
8+
.required(),
9+
10+
email: Joi.string()
11+
.email({ minDomainSegments: 2, tlds: { allow: ['com', 'net'] } })
12+
.required()
13+
})

src/services/database/database.service.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { Injectable, Inject, NotFoundException } from '@nestjs/common';
2-
import { Client } from 'pg';
2+
//import { Client } from 'pg';
33
import { InjectRepository } from '@nestjs/typeorm';
44
import { Repository } from 'typeorm';
55

6-
import { Project } from './../../entities/project.entity';
6+
import { Project } from '../../entities/project.entity';
77
@Injectable()
88
export class DatabaseService {
99
constructor(
@@ -20,23 +20,29 @@ export class DatabaseService {
2020
async getProject(id: number): Promise<object> {
2121
const project = await this.projectRepo.findOne(id);
2222
if (!project) {
23-
throw new NotFoundException(`Product #${id} not found`);
23+
throw new NotFoundException(`product with id ${id} not found`);
2424
}
2525
return project;
2626
}
2727
async getProjects(params): Promise<object> {
28-
let data = await this.projectRepo.find()
29-
return data;
28+
const projects = await this.projectRepo.find();
29+
if (!projects) {
30+
throw new NotFoundException(`no products found`);
31+
}
32+
return projects;
3033
}
3134
async updateProject(id: number, payload: object): Promise<object> {
3235
const project = await this.projectRepo.findOne(id);
36+
if (!project) {
37+
throw new NotFoundException(`product with id ${id} not found`);
38+
}
3339
this.projectRepo.merge(project, payload);
3440
return await this.projectRepo.save(project);
3541
}
3642
async deleteProject(id: number): Promise<boolean> {
3743
let deleted = await this.projectRepo.delete(id)
3844
if (deleted.affected != 1) {
39-
return false
45+
throw new NotFoundException(`product with id ${id} not found`);
4046
}
4147
return true
4248
}

0 commit comments

Comments
 (0)