IsDecimalã¯ãªãæ°å€ãæ€èšŒã§ããªãã®ãïŒ
NestJSã§ã® class-validator ã¯ãããŒã¿ã®ããªããŒã·ã§ã³ãéåžžã«ç°¡åã«ããŠããã匷åãªããŒã«ã§ããDTOïŒData Transfer ObjectïŒã«ããã€ãã®ãã³ã¬ãŒã¿ãŒã远å ããã ãã§ãåä¿¡ãªã¯ãšã¹ãã®åœ¢åŒãç°¡åã«å¶åŸ¡ã§ããŸããããããæã«ã¯äºæ³ãšç°ãªãåäœããããã³ã¬ãŒã¿ãŒã«æ©ãŸãããããšããããŸãããã®äžã€ã @IsDecimal ã§ãã
æããã«å°æ°ç¹ä»ãã®æ°å€ãéã£ãã®ã«ãæå¹ãª10鲿°ã§ã¯ãããŸããããšãããšã©ãŒãåºãçµéšã¯ãããŸãããïŒãã®èšäºã§ã¯ããªã @IsDecimal ããã®ãããªåé¡ãåŒãèµ·ããã®ãããããŠNestJSã§å°æ°ç¹ã®ããæ°å€ãæ£ããæ€èšŒããæ¹æ³ãæç¢ºã«èª¬æããŸãã
@IsDecimal ã®èª€è§£ãšçå®
å€ãã®éçºè
㯠@IsDecimal ãæ°å€åã®å°æ°ãæ€èšŒããããã«äœ¿çšããããšããŸããããããStack Overflow ã§ãè°è«ãããŠããããã«ã@IsDecimal 㯠æååïŒstringïŒåã®å€ã10鲿°åœ¢åŒã«åã£ãŠãããã©ãã ã確èªãããã³ã¬ãŒã¿ãŒã§ãã
å®éãclass-validator ã® GitHub ã€ã·ã¥ãŒ (#1423) ã«ãã@IsDecimal ã®èª¬æã³ã¡ã³ãã誀ã£ãŠããŠæ··ä¹±ãæããéå»ã®èšé²ããããŸããçŸåšã¯ä¿®æ£ãããŠããŸãããããã§ãå€ãã®éçºè
ããã®ç¹ã§æ··ä¹±ããŠããŸãã
次ã®ãããªã³ãŒããã芧ãã ããã
// create-product.dto.ts
import { IsDecimal, IsNotEmpty, Min } from 'class-validator';
export class CreateProductDto {
@IsDecimal({ decimal_digits: '2' }) // ðš ããã§åé¡ãçºçããŸãïŒ
@IsNotEmpty()
@Min(0)
price: number; // å㯠'number' ã§ãã
}
ãã®DTOã«JSON圢åŒã§ { "price": 1574.23 } ã®ãããªãªã¯ãšã¹ããéããšãclass-validator 㯠price ãã£ãŒã«ããæ°å€åã§ããããã@IsDecimal ã®æ€èšŒã«éãããšã©ãŒãè¿ããŸãã
ã§ã¯ãæ°å€åã®å°æ°ã¯ã©ããã£ãŠæ€èšŒããã°è¯ãã®ã§ããããïŒ2ã€ã®è§£æ±ºçããããŸãã
解決ç1: @IsNumber ã䜿çšãã
æãã·ã³ãã«ã§çŽæçãªè§£æ±ºçã¯ã@IsNumber ãã³ã¬ãŒã¿ãŒã䜿çšããããšã§ãã@IsNumber ã¯æ°å€åã®å€ãæ€èšŒããmaxDecimalPlaces ãªãã·ã§ã³ã䜿ã£ãŠèš±å®¹ãããå°æ°ç¹ä»¥äžã®æ¡æ°ãæå®ã§ããŸãã
// create-product.dto.tsïŒä¿®æ£åŸïŒ
import { IsNumber, IsNotEmpty, Min } from 'class-validator';
export class CreateProductDto {
@IsNumber({ maxDecimalPlaces: 2 }) // â
ãã®ããã«ä¿®æ£ããŠãã ããïŒ
@IsNotEmpty()
@Min(0)
price: number;
}
ãã®ããã«ä¿®æ£ããã°ãprice ãã£ãŒã«ããæ°å€ã§ãããå°æ°ç¹ä»¥äž2æ¡ãŸã§ãèš±å¯ããããã«æ£ç¢ºã«æ€èšŒã§ããŸãã
ãã³ãïŒããŒã¿ããŒã¹ã®ç²ŸåºŠãä¿èšŒããããã«ãTypeORMãªã©ã®ORMã䜿ã£ãŠããå Žåã¯ããšã³ãã£ãã£ïŒEntityïŒãã¡ã€ã«ã§ @Column('decimal') ãã³ã¬ãŒã¿ãŒãäžç·ã«å®çŸ©ããŠãããšè¯ãã§ãããã
解決ç2: ã«ã¹ã¿ã ãã³ã¬ãŒã¿ãŒãäœæãã
ããè€éãªããªããŒã·ã§ã³ã«ãŒã«ãå¿
èŠãªå Žåã¯ãã«ã¹ã¿ã ãã³ã¬ãŒã¿ãŒãèªäœããæ¹æ³ããããŸããexonerate ã®ãããªã©ã€ãã©ãªã䜿ãã°ãè€æ°ã®ã«ãŒã«ãçµã¿åãããŠåŒ·åãªã«ã¹ã¿ã ãã³ã¬ãŒã¿ãŒãç°¡åã«äœæã§ããŸãã
ãŸãã©ã€ãã©ãªãã€ã³ã¹ããŒã«ããŠãã ããã
npm install exonerate
次ã«ãDTOã§ @Exonerate ãã³ã¬ãŒã¿ãŒã䜿çšããŠã以äžã®ããã«æ§ã
ãªã«ãŒã«ãé©çšã§ããŸãã
// create-user.dto.tsïŒexonerate䜿çšäŸïŒ
import { Exonerate } from 'exonerate';
import { User } from './user.entity'; // Userãšã³ãã£ãã£ãååšãããšä»®å®
import { AddressDto } from './address.dto'; // Address DTOãååšãããšä»®å®
enum ROLE {
ADMIN = 'ADMIN',
USER = 'USER',
}
export class CreateUserDto {
@Exonerate({ rules: 'required|string|max:20|min:4|exist:name', entity: User })
name: string;
@Exonerate({ rules: 'required|email|unique:email', entity: User })
email: string;
@Exonerate({
rules: 'required|max:20|min:8|pattern',
regexPattern: /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/
})
password: string;
@Exonerate({ rules: 'required|enum', enumType: ROLE })
role: string;
}
exonerate ã¯å°æ°ç¹ã®æ€èšŒã ãã§ãªããã¡ãŒã«ã¢ãã¬ã¹ã®éè€ç¢ºèªïŒunique:emailïŒãç¹å®ãã¿ãŒã³ã®æ€èšŒïŒpatternïŒãªã©ãè€åçãªã«ãŒã«ãç°¡æœã«è¡šçŸã§ããããã«ããŠãããŸãããããžã§ã¯ãå
šäœã§äžè²«æ§ã®ããåå©çšå¯èœãªããªããŒã·ã§ã³ããžãã¯ãå¿
èŠãªå Žåã«éåžžã«äŸ¿å©ã§ãã
ã°ããŒãã«ãã€ãã®èšå®
class-validator ãã¢ããªã±ãŒã·ã§ã³å
šäœã§åäœãããã«ã¯ãmain.ts ãã¡ã€ã«ã« ValidationPipe ã远å ããå¿
èŠããããŸãããã®èšå®ãå¿ããªãããã«ããŸãããïŒ
// main.ts
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(3000);
}
bootstrap();
ãŸããç°å¢å€æ°ãªã©ã䜿ãå Žå㯠app.module.ts ã« ConfigModule ã®èšå®ã远å ããã®ãäžè¬çã§ãã
// app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
envFilePath: '.env',
}),
// ... ä»ã®ã¢ãžã¥ãŒã«
],
controllers: [],
providers: [],
})
export class AppModule {}
æ£ããããŒã«ãæ£ããå Žæã§
ä»åã®å
容ãããéèŠãªæèšãåŸãŸããã@IsDecimal ã¯æååçšã®ããŒã«ã§ãããæ°å€åã®å°æ°ç¹ãæ€èšŒããã«ã¯ @IsNumber ã䜿ãã¹ãã ãšããããšã§ãã
ã³ãŒããæžãéã«ã¯ããã³ã¬ãŒã¿ãŒã颿°ã®èª¬æãäžå¯§ã«ç¢ºèªããç¿æ £ãæã€ããšã§ãäºæãã¬ãã°ãé²ã匷åãªé²åŸ¡ææ®µã«ãªããŸããããå ¬åŒããã¥ã¡ã³ãã®èª¬æãäžååã ã£ãããæ··ä¹±ãæãããã§ããã°ãé æ ®ããã«GitHubã®ã€ã·ã¥ãŒãã³ãã¥ããã£ã§è³ªåãããã£ããçè§£ããŠé²ããã®ãè¯ãã§ãããïŒ