Skip to content

QueryParams doesn't put single param values into an array #389

Closed
@ps2goat

Description

@ps2goat

I'm currently on routingcontrollers v 0.7.6, using Typescript 2.7.2. This issue may be better suited as a class-transformer bug, please advise if so.

Summary

When using QueryParams with a parameter that should be an array, but has only one value, the type of that parameter becomes the single value. E.g., type string[] changes to type string.

Initial Attempt: QueryParam

I originally had a controller that accepted an array of string values similar to QueryParam with array. When you specify more than one value in the query string, it works. When you only specify one, it breaks.

Controller example:

    @Get('/route')
    public async myController(@QueryParam('value') values: string[]): Promise<ReturnModel> {
    }

working url example: myurl/route?value=abc&value=def
not working url example: myurl/route?value=abc

Next Attempt: QueryParams

My next step was to implement the fix I found in issue 320, which involves defining a type and deconstructing all query params.

New Controller example:

    @Get('/route')
    public async myController(@QueryParams() { value }: SampleModel): Promise<ReturnModel> {
    }

SampleModel:

import { Type } from 'class-transformer';

export class SampleModel {
    @Type(( ) => String)
    public value: string[] = [];
}

The Problem with arrays when using QueryParams

This works, but this is also where my issue is. If I pass in a multiple values, it works as expected. If I pass in a single value, value becomes a string instead of a string array. I'm trying to type this, since I'm using Typescript, so I tried changing the property type in my model to:

public value: string[] | string = [];

and it works for the single parameter, but class transformer blows up with two or more of the same parameter name.

StackTrace (full paths redacted):

newValue_1.push is not a function
application.js:630
    at ...\node_modules\class-transformer\TransformOperationExecutor.js:38:37
    at Array.forEach (<anonymous>)
    at TransformOperationExecutor.transform (...\node_modules\class-transformer\TransformOperationExecutor.js:30:20)
    at _loop_1 (...\node_modules\class-transformer\TransformOperationExecutor.js:154:46)
    at TransformOperationExecutor.transform (...\node_modules\class-transformer\TransformOperationExecutor.js:178:18)
    at ClassTransformer.plainToClass (...\node_modules\class-transformer\ClassTransformer.js:17:26)
    at Object.plainToClass (...\src\index.ts:37:29)
    at ActionParameterHandler.transformValue (...\node_modules\routing-controllers\ActionParameterHandler.js:142:42)
    at ActionParameterHandler.normalizeParamValue (...\node_modules\routing-controllers\ActionParameterHandler.js:113:35)
    at ActionParameterHandler.handle (...\node_modules\routing-controllers\ActionParameterHandler.js:36:27)

Preferred Results, in order of preference:

  1. Allow what the OP tried in Issue 320-- this is the way it works in some other model binding systems, such as ASP.NET.
  2. If I'm using my second approach posted here, and I there's only one query parameter for something that should be an array (my SampleModel.value property), place that single value into an array.
  3. Allow for multi-types so I can correctly type my model's properties in my apps.

Workaround

The workaround isn't horrible, but it would be nice to have the underlying frameworks updated so we don't have to repeat the workarounds in numerous clients.

My workaround:

    // if only one value is passed in, the type will be a string. convert to an array for consistency in handling.
        const values: string[] = Array.isArray(value) ? value: [value] || [ ];

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: awaiting answerAwaiting answer from the author of issue or PR.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions