Skip to content

Commit 7df956c

Browse files
js2melaktakChristian ZangltiagoskanetaTiago Kaneta
authored
Release 9.2.0 (#278)
* added --unwrap-response-data to unwrap the data item from the response (#268) * added --unwrap-response-data to unwrap the data item from the response * add axios --unwrap-response-data Co-authored-by: Christian Zangl <[email protected]> * fix: formdata in axios template (#277) Co-authored-by: Tiago Kaneta <[email protected]> * Feature: add full response typing for status code, data and headers. (#272) This commit adds additional type information to the route's response object that allows types to be created that express the combination of status code, data and headers for each response. This type information can be used to "narrow" a response type based on an HTTP status code. This narrowing is useful since it can prevent type mismatches where a status code is presumed to have one type but in actuality it returns another. Additionally, response headers are now associated with data types and status codes rather than being free form. A caveat right now is that only there are no response codes like 3XX or 5XX, every code must be explicitly listed. * bump: up version to 9.2.0 Co-authored-by: Christian Zangl <[email protected]> Co-authored-by: Christian Zangl <[email protected]> Co-authored-by: Tiago Surjus Kaneta <[email protected]> Co-authored-by: Tiago Kaneta <[email protected]> Co-authored-by: Rusty Conover <[email protected]>
1 parent 189dec0 commit 7df956c

File tree

12 files changed

+69
-8
lines changed

12 files changed

+69
-8
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# next release
22

3+
# 9.2.0
4+
5+
Features:
6+
- full response typing for status code, data and headers. (#272, thanks @rustyconover)
7+
- --unwrap-response-data to unwrap the data item from the response (#268, thanks @laktak)
8+
9+
Fixes:
10+
- fix: formdata in axios template (#277, thanks @tiagoskaneta)
11+
312
# 9.1.2
413

514
Fixes:

index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ program
6666
.option("--disableStrictSSL", "disabled strict SSL", false)
6767
.option("--disableProxy", "disabled proxy", false)
6868
.option("--axios", "generate axios http client", false)
69+
.option("--unwrap-response-data", "unwrap the data item from the response", false)
6970
.option("--single-http-client", "Ability to send HttpClient instance to Api constructor", false)
7071
.option("--silent", "Output only errors to console", false)
7172
.option("--default-response <type>", "default type for empty response schema", TS_KEYWORDS.VOID)
@@ -100,6 +101,7 @@ const {
100101
disableProxy,
101102
cleanOutput,
102103
defaultResponse,
104+
unwrapResponseData,
103105
singleHttpClient,
104106
axios,
105107
silent,
@@ -115,6 +117,7 @@ generateApi({
115117
httpClientType: axios ? HTTP_CLIENT.AXIOS : HTTP_CLIENT.FETCH,
116118
defaultResponseAsSuccess: defaultAsSuccess,
117119
defaultResponseType: defaultResponse,
120+
unwrapResponseData: unwrapResponseData,
118121
generateUnionEnums: unionEnums,
119122
generateResponses: responses,
120123
extractRequestParams: !!extractRequestParams,

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "swagger-typescript-api",
3-
"version": "9.1.2",
3+
"version": "9.2.0",
44
"description": "Generate typescript/javascript api from swagger schema",
55
"scripts": {
66
"cli:json": "node index.js -r -d -p ./swagger-test-cli.json -n swagger-test-cli.ts",

src/config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ const config = {
5858
defaultResponseType: TS_KEYWORDS.VOID,
5959
singleHttpClient: false,
6060
httpClientType: HTTP_CLIENT.FETCH,
61+
unwrapResponseData: false,
6162
templatePaths: {
6263
/** `templates/base` */
6364
base: "",

src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ module.exports = {
4444
extractRequestParams = config.extractRequestParams,
4545
extractRequestBody = config.extractRequestBody,
4646
defaultResponseType = config.defaultResponseType,
47+
unwrapResponseData = config.unwrapResponseData,
4748
singleHttpClient = config.singleHttpClient,
4849
prettier: prettierOptions = constants.PRETTIER_OPTIONS,
4950
hooks: rawHooks,
@@ -77,6 +78,7 @@ module.exports = {
7778
disableProxy,
7879
cleanOutput,
7980
defaultResponseType,
81+
unwrapResponseData,
8082
singleHttpClient,
8183
constants,
8284
silent,

src/routes.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const _ = require("lodash");
22
const {
33
types,
44
parseSchema,
5+
getType,
56
getRefType,
67
getInlineParseContent,
78
checkAndAddNull,
@@ -475,6 +476,21 @@ const getResponseBodyInfo = (routeInfo, routeParams, parsedSchemas) => {
475476
(response) => !response.isSuccess && response.type !== TS_KEYWORDS.ANY,
476477
);
477478

479+
const handleResponseHeaders = (src) => {
480+
if (!src) {
481+
return "headers: {},";
482+
}
483+
const headerTypes = Object.fromEntries(
484+
Object.entries(src).map(([k, v]) => {
485+
return [k, getType(v)];
486+
}),
487+
);
488+
const r = `headers: { ${Object.entries(headerTypes)
489+
.map(([k, v]) => `"${k}": ${v}`)
490+
.join(",")} },`;
491+
return r;
492+
};
493+
478494
return {
479495
contentTypes,
480496
responses: responseInfos,
@@ -486,6 +502,19 @@ const getResponseBodyInfo = (routeInfo, routeParams, parsedSchemas) => {
486502
schemas: errorResponses,
487503
type: _.uniq(errorResponses.map((response) => response.type)).join(" | ") || TS_KEYWORDS.ANY,
488504
},
505+
full: {
506+
types:
507+
responseInfos
508+
.map(
509+
(response) => `{
510+
data: ${response.type}, status: ${response.status}, statusCode: ${
511+
response.status
512+
}, statusText: "${response.description}", ${handleResponseHeaders(
513+
response.headers,
514+
)} config: {} }`,
515+
)
516+
.join(" | ") || TS_KEYWORDS.ANY,
517+
},
489518
};
490519
};
491520

@@ -685,6 +714,7 @@ const parseRoutes = ({
685714
contentTypes: responseBodyInfo.contentTypes,
686715
type: responseBodyInfo.success.type,
687716
errorType: responseBodyInfo.error.type,
717+
fullTypes: responseBodyInfo.full.types,
688718
},
689719
raw: rawRouteInfo,
690720
};

templates/base/http-clients/axios-http-client.eta

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<%
2-
const { apiConfig, generateResponses } = it;
2+
const { apiConfig, generateResponses, config } = it;
33
%>
44

55
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, ResponseType } from "axios";
@@ -89,7 +89,11 @@ export class HttpClient<SecurityDataType = unknown> {
8989
format,
9090
body,
9191
...params
92+
<% if (config.unwrapResponseData) { %>
93+
}: FullRequestParams): Promise<T> => {
94+
<% } else { %>
9295
}: FullRequestParams): Promise<AxiosResponse<T>> => {
96+
<% } %>
9397
const secureParams = ((typeof secure === 'boolean' ? secure : this.secure) && this.securityWorker && (await this.securityWorker(this.securityData))) || {};
9498
const requestParams = this.mergeRequestParams(params, secureParams);
9599
const responseFormat = (format && this.format) || void 0;
@@ -99,7 +103,7 @@ export class HttpClient<SecurityDataType = unknown> {
99103
requestParams.headers.post = {};
100104
requestParams.headers.put = {};
101105

102-
const formData = this.createFormData(body as Record<string, unknown>);
106+
body = this.createFormData(body as Record<string, unknown>);
103107
}
104108

105109
return this.instance.request({
@@ -112,6 +116,10 @@ export class HttpClient<SecurityDataType = unknown> {
112116
responseType: responseFormat,
113117
data: body,
114118
url: path,
119+
<% if (config.unwrapResponseData) { %>
120+
}).then(response => response.data);
121+
<% } else { %>
115122
});
123+
<% } %>
116124
};
117125
}

templates/base/http-clients/fetch-http-client.eta

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<%
2-
const { apiConfig, generateResponses } = it;
2+
const { apiConfig, generateResponses, config } = it;
33
%>
44

55
export type QueryParamsType = Record<string | number, any>;
@@ -164,7 +164,11 @@ export class HttpClient<SecurityDataType = unknown> {
164164
baseUrl,
165165
cancelToken,
166166
...params
167+
<% if (config.unwrapResponseData) { %>
168+
}: FullRequestParams): Promise<T> => {
169+
<% } else { %>
167170
}: FullRequestParams): Promise<HttpResponse<T, E>> => {
171+
<% } %>
168172
const secureParams = ((typeof secure === 'boolean' ? secure : this.baseApiParams.secure) && this.securityWorker && await this.securityWorker(this.securityData)) || {};
169173
const requestParams = this.mergeRequestParams(params, secureParams);
170174
const queryString = query && this.toQueryString(query);
@@ -206,7 +210,11 @@ export class HttpClient<SecurityDataType = unknown> {
206210
}
207211

208212
if (!response.ok) throw data;
213+
<% if (config.unwrapResponseData) { %>
214+
return data.data;
215+
<% } else { %>
209216
return data;
217+
<% } %>
210218
});
211219
};
212220
}

tests/spec/axios/schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1547,7 +1547,7 @@ export class HttpClient<SecurityDataType = unknown> {
15471547
requestParams.headers.post = {};
15481548
requestParams.headers.put = {};
15491549

1550-
const formData = this.createFormData(body as Record<string, unknown>);
1550+
body = this.createFormData(body as Record<string, unknown>);
15511551
}
15521552

15531553
return this.instance.request({

tests/spec/axiosSingleHttpClient/schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1547,7 +1547,7 @@ export class HttpClient<SecurityDataType = unknown> {
15471547
requestParams.headers.post = {};
15481548
requestParams.headers.put = {};
15491549

1550-
const formData = this.createFormData(body as Record<string, unknown>);
1550+
body = this.createFormData(body as Record<string, unknown>);
15511551
}
15521552

15531553
return this.instance.request({

tests/spec/jsAxios/schema.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export class HttpClient {
3434
requestParams.headers.common = { Accept: "*/*" };
3535
requestParams.headers.post = {};
3636
requestParams.headers.put = {};
37-
const formData = this.createFormData(body);
37+
body = this.createFormData(body);
3838
}
3939
return this.instance.request({
4040
...requestParams,

0 commit comments

Comments
 (0)