routing-controllers-openapi icon indicating copy to clipboard operation
routing-controllers-openapi copied to clipboard

Map with string array as values

Open tomashq opened this issue 3 years ago • 5 comments

hi, I would like to generate OpenAPI specs for a payload which would contain a map with string[] as values.

Example:

{
    'combinations': {
        'combination1': ['elem1', 'elem2'],
        'combination2': ['elem2', 'elem3'],
    },
}

I can't seem to find a right way to annotate class properties in order to generate correct specs that would reflect above JSON shape.

I tried few approaches but nothing seemed to work:

string[] as values

export class Body {
    @ValidateNested({each: true})
    public combinations: Map<string, string[]>;
}

another one using class extending string[]

export class StringArray extends Array<string>{}

export class Body {
    @ValidateNested({each: true})
    @Type(() => StringArray)
    public combinations: Map<string, StringArray>;
}

Does 'routing-controllers-openapi' support such case?

Thanks! Tom

tomashq avatar May 01 '21 12:05 tomashq

@tomashq, Did you find a solution for this?

fhasni avatar Nov 09 '21 16:11 fhasni

It's likely possible to define your custom schema with the @JSONSchema annotation. However I'm not sure how to do it exactly. Does anyone know more details here? See also: https://github.com/epiphone/class-validator-jsonschema#validatenested-and-arrays

Simple examples for arrays and maps I got to work:

@ValidateNested({ each: true })
@Type(() => YourObjectType)
items: YourObjectType[]

For simple object/maps the same works:

@ValidateNested({ each: true })
@Type(() => YourObjectType)
items?: Map<string, YourObjectType>;

What's missing right now is to annotate a class with Type Information. e.g. First example of @tomashq: The StringArray class does not add any information, because at runtime there's still no type information for that class and we can't annotate a class with the required @ValidateNested, @Type(() => string).

I'll open another ticket since this looks like a more generic issue.

judos avatar Jan 03 '22 15:01 judos

Workaround in general is to define the JSONSchema manually. I provided an example in #98. Also for simple strings I had troubles defining the type correct so I did this:

@IsArray({ each: true })
@JSONSchema({
  type: 'array',
  items: {
    type: 'string'
  }
})
data: string[];

For your case @tomashq you can use this:

export class Body {
  @IsObject()
  @JSONSchema({
    type: 'object',
    properties: {
      '{key}': {
        type: 'array',
        items: {
          type: 'string'
        }
      }
    }
  })
  public combinations: Map<string, string[]>;
}

That shows the following JSONSchema in swagger for me:

"combinations": {
  "{key}": [
    "string"
  ]
}

Now this ticket can be closed.

judos avatar Jan 03 '22 16:01 judos

would this way work for @IsArray() too? I am trying to bulk insert with array, but my items in array is null in swagger

@IsArray() @ValidateNested({ each: true }) @Type(() => CreatePostDto) public posts: CreatePostDto[]

image

ekankr2 avatar Apr 26 '22 02:04 ekankr2

I actually found a better way for Object in arrays. You can use JSONSchema for better Swagger examples. put your DTOs in "CreatePostDTO"

@IsArray()
    @JSONSchema({  
        type: 'array',  
        items: {  
            $ref: '#/components/schemas/CreatePostDTO'  
        }
    })
    @Type(() => CreatePostDTO)
    public posts: CreatePostDTO[]

my example would look like this

image

my CreatePostDTO looks like this

export class UpdatePostDto {
  @IsNotEmpty()
  public title: string;

  @IsNotEmpty()
  public content: string;
}

ekankr2 avatar Apr 26 '22 03:04 ekankr2