From 8d62280efb90a6dda9b27f2129ab852bf748ebde Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Thu, 5 Jun 2025 06:08:29 +0300 Subject: [PATCH] add validators --- package.json | 2 ++ src/main.ts | 2 ++ src/task/docorators/start-with.decorator.ts | 24 +++++++++++++ src/task/dto/create-task.dto.ts | 40 +++++++++++++++++++-- src/task/dto/update-task.dto.ts | 7 ++++ src/task/task.service.ts | 5 ++- yarn.lock | 29 +++++++++++++++ 7 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 src/task/docorators/start-with.decorator.ts diff --git a/package.json b/package.json index a3dd237..67e6500 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,8 @@ "@nestjs/core": "^11.0.1", "@nestjs/mapped-types": "*", "@nestjs/platform-express": "^11.0.1", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.2", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1" }, diff --git a/src/main.ts b/src/main.ts index f76bc8d..9be6371 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,8 +1,10 @@ import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; +import { ValidationPipe } from '@nestjs/common'; async function bootstrap() { const app = await NestFactory.create(AppModule); + app.useGlobalPipes(new ValidationPipe()); await app.listen(process.env.PORT ?? 3000); } bootstrap(); diff --git a/src/task/docorators/start-with.decorator.ts b/src/task/docorators/start-with.decorator.ts new file mode 100644 index 0000000..7876aba --- /dev/null +++ b/src/task/docorators/start-with.decorator.ts @@ -0,0 +1,24 @@ +import { registerDecorator, ValidatorOptions } from 'class-validator'; + +export function StartsWiths( + prefix: string, + validatorOption?: ValidatorOptions, +) { + return (obj: object, propertyName: string) => { + registerDecorator({ + name: 'startsWith', + target: obj.constructor, + propertyName, + options: validatorOption, + validator: { + validate(value: any): Promise | boolean { + console.log('value', value); + return typeof value === 'string' && value.startsWith(prefix); + }, + defaultMessage(): string { + return `Should start with "${prefix}"`; + }, + }, + }); + }; +} diff --git a/src/task/dto/create-task.dto.ts b/src/task/dto/create-task.dto.ts index 7db2652..ade5638 100644 --- a/src/task/dto/create-task.dto.ts +++ b/src/task/dto/create-task.dto.ts @@ -1,3 +1,39 @@ -export class CreateTaskDto { - title: string; +import { + IsArray, + IsEnum, + IsInt, + IsNotEmpty, + IsOptional, + IsPositive, + IsString, + Length, +} from 'class-validator'; +import { StartsWiths } from '../docorators/start-with.decorator'; + +export enum TaskTag { + WORK = 'work', + STUDY = 'study', + HOME = 'home', +} + +export class CreateTaskDto { + @IsString() + @IsNotEmpty() + @StartsWiths('task') + @Length(2, 10) + title: string; + + @IsString() + @IsOptional() + description: string; + + @IsInt({}) + @IsOptional() + @IsPositive() + priority: number; + + @IsArray() + @IsEnum(TaskTag, { each: true }) + @IsOptional() + tags: TaskTag[]; } diff --git a/src/task/dto/update-task.dto.ts b/src/task/dto/update-task.dto.ts index 3acda63..f7af821 100644 --- a/src/task/dto/update-task.dto.ts +++ b/src/task/dto/update-task.dto.ts @@ -1,4 +1,11 @@ +import { IsBoolean, IsNotEmpty, IsString, Length } from 'class-validator'; + export class UpdateTaskDto { + @IsString({ message: 'Должно быть строкой' }) + @IsNotEmpty({ message: 'Не должно быть пустым' }) + @Length(2, 40, { message: 'Должно быть от 2 до 40 символов' }) title: string; + + @IsBoolean({ message: 'Должно быть булевым выражением' }) isCompleted: boolean; } diff --git a/src/task/task.service.ts b/src/task/task.service.ts index fb95a41..dbee2e0 100644 --- a/src/task/task.service.ts +++ b/src/task/task.service.ts @@ -32,11 +32,14 @@ export class TaskService { } create(dto: CreateTaskDto) { - const { title } = dto; + const { title, description, priority, tags } = dto; const newTask = { id: this.tasks.length + 1, title, isCompleted: false, + description, + priority, + tags, }; this.tasks.push(newTask); diff --git a/yarn.lock b/yarn.lock index dd112d6..3b2dc3e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1462,6 +1462,11 @@ "@types/methods" "^1.1.4" "@types/superagent" "^8.1.0" +"@types/validator@^13.11.8": + version "13.15.1" + resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.15.1.tgz#52f3617eb5ba30dd0018380c64568440d0b4de0a" + integrity sha512-9gG6ogYcoI2mCMLdcO0NYI0AYrbxIjv0MDmy/5Ywo6CpWWrqYayc+mmgxRsCgtcGJm9BSbXkMsmxGah1iGHAAQ== + "@types/yargs-parser@*": version "21.0.3" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" @@ -2264,6 +2269,20 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz#0f79731eb8cfe1ec72acd4066efac9d61991b00d" integrity sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q== +class-transformer@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336" + integrity sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw== + +class-validator@^0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.14.2.tgz#a3de95edd26b703e89c151a2023d3c115030340d" + integrity sha512-3kMVRF2io8N8pY1IFIXlho9r8IPUUIfHe2hYVtiebvAzU2XeQFXTv+XI4WX+TnXmtwXMDcjngcpkiPM0O9PvLw== + dependencies: + "@types/validator" "^13.11.8" + libphonenumber-js "^1.11.1" + validator "^13.9.0" + cli-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" @@ -4051,6 +4070,11 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +libphonenumber-js@^1.11.1: + version "1.12.8" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.12.8.tgz#20e5b57f24e60359d795e2fa2ee185776331e34f" + integrity sha512-f1KakiQJa9tdc7w1phC2ST+DyxWimy9c3g3yeF+84QtEanJr2K77wAmBPP22riU05xldniHsvXuflnLZ4oysqA== + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" @@ -5527,6 +5551,11 @@ v8-to-istanbul@^9.0.1: "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^2.0.0" +validator@^13.9.0: + version "13.15.15" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.15.15.tgz#246594be5671dc09daa35caec5689fcd18c6e7e4" + integrity sha512-BgWVbCI72aIQy937xbawcs+hrVaN/CZ2UwutgaJ36hGqRrLNM+f5LUT/YPRbo8IV/ASeFzXszezV+y2+rq3l8A== + vary@^1, vary@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"