@mittwald/api-client-commons 4.2.0-alpha.6 → 4.2.1-alpha.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/LICENSE +21 -0
- package/dist/esm/axios.js +1 -0
- package/dist/esm/core/ApiClientBase.js +13 -0
- package/dist/esm/core/ApiClientError.js +12 -0
- package/dist/esm/core/OpenAPIPath.js +20 -0
- package/dist/esm/core/Request.js +76 -0
- package/dist/esm/core/Request.test.js +53 -0
- package/dist/esm/core/index.js +4 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/react/ApiCallAsyncResourceFactory.js +35 -0
- package/dist/esm/react/ApiCallAsyncResourceFactory.test-types.js +36 -0
- package/dist/esm/react/ApiCallAsyncResourceFactory.test.js +46 -0
- package/dist/esm/react/index.js +1 -0
- package/dist/esm/react/types.js +1 -0
- package/dist/esm/types/NullableOnNoRequiredKeysDeep.js +1 -0
- package/dist/esm/types/OpenAPIOperation.js +1 -0
- package/dist/esm/types/RequestFunction.js +1 -0
- package/dist/esm/types/RequestFunction.test-types.js +29 -0
- package/dist/esm/types/RequestType.js +1 -0
- package/dist/esm/types/RequestType.test-types.js +146 -0
- package/dist/esm/types/Response.js +1 -0
- package/dist/esm/types/Response.test-types.js +70 -0
- package/dist/esm/types/assertStatus.js +7 -0
- package/dist/esm/types/assertStatus.test-types.js +8 -0
- package/dist/esm/types/http.js +1 -0
- package/dist/esm/types/index.js +7 -0
- package/dist/esm/types/simplify.js +1 -0
- package/dist/types/axios.d.ts +1 -0
- package/dist/types/core/ApiClientBase.d.ts +9 -0
- package/dist/types/core/ApiClientError.d.ts +7 -0
- package/dist/types/core/OpenAPIPath.d.ts +9 -0
- package/dist/types/core/Request.d.ts +13 -0
- package/dist/types/core/Request.test.d.ts +1 -0
- package/dist/types/core/index.d.ts +4 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/react/ApiCallAsyncResourceFactory.d.ts +12 -0
- package/dist/types/react/ApiCallAsyncResourceFactory.test-types.d.ts +1 -0
- package/dist/types/react/ApiCallAsyncResourceFactory.test.d.ts +1 -0
- package/dist/types/react/index.d.ts +1 -0
- package/dist/types/react/types.d.ts +3 -0
- package/dist/types/types/NullableOnNoRequiredKeysDeep.d.ts +6 -0
- package/dist/types/types/OpenAPIOperation.d.ts +20 -0
- package/dist/types/types/RequestFunction.d.ts +11 -0
- package/dist/types/types/RequestFunction.test-types.d.ts +1 -0
- package/dist/types/types/RequestType.d.ts +21 -0
- package/dist/types/types/RequestType.test-types.d.ts +1 -0
- package/dist/types/types/Response.d.ts +7 -0
- package/dist/types/types/Response.test-types.d.ts +1 -0
- package/dist/types/types/assertStatus.d.ts +5 -0
- package/dist/types/types/assertStatus.test-types.d.ts +1 -0
- package/dist/types/types/http.d.ts +13 -0
- package/dist/types/types/index.d.ts +7 -0
- package/dist/types/types/simplify.d.ts +3 -0
- package/package.json +52 -45
- package/dist/RequestFunction-b1412636.d.ts +0 -71
- package/dist/chunk-PEYA5TMK.js +0 -154
- package/dist/index.cjs +0 -196
- package/dist/index.d.cts +0 -49
- package/dist/index.d.ts +0 -49
- package/dist/index.js +0 -48
- package/dist/react.cjs +0 -185
- package/dist/react.d.cts +0 -19
- package/dist/react.d.ts +0 -19
- package/dist/react.js +0 -45
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Mittwald CM Service GmbH & Co. KG and contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "axios";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import axios, { Axios } from "axios";
|
|
2
|
+
import Request from "./Request.js";
|
|
3
|
+
export class ApiClientBase {
|
|
4
|
+
axios;
|
|
5
|
+
constructor(axiosConfig = axios) {
|
|
6
|
+
this.axios =
|
|
7
|
+
axiosConfig instanceof Axios ? axiosConfig : axios.create(axiosConfig);
|
|
8
|
+
}
|
|
9
|
+
requestFunctionFactory(operation) {
|
|
10
|
+
return (conf) => new Request(operation, conf).execute(this.axios);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export default ApiClientBase;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AxiosError } from "axios";
|
|
2
|
+
export class ApiClientError extends AxiosError {
|
|
3
|
+
constructor(message, code, config, request, response) {
|
|
4
|
+
super(message, code, config, request, response);
|
|
5
|
+
Object.setPrototypeOf(this, ApiClientError.prototype);
|
|
6
|
+
this.name = "ApiClientError";
|
|
7
|
+
}
|
|
8
|
+
static fromResponse(message, response) {
|
|
9
|
+
return new ApiClientError(message, undefined, response.config, response.request, response);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export default ApiClientError;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export class OpenAPIPath {
|
|
2
|
+
rawPath;
|
|
3
|
+
params;
|
|
4
|
+
constructor(rawPath, params) {
|
|
5
|
+
this.rawPath = rawPath;
|
|
6
|
+
this.params = params;
|
|
7
|
+
}
|
|
8
|
+
buildUrl() {
|
|
9
|
+
return OpenAPIPath.setPathParams(this.rawPath, this.params);
|
|
10
|
+
}
|
|
11
|
+
static setPathParams(path, params) {
|
|
12
|
+
const asEntries = Object.entries(params ?? {});
|
|
13
|
+
const finalPath = asEntries.reduce((path, entry) => {
|
|
14
|
+
const [key, value] = entry;
|
|
15
|
+
return path.replace(`{${key}}`, encodeURIComponent(value));
|
|
16
|
+
}, path);
|
|
17
|
+
return finalPath.startsWith("/") ? finalPath.substring(1) : finalPath;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export default OpenAPIPath;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import OpenAPIPath from "./OpenAPIPath.js";
|
|
2
|
+
export class Request {
|
|
3
|
+
operationDescriptor;
|
|
4
|
+
requestObject;
|
|
5
|
+
requestConfig;
|
|
6
|
+
constructor(operationDescriptor, requestObject) {
|
|
7
|
+
this.operationDescriptor = operationDescriptor;
|
|
8
|
+
this.requestObject = requestObject;
|
|
9
|
+
this.requestConfig = Object.freeze(this.buildAxiosConfig());
|
|
10
|
+
}
|
|
11
|
+
execute(axios) {
|
|
12
|
+
return axios.request(this.requestConfig);
|
|
13
|
+
}
|
|
14
|
+
buildAxiosConfig() {
|
|
15
|
+
const { method, path } = this.operationDescriptor;
|
|
16
|
+
const pathParameters = this.requestObject;
|
|
17
|
+
const openApiPath = new OpenAPIPath(path, pathParameters);
|
|
18
|
+
const url = openApiPath.buildUrl();
|
|
19
|
+
const data = this.requestObject && "data" in this.requestObject
|
|
20
|
+
? this.requestObject.data
|
|
21
|
+
: undefined;
|
|
22
|
+
const headersConfig = this.requestObject && "headers" in this.requestObject
|
|
23
|
+
? this.requestObject.headers
|
|
24
|
+
: undefined;
|
|
25
|
+
const headers = headersConfig
|
|
26
|
+
? this.makeAxiosHeaders(headersConfig)
|
|
27
|
+
: undefined;
|
|
28
|
+
const queryParametersConfig = this.requestObject && "queryParameters" in this.requestObject
|
|
29
|
+
? this.requestObject.queryParameters
|
|
30
|
+
: undefined;
|
|
31
|
+
const params = this.convertQueryToUrlSearchParams(queryParametersConfig);
|
|
32
|
+
return {
|
|
33
|
+
url,
|
|
34
|
+
method,
|
|
35
|
+
headers,
|
|
36
|
+
// Must be a plain object or an URLSearchParams object
|
|
37
|
+
params,
|
|
38
|
+
data,
|
|
39
|
+
validateStatus: () => true,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
makeAxiosHeaders(headers) {
|
|
43
|
+
return Object.fromEntries(Object.entries(headers).map(([key, value]) => [key, value?.toString()]));
|
|
44
|
+
}
|
|
45
|
+
convertQueryToUrlSearchParams(query) {
|
|
46
|
+
if (query === undefined || query === null) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
if (query instanceof URLSearchParams) {
|
|
50
|
+
return query;
|
|
51
|
+
}
|
|
52
|
+
if (typeof query === "string") {
|
|
53
|
+
return new URLSearchParams(query);
|
|
54
|
+
}
|
|
55
|
+
if (typeof query === "object") {
|
|
56
|
+
const searchParams = new URLSearchParams();
|
|
57
|
+
for (const [key, value] of Object.entries(query)) {
|
|
58
|
+
if (Array.isArray(value)) {
|
|
59
|
+
for (const arrayItem of value) {
|
|
60
|
+
searchParams.append(key, arrayItem);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
searchParams.append(key, typeof value === "string" ||
|
|
65
|
+
typeof value === "number" ||
|
|
66
|
+
typeof value === "boolean"
|
|
67
|
+
? value.toString()
|
|
68
|
+
: JSON.stringify(value));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return searchParams;
|
|
72
|
+
}
|
|
73
|
+
throw new Error(`Unexpected query parameter type (${typeof query})`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export default Request;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import Request from "./Request.js";
|
|
2
|
+
import { jest } from "@jest/globals";
|
|
3
|
+
const requestFn = jest.fn();
|
|
4
|
+
const mockedAxios = {
|
|
5
|
+
request: requestFn,
|
|
6
|
+
};
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
jest.resetAllMocks();
|
|
9
|
+
});
|
|
10
|
+
describe("query parameters", () => {
|
|
11
|
+
const op = {
|
|
12
|
+
path: "/",
|
|
13
|
+
operationId: "test",
|
|
14
|
+
method: "GET",
|
|
15
|
+
};
|
|
16
|
+
const executeRequest = (query) => {
|
|
17
|
+
const request = new Request(op, { queryParameters: query });
|
|
18
|
+
request.execute(mockedAxios);
|
|
19
|
+
const requestConfig = requestFn.mock.calls[0][0];
|
|
20
|
+
return requestConfig.params.toString();
|
|
21
|
+
};
|
|
22
|
+
test("Empty query", () => {
|
|
23
|
+
const query = executeRequest({});
|
|
24
|
+
expect(query).toBe("");
|
|
25
|
+
});
|
|
26
|
+
test("Simple parameter", () => {
|
|
27
|
+
const query = executeRequest({
|
|
28
|
+
foo: "bar",
|
|
29
|
+
});
|
|
30
|
+
expect(query).toBe("foo=bar");
|
|
31
|
+
});
|
|
32
|
+
test("Two parameters", () => {
|
|
33
|
+
const query = executeRequest({
|
|
34
|
+
foo: "bar",
|
|
35
|
+
bam: "baz",
|
|
36
|
+
});
|
|
37
|
+
expect(query).toBe("foo=bar&bam=baz");
|
|
38
|
+
});
|
|
39
|
+
test("Array parameters", () => {
|
|
40
|
+
const query = executeRequest({
|
|
41
|
+
foo: ["bar", "bam"],
|
|
42
|
+
});
|
|
43
|
+
expect(query).toBe("foo=bar&foo=bam");
|
|
44
|
+
});
|
|
45
|
+
test("Number, boolean, JSON", () => {
|
|
46
|
+
const query = executeRequest({
|
|
47
|
+
foo: 1,
|
|
48
|
+
bar: true,
|
|
49
|
+
baz: { some: "value" },
|
|
50
|
+
});
|
|
51
|
+
expect(query).toBe("foo=1&bar=true&baz=%7B%22some%22%3A%22value%22%7D");
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { getAsyncResource } from "@mittwald/react-use-promise";
|
|
2
|
+
import { assertStatus, } from "../types/index.js";
|
|
3
|
+
import Request from "../core/Request.js";
|
|
4
|
+
export class ApiCallAsyncResourceFactory {
|
|
5
|
+
static namespace = "@mittwald/api-client";
|
|
6
|
+
operation;
|
|
7
|
+
requestFn;
|
|
8
|
+
constructor(operation, requestFn) {
|
|
9
|
+
this.operation = operation;
|
|
10
|
+
this.requestFn = requestFn;
|
|
11
|
+
}
|
|
12
|
+
getAsyncResourceId() {
|
|
13
|
+
return `${ApiCallAsyncResourceFactory.namespace}/${this.operation.operationId}`;
|
|
14
|
+
}
|
|
15
|
+
getAsyncResourceTags(request) {
|
|
16
|
+
const url = request.requestConfig.url ?? "";
|
|
17
|
+
return [
|
|
18
|
+
this.getAsyncResourceId(),
|
|
19
|
+
`${ApiCallAsyncResourceFactory.namespace}/${this.operation.method}`,
|
|
20
|
+
`${ApiCallAsyncResourceFactory.namespace}/${url}`,
|
|
21
|
+
];
|
|
22
|
+
}
|
|
23
|
+
async executeRequest(requestObj) {
|
|
24
|
+
const response = await this.requestFn(requestObj);
|
|
25
|
+
assertStatus(response, 200);
|
|
26
|
+
return response.data;
|
|
27
|
+
}
|
|
28
|
+
getApiResource = ((requestObj) => {
|
|
29
|
+
const request = new Request(this.operation, requestObj);
|
|
30
|
+
return getAsyncResource((requestObj) => this.executeRequest(requestObj), [requestObj], {
|
|
31
|
+
tags: this.getAsyncResourceTags(request),
|
|
32
|
+
loaderId: this.getAsyncResourceId(),
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ApiCallAsyncResourceFactory } from "./ApiCallAsyncResourceFactory.js";
|
|
2
|
+
const getStuff = new ApiCallAsyncResourceFactory({
|
|
3
|
+
operationId: "getStuff",
|
|
4
|
+
path: "/stuff",
|
|
5
|
+
method: "GET",
|
|
6
|
+
}, {});
|
|
7
|
+
function ignoredCheckRequestType() {
|
|
8
|
+
getStuff.getApiResource({
|
|
9
|
+
data: {
|
|
10
|
+
// @ts-expect-error Not matching request type
|
|
11
|
+
foo: "",
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
getStuff.getApiResource({
|
|
15
|
+
data: {
|
|
16
|
+
requestString: "",
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
function ignoredCheckResponseType() {
|
|
21
|
+
const stuff = getStuff
|
|
22
|
+
.getApiResource({
|
|
23
|
+
data: {
|
|
24
|
+
requestString: "",
|
|
25
|
+
},
|
|
26
|
+
})
|
|
27
|
+
.use();
|
|
28
|
+
// @ts-expect-error Accessing unknown prop
|
|
29
|
+
stuff.foo;
|
|
30
|
+
(function (ignored) {
|
|
31
|
+
// @ts-expect-error is a number
|
|
32
|
+
})(stuff.responseData);
|
|
33
|
+
(function (ignored) {
|
|
34
|
+
// is number
|
|
35
|
+
})(stuff.responseData);
|
|
36
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { beforeEach, expect, jest } from "@jest/globals";
|
|
2
|
+
import { ApiCallAsyncResourceFactory } from "./ApiCallAsyncResourceFactory.js";
|
|
3
|
+
import { refresh } from "@mittwald/react-use-promise";
|
|
4
|
+
beforeEach(() => {
|
|
5
|
+
refresh();
|
|
6
|
+
jest.resetAllMocks();
|
|
7
|
+
});
|
|
8
|
+
const requestMock = jest.fn();
|
|
9
|
+
const getStuff = new ApiCallAsyncResourceFactory({
|
|
10
|
+
operationId: "getStuff",
|
|
11
|
+
path: "/stuff",
|
|
12
|
+
method: "GET",
|
|
13
|
+
}, requestMock);
|
|
14
|
+
const testRequest1 = {
|
|
15
|
+
data: {
|
|
16
|
+
foo: "bar",
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
const testRequest2 = {
|
|
20
|
+
data: {
|
|
21
|
+
foo: "baz",
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
test("Resource loader executes request", async () => {
|
|
25
|
+
await getStuff.getApiResource(testRequest1).load();
|
|
26
|
+
expect(requestMock).toHaveBeenCalledTimes(1);
|
|
27
|
+
const firstRequestParams = requestMock.mock.calls[0][0];
|
|
28
|
+
expect(firstRequestParams).toMatchObject(testRequest1);
|
|
29
|
+
});
|
|
30
|
+
test("Resource is cached under URL", async () => {
|
|
31
|
+
await getStuff.getApiResource(testRequest1).load();
|
|
32
|
+
expect(requestMock).toHaveBeenCalledTimes(1);
|
|
33
|
+
await getStuff.getApiResource(testRequest1).load();
|
|
34
|
+
expect(requestMock).toHaveBeenCalledTimes(1);
|
|
35
|
+
refresh({
|
|
36
|
+
tag: "@mittwald/api-client/stuff",
|
|
37
|
+
});
|
|
38
|
+
await getStuff.getApiResource(testRequest1).load();
|
|
39
|
+
expect(requestMock).toHaveBeenCalledTimes(2);
|
|
40
|
+
});
|
|
41
|
+
test("Resources are different when request object changes", async () => {
|
|
42
|
+
await getStuff.getApiResource(testRequest1).load();
|
|
43
|
+
expect(requestMock).toHaveBeenCalledTimes(1);
|
|
44
|
+
await getStuff.getApiResource(testRequest2).load();
|
|
45
|
+
expect(requestMock).toHaveBeenCalledTimes(2);
|
|
46
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./ApiCallAsyncResourceFactory.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
function ignoredTestEmptyRequestTypes() {
|
|
2
|
+
const f = {};
|
|
3
|
+
void f();
|
|
4
|
+
void f({
|
|
5
|
+
headers: {},
|
|
6
|
+
});
|
|
7
|
+
void f({
|
|
8
|
+
headers: { extra: true },
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
function ignoredTestOptionalHeadersRequestTypes() {
|
|
12
|
+
const f = {};
|
|
13
|
+
void f();
|
|
14
|
+
void f({
|
|
15
|
+
headers: {},
|
|
16
|
+
});
|
|
17
|
+
void f({
|
|
18
|
+
headers: { extra: true },
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function ignoredTestPathParametersAreInRootOfRequestConfig() {
|
|
22
|
+
const f = {};
|
|
23
|
+
void f({
|
|
24
|
+
foo: "",
|
|
25
|
+
});
|
|
26
|
+
// @ts-expect-error Missing parameter
|
|
27
|
+
void f({});
|
|
28
|
+
}
|
|
29
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { expectAssignable } from "tsd";
|
|
2
|
+
function ignoredTestEmptyRequestTypes() {
|
|
3
|
+
expectAssignable({});
|
|
4
|
+
// @ts-expect-error Not assignable
|
|
5
|
+
expectAssignable({ extra: true });
|
|
6
|
+
// @ts-expect-error Not assignable
|
|
7
|
+
expectAssignable({ data: {} });
|
|
8
|
+
// @ts-expect-error Not assignable
|
|
9
|
+
expectAssignable({ data: null });
|
|
10
|
+
// @ts-expect-error Not assignable
|
|
11
|
+
expectAssignable({ pathParameters: {} });
|
|
12
|
+
}
|
|
13
|
+
function ignoredTestRequestTypesWithDataType() {
|
|
14
|
+
expectAssignable({ data: { foo: "" } });
|
|
15
|
+
// @ts-expect-error Not assignable
|
|
16
|
+
expectAssignable({});
|
|
17
|
+
expectAssignable({
|
|
18
|
+
// @ts-expect-error Not assignable
|
|
19
|
+
data: { foo: "", extra: "" },
|
|
20
|
+
});
|
|
21
|
+
// @ts-expect-error Not assignable
|
|
22
|
+
expectAssignable({ data: { noFoo: "" } });
|
|
23
|
+
}
|
|
24
|
+
function ignoredTestRequestTypesWithPathParameters() {
|
|
25
|
+
expectAssignable({
|
|
26
|
+
data: { foo: "" },
|
|
27
|
+
pathParameters: { bar: "" },
|
|
28
|
+
});
|
|
29
|
+
expectAssignable({
|
|
30
|
+
pathParameters: { bar: "" },
|
|
31
|
+
});
|
|
32
|
+
// @ts-expect-error Not assignable
|
|
33
|
+
expectAssignable({});
|
|
34
|
+
expectAssignable({
|
|
35
|
+
// @ts-expect-error Not assignable
|
|
36
|
+
pathParameters: {},
|
|
37
|
+
});
|
|
38
|
+
expectAssignable({
|
|
39
|
+
// @ts-expect-error Not assignable
|
|
40
|
+
pathParameters: { foo: "", extra: "" },
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function ignoredTestRequestTypesWithHeader() {
|
|
44
|
+
expectAssignable({
|
|
45
|
+
data: {
|
|
46
|
+
foo: "",
|
|
47
|
+
},
|
|
48
|
+
pathParameters: { bar: "" },
|
|
49
|
+
headers: { baz: "" },
|
|
50
|
+
});
|
|
51
|
+
expectAssignable({
|
|
52
|
+
pathParameters: { bar: "" },
|
|
53
|
+
headers: { baz: "" },
|
|
54
|
+
});
|
|
55
|
+
expectAssignable({
|
|
56
|
+
headers: { baz: "" },
|
|
57
|
+
});
|
|
58
|
+
// @ts-expect-error Not assignable
|
|
59
|
+
expectAssignable({});
|
|
60
|
+
expectAssignable({
|
|
61
|
+
headers: {
|
|
62
|
+
// @ts-expect-error Not assignable
|
|
63
|
+
baz: 42,
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
expectAssignable({
|
|
67
|
+
// @ts-expect-error Not assignable
|
|
68
|
+
headers: {},
|
|
69
|
+
});
|
|
70
|
+
expectAssignable({
|
|
71
|
+
// @ts-expect-error Not assignable
|
|
72
|
+
data: {},
|
|
73
|
+
headers: {
|
|
74
|
+
baz: "",
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
expectAssignable({
|
|
78
|
+
// @ts-expect-error Not assignable
|
|
79
|
+
pathParameters: {},
|
|
80
|
+
headers: {
|
|
81
|
+
baz: "",
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function ignoredTestRequestTypesWithQuery() {
|
|
86
|
+
expectAssignable({
|
|
87
|
+
data: {
|
|
88
|
+
foo: "",
|
|
89
|
+
},
|
|
90
|
+
pathParameters: { bar: "" },
|
|
91
|
+
headers: { baz: "" },
|
|
92
|
+
queryParameters: {
|
|
93
|
+
whut: "",
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
expectAssignable({
|
|
97
|
+
pathParameters: { bar: "" },
|
|
98
|
+
headers: { baz: "" },
|
|
99
|
+
queryParameters: {
|
|
100
|
+
whut: "",
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
expectAssignable({
|
|
104
|
+
queryParameters: {
|
|
105
|
+
whut: "",
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
// @ts-expect-error Not assignable
|
|
109
|
+
expectAssignable({});
|
|
110
|
+
expectAssignable({
|
|
111
|
+
queryParameters: {
|
|
112
|
+
// @ts-expect-error Not assignable
|
|
113
|
+
whut: 42,
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
expectAssignable({
|
|
117
|
+
// @ts-expect-error Not assignable
|
|
118
|
+
queryParameters: {},
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
function ignoredTestAdditionalHeadersCanAlwaysBeSet() {
|
|
122
|
+
expectAssignable({
|
|
123
|
+
headers: { extra: true },
|
|
124
|
+
});
|
|
125
|
+
expectAssignable({
|
|
126
|
+
headers: { extra: true },
|
|
127
|
+
});
|
|
128
|
+
expectAssignable({
|
|
129
|
+
headers: { extra: true },
|
|
130
|
+
});
|
|
131
|
+
expectAssignable({
|
|
132
|
+
data: {
|
|
133
|
+
foo: "",
|
|
134
|
+
},
|
|
135
|
+
headers: { extra: true },
|
|
136
|
+
});
|
|
137
|
+
expectAssignable({
|
|
138
|
+
pathParameters: {
|
|
139
|
+
bar: "",
|
|
140
|
+
},
|
|
141
|
+
headers: { extra: true },
|
|
142
|
+
});
|
|
143
|
+
expectAssignable({
|
|
144
|
+
headers: { extra: true, baz: "" },
|
|
145
|
+
});
|
|
146
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { expectAssignable, expectNotAssignable, expectType } from "tsd";
|
|
2
|
+
const additionalAxiosResponseData = {
|
|
3
|
+
statusText: "",
|
|
4
|
+
headers: {},
|
|
5
|
+
config: {},
|
|
6
|
+
mediaType: "application/json",
|
|
7
|
+
};
|
|
8
|
+
expectAssignable({
|
|
9
|
+
data: { a: "" },
|
|
10
|
+
status: 200,
|
|
11
|
+
...additionalAxiosResponseData,
|
|
12
|
+
});
|
|
13
|
+
expectNotAssignable({
|
|
14
|
+
data: { a: "", extra: "!" },
|
|
15
|
+
status: 200,
|
|
16
|
+
...additionalAxiosResponseData,
|
|
17
|
+
});
|
|
18
|
+
expectAssignable({
|
|
19
|
+
data: {
|
|
20
|
+
b: "",
|
|
21
|
+
},
|
|
22
|
+
status: 201,
|
|
23
|
+
...additionalAxiosResponseData,
|
|
24
|
+
});
|
|
25
|
+
expectAssignable({
|
|
26
|
+
data: null,
|
|
27
|
+
status: 400,
|
|
28
|
+
...additionalAxiosResponseData,
|
|
29
|
+
});
|
|
30
|
+
expectNotAssignable({
|
|
31
|
+
data: null,
|
|
32
|
+
status: 42,
|
|
33
|
+
...additionalAxiosResponseData,
|
|
34
|
+
});
|
|
35
|
+
expectNotAssignable({
|
|
36
|
+
data: null,
|
|
37
|
+
status: 42,
|
|
38
|
+
extra: "!",
|
|
39
|
+
...additionalAxiosResponseData,
|
|
40
|
+
});
|
|
41
|
+
expectNotAssignable({
|
|
42
|
+
data: { extraContent: "" },
|
|
43
|
+
status: 400,
|
|
44
|
+
...additionalAxiosResponseData,
|
|
45
|
+
});
|
|
46
|
+
function ignoredTestRequestTypesWithDataPathParameters() {
|
|
47
|
+
const someResponse = {};
|
|
48
|
+
expectType(someResponse.status);
|
|
49
|
+
if (someResponse.status === 200) {
|
|
50
|
+
// @ts-expect-error > a is not in data
|
|
51
|
+
someResponse.data.a;
|
|
52
|
+
// @ts-expect-error > b is not in data
|
|
53
|
+
someResponse.data.b;
|
|
54
|
+
if (someResponse.mediaType === "text/plain") {
|
|
55
|
+
// @ts-expect-error > a is not in data
|
|
56
|
+
someResponse.data.a;
|
|
57
|
+
expectType(someResponse.data.text);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
// @ts-expect-error > text is not in data
|
|
61
|
+
someResponse.data.text;
|
|
62
|
+
expectType(someResponse.data.a);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else if (someResponse.status === 201) {
|
|
66
|
+
expectType(someResponse.data.b);
|
|
67
|
+
// @ts-expect-error > a is not in data
|
|
68
|
+
someResponse.data.a;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import ApiClientError from "../core/ApiClientError.js";
|
|
2
|
+
export function assertStatus(response, expectedStatus) {
|
|
3
|
+
if (response.status !== expectedStatus) {
|
|
4
|
+
throw ApiClientError.fromResponse(`Unexpected response status (expected ${expectedStatus}, got: ${response.status})`, response);
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
export default assertStatus;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { expectAssignable } from "tsd";
|
|
2
|
+
import assertStatus from "./assertStatus.js";
|
|
3
|
+
function ignoredTestAssertStatusAssertsAlsoTheCorrectResponseType() {
|
|
4
|
+
assertStatus(someResponse, 200);
|
|
5
|
+
expectAssignable(someResponse);
|
|
6
|
+
// @ts-expect-error Not assignable
|
|
7
|
+
expectAssignable(someResponse);
|
|
8
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "axios";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AxiosInstance, CreateAxiosDefaults } from "axios";
|
|
2
|
+
import { RequestFunction } from "../types/index.js";
|
|
3
|
+
import { OpenAPIOperation } from "../types/index.js";
|
|
4
|
+
export declare abstract class ApiClientBase {
|
|
5
|
+
axios: AxiosInstance;
|
|
6
|
+
constructor(axiosConfig?: AxiosInstance | CreateAxiosDefaults);
|
|
7
|
+
protected requestFunctionFactory<TOp extends OpenAPIOperation>(operation: TOp): RequestFunction<TOp>;
|
|
8
|
+
}
|
|
9
|
+
export default ApiClientBase;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from "axios";
|
|
2
|
+
import { AnyResponse } from "../types/Response.js";
|
|
3
|
+
export declare class ApiClientError<T = unknown, D = unknown> extends AxiosError<T, D> {
|
|
4
|
+
constructor(message?: string, code?: string, config?: InternalAxiosRequestConfig<D>, request?: unknown, response?: AxiosResponse<T, D>);
|
|
5
|
+
static fromResponse(message: string, response: AnyResponse): ApiClientError;
|
|
6
|
+
}
|
|
7
|
+
export default ApiClientError;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { PathParameters } from "../types/http.js";
|
|
2
|
+
export declare class OpenAPIPath {
|
|
3
|
+
private readonly rawPath;
|
|
4
|
+
private readonly params?;
|
|
5
|
+
constructor(rawPath: string, params?: PathParameters);
|
|
6
|
+
buildUrl(): string;
|
|
7
|
+
private static setPathParams;
|
|
8
|
+
}
|
|
9
|
+
export default OpenAPIPath;
|