From 2b4e80b3141fa82a28a0ffb210343ea4c8a93b1a Mon Sep 17 00:00:00 2001 From: Hendra Lin Date: Fri, 14 Apr 2023 11:46:55 +0700 Subject: [PATCH] Part 2: Building a REST API with NestJS and Prisma: Input Validation & Transformation --- package.json | 2 ++ src/articles/articles.controller.ts | 14 +++++++------- src/articles/dto/create-article.dto.ts | 12 ++++++++++++ src/main.ts | 3 +++ yarn.lock | 29 +++++++++++++++++++++++++++++ 5 files changed, 53 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 346960e..918fe2e 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,8 @@ "@nestjs/platform-express": "^9.0.0", "@nestjs/swagger": "^6.3.0", "@prisma/client": "^4.12.0", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.0", "reflect-metadata": "^0.1.13", "rxjs": "^7.2.0", "swagger-ui-express": "^4.6.2" diff --git a/src/articles/articles.controller.ts b/src/articles/articles.controller.ts index 8c35405..1085cf9 100644 --- a/src/articles/articles.controller.ts +++ b/src/articles/articles.controller.ts @@ -1,4 +1,4 @@ -import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common'; +import { Controller, Get, Post, Body, Patch, Param, Delete, ParseIntPipe } from '@nestjs/common'; import { ArticlesService } from './articles.service'; import { CreateArticleDto } from './dto/create-article.dto'; import { UpdateArticleDto } from './dto/update-article.dto'; @@ -30,19 +30,19 @@ export class ArticlesController { @Get(':id') @ApiOkResponse({ type: ArticleEntity }) - findOne(@Param('id') id: string) { - return this.articlesService.findOne(+id); + findOne(@Param('id', ParseIntPipe) id: number) { + return this.articlesService.findOne(id); } @Patch(':id') @ApiOkResponse({ type: ArticleEntity }) - update(@Param('id') id: string, @Body() updateArticleDto: UpdateArticleDto) { - return this.articlesService.update(+id, updateArticleDto); + update(@Param('id', ParseIntPipe) id: number, @Body() updateArticleDto: UpdateArticleDto) { + return this.articlesService.update(id, updateArticleDto); } @Delete(':id') @ApiOkResponse({ type: ArticleEntity }) - remove(@Param('id') id: string) { - return this.articlesService.remove(+id); + remove(@Param('id', ParseIntPipe) id: number) { + return this.articlesService.remove(id); } } diff --git a/src/articles/dto/create-article.dto.ts b/src/articles/dto/create-article.dto.ts index a27259e..6291045 100644 --- a/src/articles/dto/create-article.dto.ts +++ b/src/articles/dto/create-article.dto.ts @@ -1,15 +1,27 @@ import { ApiProperty } from '@nestjs/swagger' +import { IsBoolean, IsNotEmpty, IsOptional, IsString, MaxLength, MinLength } from 'class-validator' export class CreateArticleDto { + @IsString() + @IsNotEmpty() + @MinLength(5) @ApiProperty() title: string + @IsString() + @IsOptional() + @IsNotEmpty() + @MaxLength(300) @ApiProperty({ required: false }) description?: string + @IsString() + @IsNotEmpty() @ApiProperty() body: string + @IsBoolean() + @IsOptional() @ApiProperty({ required: false, default: false }) published?: boolean = false } diff --git a/src/main.ts b/src/main.ts index a085ef3..0cfc89d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,10 +1,13 @@ import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; +import { ValidationPipe } from '@nestjs/common' async function bootstrap() { const app = await NestFactory.create(AppModule); + app.useGlobalPipes(new ValidationPipe({ whitelist: true })) + const config = new DocumentBuilder() .setTitle('Median') .setDescription('The Median API description') diff --git a/yarn.lock b/yarn.lock index dd2ea3c..eacbdb1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1046,6 +1046,11 @@ dependencies: "@types/superagent" "*" +"@types/validator@^13.7.10": + version "13.7.15" + resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.7.15.tgz#408c99d1b5f0eecc78109c11f896f72d1f026a10" + integrity sha512-yeinDVQunb03AEP8luErFcyf/7Lf7AzKCD0NXfgVoGCCQDNpZET8Jgq74oBgqKld3hafLbfzt/3inUdQvaFeXQ== + "@types/yargs-parser@*": version "21.0.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" @@ -1695,6 +1700,20 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== +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.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.14.0.tgz#40ed0ecf3c83b2a8a6a320f4edb607be0f0df159" + integrity sha512-ct3ltplN8I9fOwUd8GrP8UQixwff129BkEtuWDKL5W45cQuLd19xqmTLu5ge78YDm/fdje6FMt0hGOhl0lii3A== + dependencies: + "@types/validator" "^13.7.10" + libphonenumber-js "^1.10.14" + validator "^13.7.0" + cli-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" @@ -3311,6 +3330,11 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +libphonenumber-js@^1.10.14: + version "1.10.26" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.26.tgz#3e6604357b3434b0005f85778b44153f4fadeecd" + integrity sha512-oB3l4J5gEhMV+ymmlIjWedsbCpsNRqbEZ/E/MpN2QVyinKNra6DcuXywxSk/72M3DZDoH/6kzurOq1erznBMwQ== + 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" @@ -4626,6 +4650,11 @@ v8-to-istanbul@^9.0.1: "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^1.6.0" +validator@^13.7.0: + version "13.9.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.9.0.tgz#33e7b85b604f3bbce9bb1a05d5c3e22e1c2ff855" + integrity sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA== + vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"