lukeautry / tsoa

Build OpenAPI-compliant REST APIs using TypeScript and Node
MIT License
3.45k stars 494 forks source link

Parameter examples are incorrectly made into single-ement arrays #1464

Closed pablo-redradix closed 11 months ago

pablo-redradix commented 1 year ago

Sorting

Expected Behavior

Examples for scalar parameters should remain scalar:

schema:
  properties:
    stringParam:
      type: string
      example: Lorem ipsum dolor sit amet
    numberParam:
      type: number
      format: double
      example: 4815162342
  required:
  - stringParam
  - numberParam
  type: object

Current Behavior

Instead, they are made into single-element arrays:

schema:
  properties:
    stringParam:
      type: string
      example:
      - Lorem ipsum dolor sit amet
    numberParam:
      type: number
      format: double
      example:
      - 4815162342
  required:
  - stringParam
  - numberParam
  type: object

Steps to Reproduce

  /**
   * @example stringParam "Lorem ipsum dolor sit amet"
   * @example numberParam 4815162342
   */
  @Post('test')
  public async testMethod(
    @BodyProp() stringParam: string,
    @BodyProp() numberParam: number
  ) {
    return
  }

Context (Environment)

Version of the library: Tried with versions 5 and 6-rc Version of NodeJS: 18.16.1

github-actions[bot] commented 1 year ago

Hello there pablo-redradix 👋

Thank you for opening your very first issue in this project.

We will try to get back to you as soon as we can.👀

pablo-redradix commented 1 year ago

I think I found the culprit: in parameterGenerator.ts you can find this:

const { examples: example, exampleLabels } = this.getParameterExample(parameter, parameterName);

It merely renames destructured examples to example, but it's still an array. This does the trick:

const { examples, exampleLabels } = this.getParameterExample(parameter, parameterName);
const example = examples?.length ? examples[0] : undefined

This line can be found five times in said file, once per property type allowing for a single example

WoH commented 1 year ago

Shouldn't they have labels, even if they're just called example-{n}? I'd prefer if we used examples for oas 3

pablo-redradix commented 1 year ago

Swagger spec doesn't allow for labels in param examples:

parameters:
  - in: query
    name: status
    schema:
      type: string
      enum: [approved, pending, closed, new]
      example: approved     #Example of a parameter value

Link to Swagger docs

It would be great if tsoa had an option to add request examples (maybe through a parameter in @Example decorator, or even a new @RequestExample decorator), but that belongs in a feature request. This thread is about fixing a bug.

WoH commented 1 year ago

I was thinking:

parameters:
  - in: query
    name: status
    schema:
      type: string
      enum: [approved, pending, closed, new]
      examples:       # Multiple examples
        example-0:         # Distinct name
          value: approved    # Example value
WoH commented 1 year ago

That would be more consistent with previous work such as https://github.com/lukeautry/tsoa/pull/1168 and https://github.com/lukeautry/tsoa/pull/1275

pablo-redradix commented 1 year ago

How do you propose multiple parameter examples be handled?

/**
 * @example stringParam "First example for stringParam"
 * @example stringParam "Second example for stringParam"
 * @example numberParam 4815162342
 */
@Post('test')
public async testMethod(
  @BodyProp() stringParam: string,
  @BodyProp() numberParam: number,
  @BodyProp() thirdParam: boolean
) {
  return
}

That's a valid annotation that doesn't map well to your proposed solution: parameters can each have 0..N examples. Swagger allows for two distinct forms of input examples:

As of today, tsoa has zero support for the latter, and erroneous support for the former. It is my understanding that both should be addressed: the first one via bug fix (such as this ticket's), the second one via a new feature that allows for full-input use of the @Example decorator:

Maybe the @Example decorator could take a third optional object parameter like this:

@Example<MyInputInterface>({
  stringParam: "First example for stringParam",
  numberParam: 1,
  thirdParam: true
}, 'Example 1', { isInputExample: true })
@Example<MyInputInterface>({
  stringParam: "Second example for stringParam",
  numberParam: 2,
  thirdParam: false
}, 'Example 2', { isInputExample: true })
@Post('test')
public async testMethod(
  @BodyProp() stringParam: string,
  @BodyProp() numberParam: number,
  @BodyProp() thirdParam: boolean
) {
  return
}

Please note that this solution does not address the buggy implementation of per-parameter jsdoc annotation of examples. That's why I think this belongs in a separate feature request ticket.

github-actions[bot] commented 11 months ago

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days