-
Notifications
You must be signed in to change notification settings - Fork 393
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix missing @QueryParams decorator options #270
Fix missing @QueryParams decorator options #270
Conversation
src/ActionParameterHandler.ts
Outdated
if (param.type === "queries" && typeof value === "object") { | ||
Object.keys(value).map(key => { | ||
const type = Reflect.getMetadata("design:type", param.targetType.prototype, key); | ||
const typeString = typeof type(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TBH, I don't like this part, I did this as a quick shortcut.
It may introduce some weird behavior when the reflected type is not constructor-like (is it possible in TypeScript?) especially when it's undefined
, so I think I should check if the type
is undefined for case like no property type provided in class definition.
|
||
return Boolean(value); | ||
|
||
default: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should also cover the date
case and also the array feature which was requested in #123 - it is possible with class-transform @Type
decorator to work with arrays.
switch (type) { | ||
case "number": | ||
if (value === "") | ||
return undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if a parameter is passed in the query with no value it should be casted to null
instead of undefined
.
I will add a normal comment to detail this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've just extracted pleerock's code to separate method, I haven't changed nothing in normalizing logic.
https://github.com/pleerock/routing-controllers/blob/master/src/ActionParameterHandler.ts#L112
I agree that we should convert ""
to true for boolean, but for number we should use undefined if param value not exist or NaN if it's not a number string. However I would like to don't mix different things in one PR, as we first need to discuss the edge cases we should merge this @QueryParams
PR and start a new one with better normalizing.
I think if a parameter is passed in the query with no value it should be casted to
Also this current approach doesn't allow partial description of the queryparams because of the incorrect behaviour of So now if a query class is defined every key must exists, otherwise the validation will fail right? Example: class GetUsersQuery {
@IsOptional()
@IsPositive()
limit: number;
@IsOptional()
@IsAlpha()
city: string;
@IsOptional()
@IsEnum(Roles)
role: string;
@IsOptional()
@IsBoolean()
isActive: boolean;
}
// this will work for query `?limit=5&city=Amsterdam&role=moderator&isActive=true`
// but wont work for `?limit=5&role=moderator` So to make this work properly we have to pass the following test as well: describe("@QueryParam should give a proper values from request query parameters", () => {
assertRequest([3001, 3002], "get", "photos?sortBy=name&limit=10&showAll", response => {
expect(queryParamSortBy).to.be.equal("name");
expect(queryParamCount).to.be.equal(undefined);
expect(queryParamLimit).to.be.equal(10);
expect(queryParamShowAll).to.be.equal(null);
expect(response).to.be.status(200);
expect(response).to.have.header("content-type", "text/html; charset=utf-8");
});
}); |
Another idea could be to support default params? Example: class GetUsersQuery {
@IsOptional()
@IsPositive()
limit: number = 30
@IsOptional()
@IsAlpha()
sortBy: string;
@IsOptional()
@IsEnum(Roles)
role: string = Roles.User;
@IsOptional()
@IsBoolean()
showAll: boolean = true;
}
describe("@QueryParam should use default values from query descriptor when it's not exist on the requets", () => {
assertRequest([3001, 3002], "get", "photos?sortBy=name&showAll", response => {
expect(queryParamSortBy).to.be.equal("name");
expect(queryParamLimit).to.be.equal(30);
expect(queryParamShowAll).to.be.equal(null);
expect(response).to.be.status(200);
expect(response).to.have.header("content-type", "text/html; charset=utf-8");
});
}); |
It allows just like it allowed before
No, keep consistent with TypeScript, where optional fields are
As you can see this can be easily done in userland, no need for special treatment on framework level. |
Ok, looks like it works - you can define defaults on class level 😉 import { plainToClass } from "class-transformer"
class Framework {
name: string = "type-express"
version: number = 0.72
isProductionReady: boolean
}
const test = plainToClass(Framework, {
isProductionReady: false,
})
console.log(test) // Framework { name: 'type-express', version: 0.72, isProductionReady: false } I've added a test case for optional query params with defaults and it works great! You can merge this PR now @NoNameProvided, I will do another one with enhanced params normalization feature soon - this one only brings back the |
I am still not agree with this. My problem is still that So I would like to see:
When a parameter is there with no value it's means exactly the same as in JS with a variable without value (aka |
Variable without value is undefined, not null. Try: let x;
console.log("x", x);
let y = 5;
delete y;
console.log("y", y);
But your controller want to receive By default, node.js querystring module parse |
How express reacts if we pass |
It is empty string. |
Ah okay it means we cant make decision based on it for numbers, boolean, etc. Im not sure what is correct |
Both |
Im not sure about such feature. Its very seamless feature |
Ok, but as I said - normalizing query object will be part of another PR. This one only bring back the query params options to let control validation and other options. Could you merge it? |
Express doesn't use the querystring package. Or does it? I cannot find it in their package.json.
I dont get it why you guys want empty string.
I want to make an easily usable difference between sent params with no value and not sent params. When I send a param I do it on a purpose, so I want it to have a different value than undefined which represent uninitialized values. I get @19majkel94 reasoning that variables without value are undefined, but we should approach this from the side of reading query params not from the side of js. Lets take an example: I have a What I am interested in is that if it's has meaningful value. With your proposal I would have to do If I am interested in seeing if the param was sent without value I can do
I am ok with this. It's a nice trick, just needs to be outlined in the docs. |
Damn, forgotten about "" 😱 Yet I am not convienced on the string one. But it's 2 vs 1 so I guess we will go that way. |
But what business logic depends if the string param has been set but with no value. Like:
if (city === undefined) { // city param not exist
return usersService.getAll();
} else if (city === null) { // city param exist but has no value
return usersService.getUsersWithCityDefined(); // ???
} For boolean no value means true, not exist means undefined, right? |
Closing in favor of #289. |
This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
This PR add param options for
@QueryParams()
decorator to let enable/disable validation/transforming and other stuffs.Also it introduce normalizing of query params object properties like it's already done for simple
@QueryParam
decorator.Fixes #160.