swagger-typescript-api 9.1.0 → 9.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # next release
2
2
 
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
+
12
+ # 9.1.2
13
+
14
+ Fixes:
15
+ - Bug with --single-http-client and private `http` property
16
+
17
+ # 9.1.1
18
+
19
+ Fixes:
20
+ - Bug with nested objects in FormData (issue #262, thanks @avlnche64)
21
+
3
22
  # 9.1.0
4
23
 
5
24
  Fixes:
package/LICENSE CHANGED
@@ -1,22 +1,22 @@
1
- MIT License
2
-
3
- Copyright (c) 2019-present acacode
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- 'Software'), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1
+ MIT License
2
+
3
+ Copyright (c) 2019-present acacode
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
22
  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -63,6 +63,7 @@ Options:
63
63
  --default-response <type> default type for empty response schema (default: "void")
64
64
  --type-prefix <string> data contract name prefix (default: "")
65
65
  --type-suffix <string> data contract name suffix (default: "")
66
+ --patch fix up small errors in the swagger source definition (default: false)
66
67
  -h, --help display help for command
67
68
  ```
68
69
 
@@ -99,7 +100,7 @@ generateApi({
99
100
  toJS: false,
100
101
  extractRequestParams: false,
101
102
  extractRequestBody: false,
102
- prettier: {
103
+ prettier: { // By default prettier config is load from your project
103
104
  printWidth: 120,
104
105
  tabWidth: 2,
105
106
  trailingComma: "all",
package/index.d.ts CHANGED
@@ -88,6 +88,10 @@ interface GenerateApiParams {
88
88
  * extract request params to data contract (Also combine path params and query params into one object)
89
89
  */
90
90
  extractRequestParams?: boolean;
91
+ /**
92
+ * extract request body type to data contract
93
+ */
94
+ extractRequestBody?: boolean;
91
95
  /**
92
96
  * prettier configuration
93
97
  */
@@ -112,6 +116,11 @@ interface GenerateApiParams {
112
116
  * extra templates
113
117
  */
114
118
  extraTemplates?: { name: string; path: string }[];
119
+
120
+ /**
121
+ * fix up small errors in the swagger source definition
122
+ */
123
+ patch?: boolean;
115
124
  }
116
125
 
117
126
  export interface Hooks {
@@ -126,14 +135,9 @@ export interface Hooks {
126
135
  /** customize configuration object before sending it to ETA templates */
127
136
  onPrepareConfig?: <C extends GenerateApiConfiguration>(currentConfiguration: C) => C | void;
128
137
  /** customize route name as you need */
129
- onCreateRouteName?: (
130
- routeNameInfo: RouteNameInfo,
131
- rawRouteInfo: RawRouteInfo,
132
- ) => RouteNameInfo | void;
138
+ onCreateRouteName?: (routeNameInfo: RouteNameInfo, rawRouteInfo: RawRouteInfo) => RouteNameInfo | void;
133
139
  /** customize request params (path params, query params) */
134
- onCreateRequestParams?: (
135
- rawType: SchemaComponent["rawTypeData"],
136
- ) => SchemaComponent["rawTypeData"] | void;
140
+ onCreateRequestParams?: (rawType: SchemaComponent["rawTypeData"]) => SchemaComponent["rawTypeData"] | void;
137
141
  /** customize name of model type */
138
142
  onFormatTypeName?: (typeName: string, rawTypeName?: string) => string | void;
139
143
  /** customize name of route (operationId), you can do it with using onCreateRouteName too */
@@ -210,14 +214,10 @@ export interface SchemaComponent {
210
214
  discriminator?: {
211
215
  propertyName?: string;
212
216
  };
213
- $parsed: ParsedSchema<
214
- SchemaTypeObjectContent | SchemaTypeEnumContent | SchemaTypePrimitiveContent
215
- >;
217
+ $parsed: ParsedSchema<SchemaTypeObjectContent | SchemaTypeEnumContent | SchemaTypePrimitiveContent>;
216
218
  };
217
219
  componentName: string;
218
- typeData: ParsedSchema<
219
- SchemaTypeObjectContent | SchemaTypeEnumContent | SchemaTypePrimitiveContent
220
- > | null;
220
+ typeData: ParsedSchema<SchemaTypeObjectContent | SchemaTypeEnumContent | SchemaTypePrimitiveContent> | null;
221
221
  }
222
222
 
223
223
  export enum RequestContentKind {
@@ -341,10 +341,7 @@ export interface GenerateApiConfiguration {
341
341
  formatDescription: (description: string, inline?: boolean) => string;
342
342
  internalCase: (value: string) => string;
343
343
  classNameCase: (value: string) => string;
344
- getInlineParseContent: (
345
- rawTypeData: SchemaComponent["rawTypeData"],
346
- typeName?: string,
347
- ) => string;
344
+ getInlineParseContent: (rawTypeData: SchemaComponent["rawTypeData"], typeName?: string) => string;
348
345
  getParseContent: (rawTypeData: SchemaComponent["rawTypeData"], typeName?: string) => ModelType;
349
346
  getComponentByRef: (ref: string) => SchemaComponent;
350
347
  parseSchema: (
@@ -352,14 +349,8 @@ export interface GenerateApiConfiguration {
352
349
  typeName?: string,
353
350
  formattersMap?: Record<MAIN_SCHEMA_TYPES, (content: ModelType) => string>,
354
351
  ) => ModelType;
355
- formatters: Record<
356
- MAIN_SCHEMA_TYPES,
357
- (content: string | object | string[] | object[]) => string
358
- >;
359
- inlineExtraFormatters: Record<
360
- Exclude<MAIN_SCHEMA_TYPES, SCHEMA_TYPES.PRIMITIVE>,
361
- (schema: ModelType) => string
362
- >;
352
+ formatters: Record<MAIN_SCHEMA_TYPES, (content: string | object | string[] | object[]) => string>;
353
+ inlineExtraFormatters: Record<Exclude<MAIN_SCHEMA_TYPES, SCHEMA_TYPES.PRIMITIVE>, (schema: ModelType) => string>;
363
354
  formatModelName: (name: string) => string;
364
355
  fmtToJSDocLine: (line: string, params?: { eol?: boolean }) => string;
365
356
  _: import("lodash").LoDashStatic;
@@ -370,12 +361,7 @@ export interface GenerateApiConfiguration {
370
361
  export interface GenerateApiOutput {
371
362
  configuration: GenerateApiConfiguration;
372
363
  files: { name: string; content: string; declaration: { name: string; content: string } | null }[];
373
- createFile: (params: {
374
- path: string;
375
- fileName: string;
376
- content: string;
377
- withPrefix?: boolean;
378
- }) => void;
364
+ createFile: (params: { path: string; fileName: string; content: string; withPrefix?: boolean }) => void;
379
365
  renderTemplate: (
380
366
  templateContent: string,
381
367
  data: Record<string, unknown>,
@@ -385,12 +371,6 @@ export interface GenerateApiOutput {
385
371
  formatTSContent: (content: string) => string;
386
372
  }
387
373
 
388
- export declare function generateApi(
389
- params: Omit<GenerateApiParams, "url" | "spec">,
390
- ): Promise<GenerateApiOutput>;
391
- export declare function generateApi(
392
- params: Omit<GenerateApiParams, "input" | "spec">,
393
- ): Promise<GenerateApiOutput>;
394
- export declare function generateApi(
395
- params: Omit<GenerateApiParams, "input" | "url">,
396
- ): Promise<GenerateApiOutput>;
374
+ export declare function generateApi(params: Omit<GenerateApiParams, "url" | "spec">): Promise<GenerateApiOutput>;
375
+ export declare function generateApi(params: Omit<GenerateApiParams, "input" | "spec">): Promise<GenerateApiOutput>;
376
+ export declare function generateApi(params: Omit<GenerateApiParams, "input" | "url">): Promise<GenerateApiOutput>;
package/index.js CHANGED
@@ -33,29 +33,20 @@ program
33
33
  )
34
34
  .option(
35
35
  "-r, --responses",
36
- "generate additional information about request responses\n" +
37
- "also add typings for bad responses",
36
+ "generate additional information about request responses\n" + "also add typings for bad responses",
38
37
  false,
39
38
  )
40
39
  .option("--union-enums", 'generate all "enum" types as union types (T1 | T2 | TN)', false)
41
40
  .option("--route-types", "generate type definitions for API routes", false)
42
41
  .option("--no-client", "do not generate an API class", false)
43
- .option(
44
- "--enum-names-as-values",
45
- "use values in 'x-enumNames' as enum values (not only as keys)",
46
- false,
47
- )
42
+ .option("--enum-names-as-values", "use values in 'x-enumNames' as enum values (not only as keys)", false)
48
43
  .option(
49
44
  "--extract-request-params",
50
45
  "extract request params to data contract (Also combine path params and query params into one object)",
51
46
  false,
52
47
  )
53
48
  .option("--extract-request-body", "extract request body type to data contract", false)
54
- .option(
55
- "--modular",
56
- "generate separated files for http client, data contracts, and routes",
57
- false,
58
- )
49
+ .option("--modular", "generate separated files for http client, data contracts, and routes", false)
59
50
  .option("--js", "generate js api module with declaration file", false)
60
51
  .option(
61
52
  "--module-name-index <number>",
@@ -66,16 +57,15 @@ program
66
57
  .option("--disableStrictSSL", "disabled strict SSL", false)
67
58
  .option("--disableProxy", "disabled proxy", false)
68
59
  .option("--axios", "generate axios http client", false)
60
+ .option("--unwrap-response-data", "unwrap the data item from the response", false)
61
+ .option("--disable-throw-on-error", "Do not throw an error when response.ok is not true", false)
69
62
  .option("--single-http-client", "Ability to send HttpClient instance to Api constructor", false)
70
63
  .option("--silent", "Output only errors to console", false)
71
64
  .option("--default-response <type>", "default type for empty response schema", TS_KEYWORDS.VOID)
72
65
  .option("--type-prefix <string>", "data contract name prefix", "")
73
66
  .option("--type-suffix <string>", "data contract name suffix", "")
74
- .option(
75
- "--clean-output",
76
- "clean output folder before generate api. WARNING: May cause data loss",
77
- false,
78
- );
67
+ .option("--clean-output", "clean output folder before generate api. WARNING: May cause data loss", false)
68
+ .option("--patch", "fix up small errors in the swagger source definition", false);
79
69
 
80
70
  program.parse(process.argv);
81
71
 
@@ -100,11 +90,15 @@ const {
100
90
  disableProxy,
101
91
  cleanOutput,
102
92
  defaultResponse,
93
+ unwrapResponseData,
94
+ disableThrowOnError,
95
+ sortTypes,
103
96
  singleHttpClient,
104
97
  axios,
105
98
  silent,
106
99
  typePrefix,
107
100
  typeSuffix,
101
+ patch,
108
102
  } = program;
109
103
 
110
104
  generateApi({
@@ -115,6 +109,9 @@ generateApi({
115
109
  httpClientType: axios ? HTTP_CLIENT.AXIOS : HTTP_CLIENT.FETCH,
116
110
  defaultResponseAsSuccess: defaultAsSuccess,
117
111
  defaultResponseType: defaultResponse,
112
+ unwrapResponseData: unwrapResponseData,
113
+ disableThrowOnError: disableThrowOnError,
114
+ sortTypes: sortTypes,
118
115
  generateUnionEnums: unionEnums,
119
116
  generateResponses: responses,
120
117
  extractRequestParams: !!extractRequestParams,
@@ -134,4 +131,10 @@ generateApi({
134
131
  silent: !!silent,
135
132
  typePrefix,
136
133
  typeSuffix,
134
+ patch: !!patch,
135
+ }).catch((err) => {
136
+ // NOTE collect all errors on top level and shows to users in any case
137
+ console.error(err);
138
+
139
+ process.exit(1);
137
140
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swagger-typescript-api",
3
- "version": "9.1.0",
3
+ "version": "9.3.0",
4
4
  "description": "Generate typescript/javascript api from swagger schema",
5
5
  "scripts": {
6
6
  "cli:json": "node index.js -r -d -p ./swagger-test-cli.json -n swagger-test-cli.ts",
@@ -12,6 +12,7 @@
12
12
  "test-all": "node --unhandled-rejections=strict ./scriptsRunner.js generate validate test:*",
13
13
  "test-all-extended": "node --unhandled-rejections=strict ./scriptsRunner.js generate-extended validate generate validate test:*",
14
14
  "test-specific": "node ./scriptsRunner.js generate validate test:*",
15
+ "prepare": "npm run test-all-extended",
15
16
  "generate": "node tests/generate.js",
16
17
  "generate-extended": "node tests/generate-extended.js",
17
18
  "generate:debug": "node --nolazy tests/generate.js",
@@ -38,24 +39,27 @@
38
39
  "test:--axios--single-http-client": "node tests/spec/axiosSingleHttpClient/test.js",
39
40
  "test:--type-suffix--type-prefix": "node tests/spec/typeSuffixPrefix/test.js",
40
41
  "test:partialBaseTemplate": "node tests/spec/partialBaseTemplate/test.js",
41
- "test:partialDefaultTemplate": "node tests/spec/partialDefaultTemplate/test.js"
42
+ "test:partialDefaultTemplate": "node tests/spec/partialDefaultTemplate/test.js",
43
+ "test:--patch": "node tests/spec/patch/test.js"
42
44
  },
43
45
  "author": "acacode",
44
46
  "license": "MIT",
45
47
  "typings": "./index.d.ts",
46
48
  "main": "src/index.js",
47
49
  "devDependencies": {
50
+ "@types/axios": "^0.14.0",
48
51
  "@types/lodash": "^4.14.166",
49
52
  "@types/node": "^15.0.2",
50
53
  "@types/prettier": "^2.1.6",
51
54
  "all-contributors-cli": "^6.19.0",
55
+ "axios": "^0.21.4",
52
56
  "husky": "^4.3.6",
53
57
  "pretty-quick": "^3.1.0"
54
58
  },
55
59
  "dependencies": {
56
60
  "@types/swagger-schema-official": "2.0.21",
57
- "axios": "^0.21.1",
58
61
  "commander": "^6.2.1",
62
+ "cosmiconfig": "^7.0.0",
59
63
  "eta": "^1.12.1",
60
64
  "js-yaml": "^4.0.0",
61
65
  "lodash": "^4.17.21",
package/src/config.js CHANGED
@@ -58,6 +58,9 @@ const config = {
58
58
  defaultResponseType: TS_KEYWORDS.VOID,
59
59
  singleHttpClient: false,
60
60
  httpClientType: HTTP_CLIENT.FETCH,
61
+ unwrapResponseData: false,
62
+ disableThrowOnError: false,
63
+ sortTypes: false,
61
64
  templatePaths: {
62
65
  /** `templates/base` */
63
66
  base: "",
@@ -82,6 +85,7 @@ const config = {
82
85
  silent: false,
83
86
  typePrefix: "",
84
87
  typeSuffix: "",
88
+ patch: false,
85
89
  componentTypeNameResolver: new NameResolver([]),
86
90
  };
87
91
 
package/src/index.js CHANGED
@@ -21,6 +21,7 @@ const { generateOutputFiles } = require("./output");
21
21
  const formatFileContent = require("./formatFileContent");
22
22
  const { logger } = require("./logger");
23
23
  const { ComponentTypeNameResolver } = require("./utils/resolveName");
24
+ const { getPrettierOptions } = require("./prettierOptions");
24
25
 
25
26
  module.exports = {
26
27
  constants: constants,
@@ -44,8 +45,11 @@ module.exports = {
44
45
  extractRequestParams = config.extractRequestParams,
45
46
  extractRequestBody = config.extractRequestBody,
46
47
  defaultResponseType = config.defaultResponseType,
48
+ unwrapResponseData = config.unwrapResponseData,
49
+ disableThrowOnError = config.disableThrowOnError,
50
+ sortTypes = config.sortTypes,
47
51
  singleHttpClient = config.singleHttpClient,
48
- prettier: prettierOptions = constants.PRETTIER_OPTIONS,
52
+ prettier: prettierOptions = getPrettierOptions(),
49
53
  hooks: rawHooks,
50
54
  extraTemplates,
51
55
  enumNamesAsValues,
@@ -55,6 +59,7 @@ module.exports = {
55
59
  silent = config.silent,
56
60
  typePrefix = config.typePrefix,
57
61
  typeSuffix = config.typeSuffix,
62
+ patch = config.patch,
58
63
  }) =>
59
64
  new Promise((resolve, reject) => {
60
65
  addToConfig({
@@ -77,16 +82,20 @@ module.exports = {
77
82
  disableProxy,
78
83
  cleanOutput,
79
84
  defaultResponseType,
85
+ unwrapResponseData,
86
+ disableThrowOnError,
87
+ sortTypes,
80
88
  singleHttpClient,
81
89
  constants,
82
90
  silent,
83
91
  toJS: translateToJavaScript,
84
92
  typePrefix,
85
93
  typeSuffix,
94
+ patch,
86
95
  });
87
96
  (spec
88
- ? convertSwaggerObject(spec)
89
- : getSwaggerObject(input, url, disableStrictSSL, disableProxy)
97
+ ? convertSwaggerObject(spec, { patch })
98
+ : getSwaggerObject(input, url, disableStrictSSL, disableProxy, { patch })
90
99
  )
91
100
  .then(({ usageSchema, originalSchema }) => {
92
101
  const templatePaths = getTemplatePaths(config);
@@ -136,11 +145,41 @@ module.exports = {
136
145
  const hasFormDataRoutes = routes.some((route) => route.hasFormDataParams);
137
146
 
138
147
  const usageComponentSchemas = filterComponentsMap(componentsMap, "schemas");
148
+ const sortByProperty = (o1, o2, propertyName) => {
149
+ if(o1[propertyName] > o2[propertyName]) {
150
+ return 1;
151
+ }
152
+ if(o1[propertyName] < o2[propertyName]) {
153
+ return -1;
154
+ }
155
+ return 0;
156
+ }
157
+ const sortByTypeName = (o1, o2) => sortByProperty(o1, o2, 'typeName');
158
+
159
+ const sortByName = (o1, o2) => sortByProperty(o1, o2, 'name');
160
+
161
+ const sortSchemas = (schemas) => {
162
+ if(config.sortTypes) {
163
+ return schemas.sort(sortByTypeName).map((schema) => {
164
+ if(schema.rawTypeData?.properties) {
165
+ return {
166
+ ...schema,
167
+ rawTypeData: {
168
+ ...schema.rawTypeData,
169
+ '$parsed': {...schema.rawTypeData['$parsed'], content: schema.rawTypeData['$parsed'].content.sort(sortByName)}
170
+ }
171
+ }
172
+ }
173
+ return schema;
174
+ });
175
+ }
176
+ return schemas;
177
+ };
139
178
 
140
179
  const rawConfiguration = {
141
180
  apiConfig: createApiConfig(usageSchema),
142
181
  config,
143
- modelTypes: _.map(usageComponentSchemas, prepareModelType),
182
+ modelTypes: _.map(sortSchemas(usageComponentSchemas), prepareModelType),
144
183
  rawModelTypes: usageComponentSchemas,
145
184
  hasFormDataRoutes,
146
185
  hasSecurityRoutes,
@@ -0,0 +1,23 @@
1
+ const { cosmiconfigSync } = require("cosmiconfig");
2
+ const constants = require("./constants");
3
+
4
+ /**
5
+ * Get prettier options from user's project or return the default one
6
+ * @return {import('prettier').Options} Prettier options
7
+ */
8
+ function getPrettierOptions() {
9
+ const prettier = cosmiconfigSync("prettier").search();
10
+
11
+ if (prettier) {
12
+ return {
13
+ ...prettier.config,
14
+ parser: "typescript",
15
+ };
16
+ }
17
+
18
+ return constants.PRETTIER_OPTIONS;
19
+ }
20
+
21
+ module.exports = {
22
+ getPrettierOptions,
23
+ };
package/src/routes.js CHANGED
@@ -2,6 +2,7 @@ const _ = require("lodash");
2
2
  const {
3
3
  types,
4
4
  parseSchema,
5
+ getType,
5
6
  getRefType,
6
7
  getInlineParseContent,
7
8
  checkAndAddNull,
@@ -475,6 +476,21 @@ const getResponseBodyInfo = (routeInfo, routeParams, parsedSchemas) => {
475
476
  (response) => !response.isSuccess && response.type !== TS_KEYWORDS.ANY,
476
477
  );
477
478
 
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
+
478
494
  return {
479
495
  contentTypes,
480
496
  responses: responseInfos,
@@ -486,6 +502,19 @@ const getResponseBodyInfo = (routeInfo, routeParams, parsedSchemas) => {
486
502
  schemas: errorResponses,
487
503
  type: _.uniq(errorResponses.map((response) => response.type)).join(" | ") || TS_KEYWORDS.ANY,
488
504
  },
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
+ },
489
518
  };
490
519
  };
491
520
 
@@ -685,6 +714,7 @@ const parseRoutes = ({
685
714
  contentTypes: responseBodyInfo.contentTypes,
686
715
  type: responseBodyInfo.success.type,
687
716
  errorType: responseBodyInfo.error.type,
717
+ fullTypes: responseBodyInfo.full.types,
688
718
  },
689
719
  raw: rawRouteInfo,
690
720
  };
package/src/schema.js CHANGED
@@ -140,6 +140,7 @@ const getObjectTypeContent = (schema) => {
140
140
 
141
141
  return {
142
142
  $$raw: property,
143
+ title: property.title,
143
144
  description: _.compact([
144
145
  property.description ||
145
146
  _.compact(_.map(property[getComplexType(property)], "description"))[0] ||
package/src/swagger.js CHANGED
@@ -18,7 +18,7 @@ const parseSwaggerFile = (file) => {
18
18
  };
19
19
 
20
20
  const getSwaggerFile = (pathToSwagger, urlToSwagger, disableStrictSSL, disableProxy) =>
21
- new Promise((resolve) => {
21
+ new Promise((resolve, reject) => {
22
22
  if (pathIsExist(pathToSwagger)) {
23
23
  logger.log(`try to get swagger by path "${pathToSwagger}"`);
24
24
  resolve(getFileContent(pathToSwagger));
@@ -38,16 +38,28 @@ const getSwaggerFile = (pathToSwagger, urlToSwagger, disableStrictSSL, disablePr
38
38
  axios
39
39
  .get(urlToSwagger, axiosOptions)
40
40
  .then((res) => resolve(res.data))
41
- .catch((err) => logger.error(`error while getting swagger by URL ${urlToSwagger}:`, err));
41
+ .catch(() => {
42
+ const message = `error while getting swagger by URL ${urlToSwagger}`;
43
+
44
+ logger.error(message);
45
+
46
+ reject(message);
47
+ });
42
48
  }
43
49
  });
44
50
 
45
- const getSwaggerObject = (pathToSwagger, urlToSwagger, disableStrictSSL, disableProxy) =>
51
+ const getSwaggerObject = (
52
+ pathToSwagger,
53
+ urlToSwagger,
54
+ disableStrictSSL,
55
+ disableProxy,
56
+ converterOptions,
57
+ ) =>
46
58
  getSwaggerFile(pathToSwagger, urlToSwagger, disableStrictSSL, disableProxy).then((file) =>
47
- convertSwaggerObject(parseSwaggerFile(file)),
59
+ convertSwaggerObject(parseSwaggerFile(file), converterOptions),
48
60
  );
49
61
 
50
- const convertSwaggerObject = (swaggerSchema) => {
62
+ const convertSwaggerObject = (swaggerSchema, converterOptions) => {
51
63
  return new Promise((resolve) => {
52
64
  swaggerSchema.info = _.merge(
53
65
  {
@@ -63,6 +75,7 @@ const convertSwaggerObject = (swaggerSchema) => {
63
75
  converter.convertObj(
64
76
  swaggerSchema,
65
77
  {
78
+ ...converterOptions,
66
79
  warnOnly: true,
67
80
  refSiblings: "preserve",
68
81
  rbname: "requestBodyName",
@@ -18,10 +18,10 @@ const formatters = {
18
18
  const extraSpace = " ";
19
19
  const result = `${extraSpace}${part.field};\n`;
20
20
 
21
- const comments = _.compact([part.title, part.description]).reduce(
21
+ const comments = _.uniq(_.compact([part.title, part.description]).reduce(
22
22
  (acc, comment) => [...acc, ...comment.split(/\n/g)],
23
23
  [],
24
- );
24
+ ));
25
25
 
26
26
  const commonText = comments.length
27
27
  ? [
@@ -1,5 +1,5 @@
1
1
  <%
2
- const { apiConfig, generateResponses } = it;
2
+ const { apiConfig, generateResponses, config } = it;
3
3
  %>
4
4
 
5
5
  import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, ResponseType } from "axios";
@@ -66,6 +66,21 @@ export class HttpClient<SecurityDataType = unknown> {
66
66
  };
67
67
  }
68
68
 
69
+ private createFormData(input: Record<string, unknown>): FormData {
70
+ return Object.keys(input || {}).reduce((formData, key) => {
71
+ const property = input[key];
72
+ formData.append(
73
+ key,
74
+ property instanceof Blob ?
75
+ property :
76
+ typeof property === "object" && property !== null ?
77
+ JSON.stringify(property) :
78
+ `${property}`
79
+ );
80
+ return formData;
81
+ }, new FormData())
82
+ }
83
+
69
84
  public request = async <T = any, _E = any>({
70
85
  secure,
71
86
  path,
@@ -74,7 +89,11 @@ export class HttpClient<SecurityDataType = unknown> {
74
89
  format,
75
90
  body,
76
91
  ...params
92
+ <% if (config.unwrapResponseData) { %>
93
+ }: FullRequestParams): Promise<T> => {
94
+ <% } else { %>
77
95
  }: FullRequestParams): Promise<AxiosResponse<T>> => {
96
+ <% } %>
78
97
  const secureParams = ((typeof secure === 'boolean' ? secure : this.secure) && this.securityWorker && (await this.securityWorker(this.securityData))) || {};
79
98
  const requestParams = this.mergeRequestParams(params, secureParams);
80
99
  const responseFormat = (format && this.format) || void 0;
@@ -84,11 +103,7 @@ export class HttpClient<SecurityDataType = unknown> {
84
103
  requestParams.headers.post = {};
85
104
  requestParams.headers.put = {};
86
105
 
87
- const formData = new FormData();
88
- for (const key in body) {
89
- formData.append(key, body[key as keyof typeof body]);
90
- }
91
- body = formData;
106
+ body = this.createFormData(body as Record<string, unknown>);
92
107
  }
93
108
 
94
109
  return this.instance.request({
@@ -101,6 +116,10 @@ export class HttpClient<SecurityDataType = unknown> {
101
116
  responseType: responseFormat,
102
117
  data: body,
103
118
  url: path,
119
+ <% if (config.unwrapResponseData) { %>
120
+ }).then(response => response.data);
121
+ <% } else { %>
104
122
  });
123
+ <% } %>
105
124
  };
106
125
  }
@@ -1,5 +1,5 @@
1
1
  <%
2
- const { apiConfig, generateResponses } = it;
2
+ const { apiConfig, generateResponses, config } = it;
3
3
  %>
4
4
 
5
5
  export type QueryParamsType = Record<string | number, any>;
@@ -103,10 +103,18 @@ export class HttpClient<SecurityDataType = unknown> {
103
103
  private contentFormatters: Record<ContentType, (input: any) => any> = {
104
104
  [ContentType.Json]: (input:any) => input !== null && (typeof input === "object" || typeof input === "string") ? JSON.stringify(input) : input,
105
105
  [ContentType.FormData]: (input: any) =>
106
- Object.keys(input || {}).reduce((data, key) => {
107
- data.append(key, input[key]);
108
- return data;
109
- }, new FormData()),
106
+ Object.keys(input || {}).reduce((formData, key) => {
107
+ const property = input[key];
108
+ formData.append(
109
+ key,
110
+ property instanceof Blob ?
111
+ property :
112
+ typeof property === "object" && property !== null ?
113
+ JSON.stringify(property) :
114
+ `${property}`
115
+ );
116
+ return formData;
117
+ }, new FormData()),
110
118
  [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input),
111
119
  }
112
120
 
@@ -156,7 +164,11 @@ export class HttpClient<SecurityDataType = unknown> {
156
164
  baseUrl,
157
165
  cancelToken,
158
166
  ...params
167
+ <% if (config.unwrapResponseData) { %>
168
+ }: FullRequestParams): Promise<T> => {
169
+ <% } else { %>
159
170
  }: FullRequestParams): Promise<HttpResponse<T, E>> => {
171
+ <% } %>
160
172
  const secureParams = ((typeof secure === 'boolean' ? secure : this.baseApiParams.secure) && this.securityWorker && await this.securityWorker(this.securityData)) || {};
161
173
  const requestParams = this.mergeRequestParams(params, secureParams);
162
174
  const queryString = query && this.toQueryString(query);
@@ -197,8 +209,14 @@ export class HttpClient<SecurityDataType = unknown> {
197
209
  this.abortControllers.delete(cancelToken);
198
210
  }
199
211
 
212
+ <% if (!config.disableThrowOnError) { %>
200
213
  if (!response.ok) throw data;
214
+ <% } %>
215
+ <% if (config.unwrapResponseData) { %>
216
+ return data.data;
217
+ <% } else { %>
201
218
  return data;
219
+ <% } %>
202
220
  });
203
221
  };
204
222
  }
@@ -39,7 +39,11 @@ const descriptionLines = _.compact([
39
39
  export class Api<SecurityDataType extends unknown><% if (!config.singleHttpClient) { %> extends HttpClient<SecurityDataType> <% } %> {
40
40
 
41
41
  <% if(config.singleHttpClient) { %>
42
- constructor (private http: HttpClient<SecurityDataType>) {}
42
+ http: HttpClient<SecurityDataType>;
43
+
44
+ constructor (http: HttpClient<SecurityDataType>) {
45
+ this.http = http;
46
+ }
43
47
  <% } %>
44
48
 
45
49
 
@@ -8,15 +8,18 @@ const dataContracts = _.map(modelTypes, "name");
8
8
 
9
9
  <% if (config.httpClientType === config.constants.HTTP_CLIENT.AXIOS) { %> import { AxiosRequestConfig, AxiosResponse } from "axios"; <% } %>
10
10
 
11
- import { HttpClient, RequestParams, ContentType } from "./<%~ config.fileNames.httpClient %>";
11
+ import { HttpClient, RequestParams, ContentType, HttpResponse } from "./<%~ config.fileNames.httpClient %>";
12
12
  <% if (dataContracts.length) { %>
13
13
  import { <%~ dataContracts.join(", ") %> } from "./<%~ config.fileNames.dataContracts %>"
14
14
  <% } %>
15
15
 
16
16
  export class <%= apiClassName %><SecurityDataType = unknown><% if (!config.singleHttpClient) { %> extends HttpClient<SecurityDataType> <% } %> {
17
-
18
17
  <% if(config.singleHttpClient) { %>
19
- constructor (private http: HttpClient<SecurityDataType>) {}
18
+ http: HttpClient<SecurityDataType>;
19
+
20
+ constructor (http: HttpClient<SecurityDataType>) {
21
+ this.http = http;
22
+ }
20
23
  <% } %>
21
24
 
22
25
  <% routes.forEach((route) => { %>