node.js - Există o modalitate de a seta o valoare implicită pentru un atribut JSON lipsă/opțional?
Folosesc NodeJs/NestJs pentru a construi un serviciu RESTful. Am creat niște obiecte pentru a se potrivi cu JSON-ul cererii. În aceste obiecte există câteva atribute opționale, dar aș dori să le setezi valori implicite dacă clientul nu le trimite prin JSON.
Care este cea mai bună modalitate de a atinge obiectivul?
Acesta este DTO-ul meu pentru a se potrivi cu JSON.
import { IsDefined, IsNumber, Min } from 'class-validator';
import { ApiModelProperty, ApiModelPropertyOptional } from '@nestjs/swagger';
export class RequestDto {
@IsDefined()
@IsNumber()
@Min(0)
@ApiModelProperty({description: 'The current age.'})
public CurrentAge: number;
@ApiModelPropertyOptional({description: 'The existing saving amount.'})
public ExistingSavingAmount: number = 0;
}
Acesta este controller-ul meu NestJs
import { Controller, Post, Body, Param } from '@nestjs/common';
import { RequestDto } from './Dto/Request.Dto';
import { ApiResponse, ApiOperation } from '@nestjs/swagger';
@Controller('mycontroller')
export class MyController {
@Post('MyEndPoint')
@ApiOperation({ title: 'Do something' })
@ApiResponse({ status: 201, description: 'Something is done' })
public doSomething(@Body() request: RequestDto) {
// do more jobs
}
}
Lansez serviciul și trimit următorul JSON către punctul meu final
{
"CurrentAge": 40,
}
În controllerul meu văd că ExistingSavingAmount este gol în loc să aibă valoarea 0. Dar dacă instanțiez RequestDto direct, pot vedea că valoarea lui ExistingSavingAmount este 0.
Răspuns #1
Valoarea ta implicită se va aplica doar dacă RequestDto este efectiv instanțiat ca o clasă. Deoarece folosești deja class-validator pentru validare, poți folosi classTransformer.plainToClass() pentru a instanția clasa.
Dacă folosești ValidationPipe încorporat, poți folosi opțiunea { transform: true } pentru a instanția automat clasa ta RequestDto:
@UsePipes(new ValidationPipe({ transform: true }))
@Post('MyEndPoint')
public doSomething(@Body() request: RequestDto) {
sau ca un canal global:
async function bootstrap() {
const app = await NestFactory.create(ApplicationModule);
app.useGlobalPipes(new ValidationPipe({ transform: true }));
await app.listen(3000);
}
bootstrap();
Răspunsul #2
OK, fără exemple de cod de la OP, fidelitatea acestui răspuns poate necesita îmbunătățiri. Asta fiind spuse, modalitatea „cu cuiburi” de a face acest lucru este printr-un TransformPipe.
Exemplul canonic pe care îl dau este pentru ParseIntPipe:
import { Injectable, BadRequestException} from '@nestjs/common';
@Injectable()
export class ParseIntPipe {
transform(value, metadata) {
const val = parseInt(value, 10);
if (isNaN(val)) {
throw new BadRequestException('Validation failed');
}
return val;
}
}
Fără să știu cum arată valorile tale implicite, voi presupune că este ceva de genul unui produs și vrei să setezi unele lucruri implicit și să lași altele ca și șir gol:
import { Injectable, BadRequestException} from '@nestjs/common';
// we will assume you have your own validation for the non-optional bits
const optionalDefaults = {
description: '',
category: 'Miscelleneous'
}
@Injectable()
export class ProductDefaultsPipe {
transform(value, metadata) {
const val = Object.assign(optionalDefaults, value);
return val;
}
}
Acum, asta spus, s-ar putea să folosești ceva care oferă scheme și definiții de modele (ca Joi sau Mongoose). Dacă folosești, atunci aș recomanda să setezi toate valorile implicite și validările în acea schemă și apoi să aplici schema în TransformPipe-ul tău mai degrabă decât să scrii mult cod personalizat. De exemplu, dacă ai un ProductSchema, asta ar funcționa pentru tine:
@Injectable()
export class ProductDefaultsPipe {
async transform(value, metadata) {
const val = new Product(value);
const isValid = await val.validate();
if (!isValid) {
throw new BadRequestException('Validation failed');
}
return val;
}
}
