tsoa
tsoa copied to clipboard
Dynamic Query/Header Param
I have a request which should look like this
users/query?someKey=someValue&someKey2=someValue2
These are dynamic query params that I handle in the server. Is there any way to create this using tsoa?
I tried something like this -
export interface QueryFilters {
[x: string]: string;
}
...
public async get(
@Query() filters?: QueryFilters
): Promise<User[]> {
return getUsers(filters);
}
but I'm getting error -
Error: @Query('filters') Can't support 'refObject' type.
I'm currently working on an implementation of refObject
for @Query
(and possibly @Header
too) by "flattening" the properties as individual parameters and reassembling them at the server.
I have a very basic but (mostly) working implementation ready, which is good enough for my own project for now. When I have the time I'll add the missing parts and create a PR.
@HoldYourWaffle we’d love if you could submit your PR for this. @dmitrirussu had a similar and interesting request here: https://github.com/lukeautry/tsoa/issues/324#issue-391707399
I also work with another team that would find this really valuable as they use OData filters. So suffice to say, you’d be quite the hero if you were to submit this! :)
Sorry for the late response, haven't touched this in a while due to summer break.
I don't remember much and I'm not able to really look into the code right now, but from what I remember my implementation was very basic and specific to my use-case. I'll see what I can do to fix it up and maybe make it more usable for other use-cases.
I believe that https://github.com/lukeautry/tsoa/issues/219#issuecomment-526403819 is a duplicate of this. I’ll close that one to keep this open.
@Templum @anro87 when we introduce array like query params then this is the issue number to track. I’m cc’ing you so you’re not left out. We apologize that your original feature request was not added in a timely manner.
@WoH can you point me to where the changes in the code would need to be to get this working? Its currently blocking for me. Would be happy to work on it (maybe tonight/this weekend)
This should not be a blocker, albeit you'd have to write the OpenAPI for yourself. Assuming Express, but you can inject the Request
(and look at req.headers) and add the Spec to your tsoa.json.
I'm not sure how the API should look like for this, the one suggested is a non-starter.
@Query() filters
would be a query param called filters, as in ?filters=
.
I could imagine resolving an interface here, but the approach would have to ensure a) you can still pull off individual query params, b) these would not be documented twice, c) the OpenAPI Spec is sound.
the one suggested is a non-starter.
It's very Javascript-esque to just get a params object. Would it not be possible to "break down" the interface/class given as a type? E.g. @Query queryObject: IQueryParams
can be converted into @Query qObjectProp1: prop1Type, @Query qObjectProp2: prop2Type, ...
A possible conflict with this solution is when we have something along the lines of @Query params, @Query('paramName') myParam: paramType
, breaking down the params object will yield a duplicate myParam
. But I guess that's something easy to handle.
The idea (getting the spec from an interface) is fine, we just need a way to indicate that it's a query param collection, not, for example, an object serialized from one query param.
I could see something like @Query('/') params: { one: string, two: number }
, since it's impossible to use /
as the name of a single query param.
You are correct. I was a bit confused there because we're using nest.js
decorators for our controllers and tsoa
"automagically" works with those. A @QueryParams()
decorator seems the logical way forward, but your idea of using a wildcard such as /
is better (and also keeps things working with nest
😄 ).
The idea (getting the spec from an interface) is fine, we just need a way to indicate that it's a query param collection, not, for example, an object serialized from one query param. I could see something like
@Query('/') params: { one: string, two: number }
, since it's impossible to use/
as the name of a single query param.
If anyone wants to implement this, I'd be glad to review a PR adding this.
any update on this?
@WoH, just to clarify about where this issue is. You are hoping for a PR that implements this:
@Query('/') params: { one: string, two: number }
Is that correct?
Yes. The validation layer can already do that for bodies, so there should be a decent amount of reuse possible. Similarly, the ParamGenerator already can tell you if a type makes sense for a single query Param, ideally we'd check in these cases as well if you're interested in this feature.
Any update on this, this would make tsoa compatible with FeathersJS which currently bundles all params into a single params
object, so would be nice if this worked.
Typical use case of multiple params are: {filter: string, limit: number, skip: number, orderBy: string, orderDirection: 'DESC' | 'ASC'}
Has anyone got it working yet for any project? We are looking at implementing OData and this would be super helpful.
I'm wondering if the proposed solution would solve for a similar use case I have: I started looking at this approach, but in addition to it not being complete, I wanted a richer query language and implemented one similar to MongoDB QL or GraphQL. The entire filter is a single string passed in as a single query-string parameter: ?filter={eq{field:value}}
. I would like to document which fields are valid in the filter, and then validate it on the server.
Obviously, I could add static documentation to the jsdoc for this parameter indicating which fields are valid, and then in the controller write code to validate, but that seems to go against the intent of tsoa. I would have no issue creating an interface with the fields defined in it, ideally with aliases: interface foo { field = fieldAlias }
. Would this PR allow for that, or is it only for the case where each field is a separate query-string parameter? If not the same, is my use case something the team would consider?