Skip to content

Commit 25e89f0

Browse files
committed
Add multiple response implementation
1 parent eff3333 commit 25e89f0

File tree

6 files changed

+134
-75
lines changed

6 files changed

+134
-75
lines changed

src/openApi/v3/parser/getContent.ts

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,38 +9,16 @@ export interface Content {
99
schema: OpenApiSchema;
1010
}
1111

12-
const BASIC_MEDIA_TYPES = [
13-
'application/json-patch+json',
14-
'application/json',
15-
'application/x-www-form-urlencoded',
16-
'text/json',
17-
'text/plain',
18-
'multipart/form-data',
19-
'multipart/mixed',
20-
'multipart/related',
21-
'multipart/batch',
22-
];
12+
export const getContent = (openApi: OpenApi, content: Dictionary<OpenApiMediaType>): Content[] | null => {
13+
const contents: Content[] = [];
14+
Object.keys(content)
15+
.filter(mediaType => isDefined(content[mediaType]?.schema))
16+
.forEach(mediaType => {
17+
contents.push({
18+
mediaType: mediaType,
19+
schema: content[mediaType].schema as OpenApiSchema,
20+
});
21+
});
2322

24-
export const getContent = (openApi: OpenApi, content: Dictionary<OpenApiMediaType>): Content | null => {
25-
const basicMediaTypeWithSchema = Object.keys(content)
26-
.filter(mediaType => {
27-
const cleanMediaType = mediaType.split(';')[0].trim();
28-
return BASIC_MEDIA_TYPES.includes(cleanMediaType);
29-
})
30-
.find(mediaType => isDefined(content[mediaType]?.schema));
31-
if (basicMediaTypeWithSchema) {
32-
return {
33-
mediaType: basicMediaTypeWithSchema,
34-
schema: content[basicMediaTypeWithSchema].schema as OpenApiSchema,
35-
};
36-
}
37-
38-
const firstMediaTypeWithSchema = Object.keys(content).find(mediaType => isDefined(content[mediaType]?.schema));
39-
if (firstMediaTypeWithSchema) {
40-
return {
41-
mediaType: firstMediaTypeWithSchema,
42-
schema: content[firstMediaTypeWithSchema].schema as OpenApiSchema,
43-
};
44-
}
45-
return null;
23+
return contents.length ? contents : null;
4624
};

src/openApi/v3/parser/getOperationRequestBody.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ export const getOperationRequestBody = (openApi: OpenApi, body: OpenApiRequestBo
3030
};
3131

3232
if (body.content) {
33-
const content = getContent(openApi, body.content);
34-
if (content) {
33+
const contents = getContent(openApi, body.content);
34+
if (contents && contents.length > 0) {
35+
// TODO: here try later to use multiple requests
36+
const content = contents.shift()!;
3537
requestBody.mediaType = content.mediaType;
3638
switch (requestBody.mediaType) {
3739
case 'application/x-www-form-urlencoded':

src/openApi/v3/parser/getOperationResponse.ts

Lines changed: 52 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -12,42 +12,27 @@ export const getOperationResponse = (
1212
openApi: OpenApi,
1313
response: OpenApiResponse,
1414
responseCode: number
15-
): OperationResponse => {
16-
const operationResponse: OperationResponse = {
17-
in: 'response',
18-
name: '',
19-
code: responseCode,
20-
description: response.description || null,
21-
export: 'generic',
22-
type: 'any',
23-
base: 'any',
24-
template: null,
25-
link: null,
26-
isDefinition: false,
27-
isReadOnly: false,
28-
isRequired: false,
29-
isNullable: false,
30-
imports: [],
31-
enum: [],
32-
enums: [],
33-
properties: [],
34-
};
15+
): OperationResponse[] => {
16+
const responses: OperationResponse[] = [];
3517

3618
if (response.content) {
37-
const content = getContent(openApi, response.content);
38-
if (content) {
39-
if (content.schema.$ref?.startsWith('#/components/responses/')) {
40-
content.schema = getRef<OpenApiSchema>(openApi, content.schema);
41-
}
42-
if (content.schema.$ref) {
43-
const model = getType(content.schema.$ref);
44-
operationResponse.export = 'reference';
45-
operationResponse.type = model.type;
46-
operationResponse.base = model.base;
47-
operationResponse.template = model.template;
48-
operationResponse.imports.push(...model.imports);
49-
return operationResponse;
50-
} else {
19+
const contents = getContent(openApi, response.content);
20+
if (contents && contents.length > 0) {
21+
contents.forEach(content => {
22+
const operationResponse = getBaseResponse(response, responseCode);
23+
if (content.schema.$ref?.startsWith('#/components/responses/')) {
24+
content.schema = getRef<OpenApiSchema>(openApi, content.schema);
25+
}
26+
if (content.schema.$ref) {
27+
const model = getType(content.schema.$ref);
28+
operationResponse.export = 'reference';
29+
operationResponse.type = model.type;
30+
operationResponse.base = model.base;
31+
operationResponse.template = model.template;
32+
operationResponse.imports.push(...model.imports);
33+
responses.push(operationResponse);
34+
return;
35+
}
5136
const model = getModel(openApi, content.schema);
5237
operationResponse.export = model.export;
5338
operationResponse.type = model.type;
@@ -75,8 +60,11 @@ export const getOperationResponse = (
7560
operationResponse.enum.push(...model.enum);
7661
operationResponse.enums.push(...model.enums);
7762
operationResponse.properties.push(...model.properties);
78-
return operationResponse;
79-
}
63+
responses.push(operationResponse);
64+
});
65+
}
66+
if (responses.length) {
67+
return responses;
8068
}
8169
}
8270

@@ -85,14 +73,40 @@ export const getOperationResponse = (
8573
if (response.headers) {
8674
for (const name in response.headers) {
8775
if (response.headers.hasOwnProperty(name)) {
76+
const operationResponse = getBaseResponse(response, responseCode);
8877
operationResponse.in = 'header';
8978
operationResponse.name = name;
9079
operationResponse.type = 'string';
9180
operationResponse.base = 'string';
92-
return operationResponse;
81+
responses.push(operationResponse);
9382
}
9483
}
84+
if (responses.length) {
85+
return responses; // TODO: is it possible to return headers and results
86+
}
9587
}
9688

97-
return operationResponse;
89+
return [getBaseResponse(response, responseCode)];
90+
};
91+
92+
const getBaseResponse = (response: OpenApiResponse, responseCode: number): OperationResponse => {
93+
return {
94+
in: 'response',
95+
name: '',
96+
code: responseCode,
97+
description: response.description || null,
98+
export: 'generic',
99+
type: 'any',
100+
base: 'any',
101+
template: null,
102+
link: null,
103+
isDefinition: false,
104+
isReadOnly: false,
105+
isRequired: false,
106+
isNullable: false,
107+
imports: [],
108+
enum: [],
109+
enums: [],
110+
properties: [],
111+
};
98112
};

src/openApi/v3/parser/getOperationResponses.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ export const getOperationResponses = (openApi: OpenApi, responses: OpenApiRespon
1818
const responseCode = getOperationResponseCode(code);
1919

2020
if (responseCode) {
21-
const operationResponse = getOperationResponse(openApi, response, responseCode);
22-
operationResponses.push(operationResponse);
21+
const ors = getOperationResponse(openApi, response, responseCode);
22+
operationResponses.push(...ors);
2323
}
2424
}
2525
}

test/__snapshots__/index.spec.ts.snap

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3751,6 +3751,7 @@ export { MultipartService } from './services/MultipartService';
37513751
export { MultipleTags1Service } from './services/MultipleTags1Service';
37523752
export { MultipleTags2Service } from './services/MultipleTags2Service';
37533753
export { MultipleTags3Service } from './services/MultipleTags3Service';
3754+
export { MultiResponsesService } from './services/MultiResponsesService';
37543755
export { NoContentService } from './services/NoContentService';
37553756
export { ParametersService } from './services/ParametersService';
37563757
export { RequestBodyService } from './services/RequestBodyService';
@@ -6614,6 +6615,38 @@ export class HeaderService {
66146615
"
66156616
`;
66166617

6618+
exports[`v3 should generate: ./test/generated/v3/services/MultiResponsesService.ts 1`] = `
6619+
"/* istanbul ignore file */
6620+
/* tslint:disable */
6621+
/* eslint-disable */
6622+
import type { ModelWithString } from '../models/ModelWithString';
6623+
6624+
import type { CancelablePromise } from '../core/CancelablePromise';
6625+
import { OpenAPI } from '../core/OpenAPI';
6626+
import { request as __request } from '../core/request';
6627+
6628+
export class MultiResponsesService {
6629+
6630+
/**
6631+
* @returns binary Successful response
6632+
* @returns ModelWithString Successful response
6633+
* @throws ApiError
6634+
*/
6635+
public static callWithMultiResponsesResult(): CancelablePromise<Blob | ModelWithString> {
6636+
return __request(OpenAPI, {
6637+
method: 'POST',
6638+
url: '/api/v{api-version}/multiResponses',
6639+
errors: {
6640+
400: \`400 server error\`,
6641+
500: \`500 server error\`,
6642+
},
6643+
});
6644+
}
6645+
6646+
}
6647+
"
6648+
`;
6649+
66176650
exports[`v3 should generate: ./test/generated/v3/services/MultipartService.ts 1`] = `
66186651
"/* istanbul ignore file */
66196652
/* tslint:disable */

test/spec/v3.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,6 +1429,38 @@
14291429
}
14301430
}
14311431
},
1432+
"/api/v{api-version}/multiResponses": {
1433+
"post": {
1434+
"tags": [
1435+
"MultiResponses"
1436+
],
1437+
"operationId": "CallWithMultiResponsesResult",
1438+
"responses": {
1439+
"200": {
1440+
"description": "Successful response",
1441+
"content": {
1442+
"application/octet-stream": {
1443+
"schema": {
1444+
"type": "string",
1445+
"format": "binary"
1446+
}
1447+
},
1448+
"application/json": {
1449+
"schema": {
1450+
"$ref": "#/components/schemas/ModelWithString"
1451+
}
1452+
}
1453+
}
1454+
},
1455+
"400": {
1456+
"description": "400 server error"
1457+
},
1458+
"500": {
1459+
"description": "500 server error"
1460+
}
1461+
}
1462+
}
1463+
},
14321464
"/api/v{api-version}/error": {
14331465
"post": {
14341466
"tags": [

0 commit comments

Comments
 (0)