Skip to content

Commit 027a727

Browse files
committed
Add axios client support
1 parent 715ddce commit 027a727

17 files changed

+290
-4
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ $ openapi --help
4040
-V, --version output the version number
4141
-i, --input <value> OpenAPI specification, can be a path, url or string content (required)
4242
-o, --output <value> Output directory (required)
43-
-c, --client <value> HTTP client to generate [fetch, xhr, node] (default: "fetch")
43+
-c, --client <value> HTTP client to generate [fetch, axios, xhr, node] (default: "fetch")
4444
--useOptions Use options instead of arguments
4545
--useUnionTypes Use union types instead of enums
4646
--exportCore <value> Write core files to disk (default: true)

bin/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const params = program
1212
.version(pkg.version)
1313
.requiredOption('-i, --input <value>', 'OpenAPI specification, can be a path, url or string content (required)')
1414
.requiredOption('-o, --output <value>', 'Output directory (required)')
15-
.option('-c, --client <value>', 'HTTP client to generate [fetch, xhr, node]', 'fetch')
15+
.option('-c, --client <value>', 'HTTP client to generate [fetch, axios, xhr, node]', 'fetch')
1616
.option('--useOptions', 'Use options instead of arguments')
1717
.option('--useUnionTypes', 'Use union types instead of enums')
1818
.option('--exportCore <value>', 'Write core files to disk', true)

jest.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@ module.exports = {
1919
testEnvironment: 'node',
2020
testMatch: [
2121
'<rootDir>/test/e2e/v2.fetch.spec.js',
22+
'<rootDir>/test/e2e/v2.axios.spec.js',
2223
'<rootDir>/test/e2e/v2.xhr.spec.js',
2324
'<rootDir>/test/e2e/v2.node.spec.js',
2425
'<rootDir>/test/e2e/v2.babel.spec.js',
2526
'<rootDir>/test/e2e/v3.fetch.spec.js',
27+
'<rootDir>/test/e2e/v3.axios.spec.js',
2628
'<rootDir>/test/e2e/v3.xhr.spec.js',
2729
'<rootDir>/test/e2e/v3.node.spec.js',
2830
'<rootDir>/test/e2e/v3.babel.spec.js',

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "openapi-typescript-codegen",
3-
"version": "0.9.3",
3+
"version": "0.9.4",
44
"description": "Library that generates Typescript clients based on the OpenAPI specification.",
55
"author": "Ferdi Koomen",
66
"homepage": "https://github.com/ferdikoomen/openapi-typescript-codegen",
@@ -23,7 +23,8 @@
2323
"json",
2424
"fetch",
2525
"xhr",
26-
"node"
26+
"node",
27+
"axios"
2728
],
2829
"maintainers": [
2930
{
@@ -76,6 +77,7 @@
7677
"@babel/preset-typescript": "7.14.5",
7778
"@rollup/plugin-commonjs": "20.0.0",
7879
"@rollup/plugin-node-resolve": "13.0.4",
80+
"@types/axios": "0.14.0",
7981
"@types/express": "4.17.13",
8082
"@types/jest": "26.0.24",
8183
"@types/js-yaml": "4.0.2",
@@ -84,6 +86,7 @@
8486
"@types/qs": "6.9.7",
8587
"@typescript-eslint/eslint-plugin": "4.28.5",
8688
"@typescript-eslint/parser": "4.28.5",
89+
"axios": "0.21.1",
8790
"codecov": "3.8.3",
8891
"eslint": "7.32.0",
8992
"eslint-config-prettier": "8.3.0",

src/HttpClient.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export enum HttpClient {
22
FETCH = 'fetch',
3+
AXIOS = 'axios',
34
XHR = 'xhr',
45
NODE = 'node',
56
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
async function getHeaders(options: ApiRequestOptions): Promise<Headers> {
2+
const token = await resolve(options, OpenAPI.TOKEN);
3+
const username = await resolve(options, OpenAPI.USERNAME);
4+
const password = await resolve(options, OpenAPI.PASSWORD);
5+
const defaultHeaders = await resolve(options, OpenAPI.HEADERS);
6+
7+
const headers = new Headers({
8+
Accept: 'application/json',
9+
...defaultHeaders,
10+
...options.headers,
11+
});
12+
13+
if (isStringWithValue(token)) {
14+
headers.append('Authorization', `Bearer ${token}`);
15+
}
16+
17+
if (isStringWithValue(username) && isStringWithValue(password)) {
18+
const credentials = btoa(`${username}:${password}`);
19+
headers.append('Authorization', `Basic ${credentials}`);
20+
}
21+
22+
if (options.body) {
23+
if (options.mediaType) {
24+
headers.append('Content-Type', options.mediaType);
25+
} else if (isBlob(options.body)) {
26+
headers.append('Content-Type', options.body.type || 'application/octet-stream');
27+
} else if (isString(options.body)) {
28+
headers.append('Content-Type', 'text/plain');
29+
} else {
30+
headers.append('Content-Type', 'application/json');
31+
}
32+
}
33+
return headers;
34+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function getRequestBody(options: ApiRequestOptions): BodyInit | undefined {
2+
if (options.formData) {
3+
return getFormData(options.formData);
4+
}
5+
if (options.body) {
6+
return options.body;
7+
}
8+
return undefined;
9+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
async function getResponseBody(response: AxiosResponse<any>): Promise<any> {
2+
try {
3+
const contentType = response.headers.get('Content-Type');
4+
if (contentType) {
5+
const isJSON = contentType.toLowerCase().startsWith('application/json');
6+
if (isJSON) {
7+
return await response.json();
8+
} else {
9+
return await response.text();
10+
}
11+
}
12+
} catch (error) {
13+
console.error(error);
14+
}
15+
return null;
16+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
function getResponseHeader(response: AxiosResponse<any>, responseHeader?: string): string | null {
2+
if (responseHeader) {
3+
const content = response.headers.get(responseHeader);
4+
if (isString(content)) {
5+
return content;
6+
}
7+
}
8+
return null;
9+
}

src/templates/core/axios/request.hbs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
{{>header}}
2+
3+
import axios, { AxiosResponse, AxiosRequestConfig } from 'axios';
4+
5+
import { ApiError } from './ApiError';
6+
import type { ApiRequestOptions } from './ApiRequestOptions';
7+
import type { ApiResult } from './ApiResult';
8+
import { OpenAPI } from './OpenAPI';
9+
10+
{{>functions/isDefined}}
11+
12+
13+
{{>functions/isString}}
14+
15+
16+
{{>functions/isStringWithValue}}
17+
18+
19+
{{>functions/isBlob}}
20+
21+
22+
{{>functions/isSuccess}}
23+
24+
25+
{{>functions/getQueryString}}
26+
27+
28+
{{>functions/getUrl}}
29+
30+
31+
{{>functions/getFormData}}
32+
33+
34+
{{>functions/resolve}}
35+
36+
37+
{{>axios/getHeaders}}
38+
39+
40+
{{>axios/getRequestBody}}
41+
42+
43+
{{>axios/sendRequest}}
44+
45+
46+
{{>axios/getResponseHeader}}
47+
48+
49+
{{>functions/catchErrors}}
50+
51+
52+
/**
53+
* Request using axios client
54+
* @param options The request options from the the service
55+
* @returns ApiResult
56+
* @throws ApiError
57+
*/
58+
export async function request(options: ApiRequestOptions): Promise<ApiResult> {
59+
const url = getUrl(options);
60+
const response = await sendRequest(options, url);
61+
const responseBody = response.data;
62+
const responseHeader = getResponseHeader(response, options.responseHeader);
63+
64+
const result: ApiResult = {
65+
url,
66+
ok: isSuccess(response.status),
67+
status: response.status,
68+
statusText: response.statusText,
69+
body: responseHeader || responseBody,
70+
};
71+
72+
catchErrors(options, result);
73+
return result;
74+
}

0 commit comments

Comments
 (0)