swagger-codegen
swagger-codegen copied to clipboard
fix typescript-node object deserialization for complex array types
PR checklist
- [X] Read the contribution guidelines.
- [X] Ran the shell script under
./bin/to update Petstore sample so that CIs can verify the change. (For instance, only need to run./bin/{LANG}-petstore.shand./bin/security/{LANG}-petstore.shif updating the {LANG} (e.g. php, ruby, python, etc) code generator or {LANG} client's mustache templates). Windows batch files can be found in.\bin\windows\. - [X] Filed the PR against the correct branch:
3.0.0branch for changes related to OpenAPI spec 3.0. Default:master. - [X] Copied the technical committee to review the pull request if your PR is targeting a particular programming language.
Description of the PR
This PR fixes the deserialization problem in typescript-node with complex array types. Fixes [typescript-node] Runtime error when using array definitions;
Sample specs to validate the fix:
swagger: "2.0"
info:
title: Sample spec
version: '1.0.0'
basePath: /v1
schemes:
- http
- https
consumes:
- application/json
produces:
- application/json
paths:
/environments/:
get:
responses:
200:
$ref: '#/responses/EnvironmentList'
responses:
EnvironmentList:
description: "List of Environment Details"
schema:
$ref: '#/definitions/EnvironmentDetailsList'
definitions:
EnvironmentDetailsList:
description: "List of Environment Details"
type: object
properties:
environments:
type: array
items:
$ref: '#/definitions/Environment'
links:
$ref: '#/definitions/Links'
Environment:
type: object
properties:
name:
type: string
Link:
type: object
properties:
href:
type: string
method:
type: string
rel:
type: string
Links:
type: array
items:
$ref: '#/definitions/Link'
Deserialization test code:
import { ObjectSerializer, EnvironmentDetailsList } from './api';
const data = {
"environments": [
{
"name": "test-environment",
}
],
"links": [
{
"href": "http://127.0.0.1:8080/v1/environments/?page=1&page_size=100&userid=owner",
"method": "GET",
"rel": "self"
}
]
};
const output = ObjectSerializer.deserialize(data, "EnvironmentDetailsList");
console.log(output)
Before fix:
The generator produces Links model class and it is referenced in EnvironmentDetailsList. While proposed solution in the #10000 to add attributeTypeMap and getAttributeTypeMap to the array model classes would fix the error TypeError: typeMap[type].getAttributeTypeMap is not a function, it does not fix the deserialization. The reason is that the empty attributeTypeMap will skip deserializing that array object links as shown in the sample code above.
export class EnvironmentDetailsList {
'environments'?: Array<Environment>;
'links'?: Links;
static discriminator: string | undefined = undefined;
static attributeTypeMap: Array<{name: string, baseName: string, type: string}> = [
{
"name": "environments",
"baseName": "environments",
"type": "Array<Environment>"
},
{
"name": "links",
"baseName": "links",
"type": "Links"
} ];
static getAttributeTypeMap() {
return EnvironmentDetailsList.attributeTypeMap;
}
}
export class Links extends Array<Link> {
static discriminator: string | undefined = undefined;
}
After fix:
It does not produce the intermediate model Links, instead any references of Links will be replaced with Array<Link>. The change will fix the runtime error and also the deserialization of those complex array types. This type mapping is very similar to how the environments is referenced as Array<Environment>
export class EnvironmentDetailsList {
'environments'?: Array<Environment>;
'links'?: Array<Link>;
static discriminator: string | undefined = undefined;
static attributeTypeMap: Array<{name: string, baseName: string, type: string}> = [
{
"name": "environments",
"baseName": "environments",
"type": "Array<Environment>"
},
{
"name": "links",
"baseName": "links",
"type": "Array<Link>"
} ];
static getAttributeTypeMap() {
return EnvironmentDetailsList.attributeTypeMap;
}
}
Tested the fix with the sample spec provided in the issue #10000 as well.
Before fix:
It produces a model LocationGetResponse. It is also referenced in the operation response.
export class LocationGetResponse extends Array<LocationGetResponse> {
}
public locationGet (input: string, options: any = {}) : Promise<{ response: http.ClientResponse; body: LocationGetResponse; }> {
....
body = ObjectSerializer.deserialize(body, "LocationGetResponse");
}
After fix:
It does not produce the model LocationGetResponse. But it will replace any references of LocationGetResponse with Array<LocationGetResponseInner>.
public locationGet (input: string, options: any = {}) : Promise<{ response: http.ClientResponse; body: Array<LocationGetResponseInner>; }> {
...
body = ObjectSerializer.deserialize(body, "Array<LocationGetResponseInner>");
}
Test code:
import { ObjectSerializer, LocationGetResponseInner } from './api';
const data = [
{
"id": "1",
"text": "text 1"
},
{
"id": "2",
"text": "text 2"
}
];
const output = ObjectSerializer.deserialize(data, "Array<LocationGetResponseInner>");
console.log(output)
@CodeNinjai
@HugoMario Could you please PR?
bump @HugoMario @poojyum