tsoa icon indicating copy to clipboard operation
tsoa copied to clipboard

Dynamic Query/Header Param

Open oreporan opened this issue 5 years ago • 17 comments

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.

oreporan avatar May 14 '19 19:05 oreporan

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 avatar Jun 15 '19 19:06 HoldYourWaffle

@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! :)

dgreene1 avatar Aug 17 '19 05:08 dgreene1

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.

HoldYourWaffle avatar Aug 22 '19 16:08 HoldYourWaffle

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.

dgreene1 avatar Aug 30 '19 00:08 dgreene1

@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.

dgreene1 avatar Aug 30 '19 00:08 dgreene1

@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)

givethemheller avatar Mar 27 '20 23:03 givethemheller

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.

WoH avatar Mar 30 '20 14:03 WoH

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.

moshewe avatar Apr 07 '20 07:04 moshewe

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.

WoH avatar Apr 07 '20 08:04 WoH

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 😄 ).

moshewe avatar Apr 16 '20 20:04 moshewe

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.

WoH avatar Apr 16 '20 20:04 WoH

any update on this?

mp205 avatar Oct 31 '21 01:10 mp205

@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?

KenEucker avatar Dec 03 '21 03:12 KenEucker

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.

WoH avatar Dec 03 '21 10:12 WoH

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.

u12206050 avatar Jan 27 '22 09:01 u12206050

Typical use case of multiple params are: {filter: string, limit: number, skip: number, orderBy: string, orderDirection: 'DESC' | 'ASC'}

u12206050 avatar Jan 27 '22 09:01 u12206050

Has anyone got it working yet for any project? We are looking at implementing OData and this would be super helpful.

luke-lewandowski avatar Mar 22 '22 05:03 luke-lewandowski

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?

dpomerantz-jci avatar Oct 07 '22 15:10 dpomerantz-jci