swagger
swagger copied to clipboard
ApiProperty for unknown keys (dictionaries)
Is there an existing issue that is already proposing this?
- [X] I have searched the existing issues
Is your feature request related to a problem? Please describe it
If my schema is contain dictionaries (properties with unknown key) I dont know how create schema descriptions for it like here https://swagger.io/docs/specification/data-models/dictionaries/
Example:
class ColorDto {
@ApiProperty()
hex: string;
@ApiProperty()
rgb: string;
}
class RainbowDto {
@ApiProperty()
name: string;
@???????
colors: { [key: string] : ColorDto }
}
Describe the solution you'd like
class ColorDto {
@ApiProperty()
hex: string;
@ApiProperty()
rgb: string;
}
class RainbowDto {
@ApiProperty()
name: string;
@ApiAdditionalProperty({
type: ColorDto
})
colors: { [key: string] : ColorDto }
}
Teachability, documentation, adoption, migration strategy
No response
What is the motivation / use case for changing the behavior?
This is super often problem, and I dont know how to solve this trouble for now...
+1 Any update on this matter?
Any update ?
Workaround
@Controller('api/v1/some-resource')
export class SomeResourceController {
@ApiOkResponse({
description: 'Some description.',
schema: {
type: 'object',
example: {
'key1': {
name: 'string',
date: 'string',
},
'key2': {
name: 'string',
date: 'string',
},
},
additionalProperties: {
$ref: '#/components/schemas/NameOfSomeDto',
},
},
})
public async readSomeResource() {}
}
Also works via @ApiProperty({additionalProperties: {$ref: "#/components/schemas/NameOfSomeDto"}});
Any updates on this? Unfortunately, it seems decorators cannot be attached to index signatures. :(
import { v4 } from 'uuid'
class SomeNestedDTO {
@ApiProperty({ example: 'abc' })
a: string
@ApiProperty({ example: 322 })
b: number
}
@ApiExtraModels(SomeNestedDTO)
class MainDTO {
@ApiProperty({
type: 'object',
properties: { [v4()]: { $ref: '#/components/schemas/SomeNestedDTO' } }
})
someNestedDTOMap: Record<string, SomeNestedDTO>
}
The result should look like:
{
"someNestedDTOMap": {
"d9472a82-8c2c-4f8b-a1cc-8d22f8929bd3": {
"a": "abc",
"b": 322
}
}
}
Use Record<string, T>
. If you're pre-4.0 you're probably SOL.
export class MyDto {
@ApiProperty({ additionalProperties: { type: 'string' } });
bag_of_fun: Record<string, string>;
}
+1
It makes these properties optional and generating mock data against openapi specification is then incorrect.
What about this solution?
import { ApiExtraModels, ApiProperty, getSchemaPath } from '@nestjs/swagger';
class ColorDto {
@ApiProperty()
hex: string;
@ApiProperty()
rgb: string;
}
@ApiExtraModels(ColorDto)
class RainbowDto {
@ApiProperty()
name: string;
@ApiProperty({
type: 'object',
additionalProperties: { $ref: getSchemaPath(ColorDto) },
})
colors: Record<string, ColorDto>;
}
The result should look like:
{
"name": "string",
"colors": {
"additionalProp1": {
"hex": "string",
"rgb": "string"
},
"additionalProp2": {
"hex": "string",
"rgb": "string"
},
"additionalProp3": {
"hex": "string",
"rgb": "string"
}
}
}
While @Kibyra answer works for nested properties, we still can't declare class level indexed properties as swagger definition like this:
import { ApiProperty } from '@nestjs/swagger';
class ColorDto {
// Can't apply decorator here
[key: string]: unknown;
@ApiProperty()
hex: string;
@ApiProperty()
rgb: string;
}
Can a class decorator could be considered allowing to add additional properties to the class ?
ApiPropertyOptional could only help you make one layer, which means it could only solve Record<string, Dto>, but it can't solve Record<string, Record<string, Dto>>
While @Kibyra answer works for nested properties, we still can't declare class level indexed properties as swagger definition like this:
class ColorDto { // Can't apply decorator here [key: string]: unknown; }
I'm having the same issue.
That's a typical use case: Have an object as parameter with a unique id as key and that maps to some content.
I haven't found a proper solution for this.
Example:
WalletAddress?: string
Memo?: string
DestinationTag?: string
}
export class CryptoAddresses {
// cannot add @ApiProperty(…) → decorators are not valid here
[id: string]: CryptoAddress
}
I can then create a controller:
...
public addresses: CryptoAddresses = {}
@ApiExtraModels(CryptoAddress)
@Get('addresses') @ApiResponse({status: 200, schema: {type: 'object', additionalProperties: {$ref: getSchemaPath(CryptoAddress)}}}) getAddresses(): CryptoAddresses {
return this.addresses
}
But I can't get a schema for CryptoAddresses
to be created…
For me, it's important to get a proper schema definition, because the client generates it's types from the schema file.
Any idea / solution for this?
A possible solution would be to add something to create an arbitrary schema for an arbitrary type to solve all unhandled use cases, such as:
@ApiSchema({
type: object,
additionalProperties: $ref: getSchemaPath(CryptoAddress)
})
class CryptoAddresses {...}