#Validation on parent DTO instead

86 messages · Page 1 of 1 (latest)

meager condor
#
class Datetime {
  @ApiProperty({
    type: Date,
    default: new Date(),
  })
  @IsDate()
  datetime: Date;
}
export class MainDto {
  @ApiProperty({ type: Datetime })
  @ValidateNested()
  @Type(() => Date)
  datetime: Datetime
}

Why is it that when I put @IsDate() in MainDto it works, but when I put @IsDate() in Datetime it doesn't work? I want to do my validation on "child dto", I thought @ValidationNested() would run the validation on the child, and report error if any of the validation fails

humble tundra
#

What's the request body look like?

meager condor
#

also I don't understand why setting

@Type(() => Datetime)

would produce this error: nested property datetime must be either object or array

meager condor
humble tundra
#

Why are you trying to set up a nested object when you aren't sending an object

meager condor
humble tundra
#

Yes

#

I don't know why you were trying to make a nested object there to begin with

meager condor
#
export class MainDto {
  @Type(() => Boolean)
  @IsBoolean()
  arriveBy: boolean
}

what about boolean? I want to validate true/false but any value would become true

#

can I check for boolean in Query? Or is it not possible because they are plain text

humble tundra
#

@Transform(({ val }) => JSON.parse(val))

meager condor
humble tundra
meager condor
#

if I input anything other than true/false, it throws error in Nest, and it couldn't trigger the @IsBoolean check

humble tundra
#

Correct

meager condor
#

is there any way to "catch" it and pass it to the @IsBoolean check?

#

basically throw @IsBoolean and respond with arriveBy must be a Boolean

humble tundra
#

You could returnval === 'true' instead of JSON.parse(val)

#

Boolean doesn't work because it returns the truthy value of whatever you pass to it. And, confusingly enough, !!'false' evaluates to true

meager condor
#

hmm I see, guess using boolean check here is kinda a bad idea

humble tundra
#

There is @IsBooleanString()

meager condor
#

putting it before @Transform with JSON.parse still gives error

humble tundra
#

Transform happens before validation. Always

meager condor
#

hmm okay, then I think val === 'true' is my best bet

#

I have another Coordinate which uses nested object as I will be reusing the Coordinate

class Coordinate {
  @IsNumber()
  @Type(() => Number)
  @Min(-90)
  @Max(90)
  lat: number;

  @IsNumber()
  @Type(() => Number)
  @Min(-180)
  @Max(180)
  lon: number;
}

class From {
  @ValidateNested()
  @Type(() => Coordinate)
  from_lat: Coordinate["lat"];

  @ValidateNested()
  @Type(() => Coordinate)
  from_lon: Coordinate["lon"];
}

// class To with same layout...

export class MainDto {
  @ValidateNested()
  @Type(() => From)
  from: From;
}

This does not trigger any validation as I can put anything in from_lat or from_lon. How should I solve this?

humble tundra
#

How do you send these values?

meager condor
#

?from_lat=test&from_lon=test

humble tundra
#

Then it won't be a nested object, right?

#

You'd need something like ?from[lat]=test&from[lon]=test

#

And even then, needed query parameters are not necessarily standard, so support is not guaranteed

meager condor
humble tundra
#

Look into querystring or qs to see how things are parsed initially

humble tundra
meager condor
#

what I am trying to do is that:

  • lat is always be -90 to 90
  • lon is always be -180 to 180
    and this is always the initial validation for Coordinate, hence I want to put it in there

and then some other dto that uses Coordinate will have further restriction/check, where maybe lat would be be 0 to 30

#

this way, if I put the initial check in Coordinate I can use it with the extra restriction or without I believe

#

but right now it is not doing any validation, can you only do validation on "parent" and not "child"?

#

I think extending Coordinate only allows me to add extra parameters, and cannot achieve what I want. Please correct me if I am wrong

humble tundra
humble tundra
humble tundra
humble tundra
#

Validation will happen on what fields your decorate

meager condor
#
class Coordinate {
  @IsNumber()
  @Min(-90)
  @Max(90)
  lat: number;

  @IsNumber()
  @Min(-180)
  @Max(180)
  lon: number;
}
class From extends PickType(Coordinate, ["lat", "lon"] as const) {
  from_lat: Coordinate["lat"];
  from_lon: Coordinate["lon"];
}
class To extends PickType(Coordinate, ["lat", "lon"] as const) {
  to_lat: Coordinate["lat"];
  to_lon: Coordinate["lon"];
}
class MainDto {
  from: From;
  to: To;
}

This would produce the image below in Swagger, how can I change it so there are only from_lat, from_lon, to_lat, to_lon in the request? And it is not doing the Min Max check in Coordinate too. I'm definitely doing something wrong but I don't quite understand

#

for example, in class From, I want to input the lat and lon with key from_lat and from_lon, but still keep the validation check in Coordinate

#

Validation on parent DTO instead

humble tundra
#

Okay, seriously, why not just set these fields directly? This seems like a lot of work for no payout to be completely honest

meager condor
# humble tundra Okay, seriously, why not just set these fields directly? This seems like a lot o...

Coordinate will be reused very often in the future, so I try to make it into a dto for basic validation.
And then there would be more validation based on what kind of data I am trying to get as they require a specific range of Coordinate. That is my idea on why I should create the Coordinate dto.

In this case right now, I have two set of Coordinate which I would like to transfer, hence I made From and To to “prefix” the lat and lon

If I do this:

class MainDto {
from: Coordinate;
to: Coordinate;
}

It would result in duplicated key and I cannot set two Coordinate

(Sorry I cant use codeblock on phone for some reason)

#

Or is there a decorator to change the key name of lat/lon so I can just do “from: Coordinate; to: Coordinate” in MainDto instead?

humble tundra
#

Okay, let's take a step back: what do you want the eventually swagger and query to look like? Let's start with the goal and work from there

meager condor
humble tundra
meager condor
#

like you see here

#

I have from_lat and from_lon

#

can I make it so it says:

from: {
    lat: ____
    lon: ____
}
#

or is it not possible in Swagger with @Query?

humble tundra
#

Is that how you want the query parameters to look? from[lat]=test&from[lon]=test&to[lat]=test&to[lon]=test?

meager condor
humble tundra
#

Then no, you do not want to have a nested class

#

You want those four properties to be on the main class, but you do not want nested classes

#

Guaranteed

meager condor
#

but what if I want to reuse Coordinate?

#

what kind if query allows me to reuse?

humble tundra
#

But this isn't a Coordinate, right? You could transform it into one, but that;s not what your query parameters are showing it to be

#

These are four query parameter fields, right? Not nested objects

meager condor
#

hmm I see. When should I be using nested objects?

humble tundra
meager condor
#

is it uncommon to use it on @Query since they are mostly plain text?

humble tundra
#

It's a non-standard thing to do. I believe querystring supports it, which is what express uses for parsing the query string, but I forget how coded into theURL Standard it is

#

Can you do it? Sure. Should you? That's up to you to decide in the end

meager condor
humble tundra
#

Yes, you could do that with a pipe or inside the controller

#

I don't think it would be too difficult though to just make a CoordinateQueryParam class that looks something like

export class CoordinateQueryParam {
  from_lat: number;
  from_lon:  number;
  to_lat: number;
  to_lon: number;
}

And any subsequent parameters that needs to be added can be by using the mapped-types from @nestjs/swagger like

export class QueryDto extends CoordinateQueryParams {
  arriveBy: Date;
  datetime: Date;
}
meager condor
humble tundra
meager condor
humble tundra
#

Using a pipe to transform it actually might get a little difficult as it would mess with the type metadata. Might be doable, but it might just be easier to do that in your controller

meager condor
#

I see

meager condor
#

oh wait, I do the basic validation on CoordinateQueryParam, and it would transform into Coordinate which would be always correct as it’s already validated on CoordinateQueryParam

humble tundra
meager condor
#

and then whenever I want more validation, I do PickType

humble tundra
#

Give it a shot and see. I might not be following your train of thought, but you might be on to something. It's been a bit of a long day

meager condor