api-def 0.5.0-alpha1 → 0.6.0-alpha2
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 +11 -1
- package/cjs/ApiUtils.d.ts +2 -0
- package/cjs/ApiUtils.js +10 -1
- package/cjs/RequestError.d.ts +5 -4
- package/cjs/RequestError.js +5 -4
- package/cjs/Requester.js +3 -3
- package/cjs/backend/AxiosRequestBackend.d.ts +3 -2
- package/cjs/backend/AxiosRequestBackend.js +13 -0
- package/cjs/backend/FetchRequestBackend.d.ts +1 -2
- package/cjs/backend/FetchRequestBackend.js +18 -10
- package/cjs/backend/MockRequestBackend.d.ts +1 -0
- package/cjs/backend/MockRequestBackend.js +4 -3
- package/cjs/backend/RequestBackend.d.ts +1 -0
- package/esm/ApiUtils.d.ts +2 -0
- package/esm/ApiUtils.js +8 -0
- package/esm/RequestError.d.ts +5 -4
- package/esm/RequestError.js +5 -4
- package/esm/Requester.js +3 -3
- package/esm/backend/AxiosRequestBackend.d.ts +3 -2
- package/esm/backend/AxiosRequestBackend.js +13 -0
- package/esm/backend/FetchRequestBackend.d.ts +1 -2
- package/esm/backend/FetchRequestBackend.js +18 -10
- package/esm/backend/MockRequestBackend.d.ts +1 -0
- package/esm/backend/MockRequestBackend.js +4 -3
- package/esm/backend/RequestBackend.d.ts +1 -0
- package/package.json +1 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
# 0.6.0
|
|
2
|
+
|
|
3
|
+
## Breaking Changes
|
|
4
|
+
|
|
5
|
+
- axios will enforce ResponseType
|
|
6
|
+
|
|
7
|
+
### Fixes
|
|
8
|
+
|
|
9
|
+
- absolute paths as `baseUrl` is now supported in fetch backend
|
|
10
|
+
|
|
1
11
|
# 0.5.0
|
|
2
12
|
|
|
3
13
|
## Breaking Changes
|
|
@@ -7,8 +17,8 @@
|
|
|
7
17
|
## Changes
|
|
8
18
|
|
|
9
19
|
- Add mocking!
|
|
20
|
+
- Restructured mocking so that mocks are defined on the endpoint level (documentation updated)
|
|
10
21
|
- Add `acceptableStatus` to specify which status codes are considered successful
|
|
11
|
-
- Restructured mocking so that mocks are defined on the endpoint level (documentation updated)
|
|
12
22
|
- Extend retry logic to use exponential back-off, rather than retrying immediately
|
|
13
23
|
- Support for additional hot-request methods:
|
|
14
24
|
- PUT, DELETE
|
package/cjs/ApiUtils.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { AcceptableStatus, ApiResponse, CancelledRequestError } from "./ApiTypes";
|
|
2
|
+
import { ResponseType } from "./ApiConstants";
|
|
2
3
|
export declare const isCancelledError: (error: Error) => error is CancelledRequestError;
|
|
3
4
|
export declare const isNetworkError: (error: Error) => boolean;
|
|
4
5
|
export declare const parseResponseDataToObject: (response: ApiResponse) => void;
|
|
5
6
|
export declare const isAcceptableStatus: (status: number, acceptableStatus?: AcceptableStatus[] | undefined) => boolean;
|
|
7
|
+
export declare const inferResponseType: (contentType: string | null | undefined) => ResponseType;
|
package/cjs/ApiUtils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isAcceptableStatus = exports.parseResponseDataToObject = exports.isNetworkError = exports.isCancelledError = void 0;
|
|
3
|
+
exports.inferResponseType = exports.isAcceptableStatus = exports.parseResponseDataToObject = exports.isNetworkError = exports.isCancelledError = void 0;
|
|
4
4
|
var TextDecoding_1 = require("./TextDecoding");
|
|
5
5
|
var isCancelledError = function (error) {
|
|
6
6
|
return "isCancelledRequest" in error;
|
|
@@ -49,3 +49,12 @@ var isAcceptableStatus = function (status, acceptableStatus) {
|
|
|
49
49
|
return (false);
|
|
50
50
|
};
|
|
51
51
|
exports.isAcceptableStatus = isAcceptableStatus;
|
|
52
|
+
var JSON_CONTENT_TYPES = ["text/json", "application/json"];
|
|
53
|
+
var inferResponseType = function (contentType) {
|
|
54
|
+
var contentTypePart = contentType === null || contentType === void 0 ? void 0 : contentType.split(";")[0].trim();
|
|
55
|
+
if (contentTypePart && JSON_CONTENT_TYPES.includes(contentTypePart)) {
|
|
56
|
+
return "json";
|
|
57
|
+
}
|
|
58
|
+
return "text";
|
|
59
|
+
};
|
|
60
|
+
exports.inferResponseType = inferResponseType;
|
package/cjs/RequestError.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { ApiResponse } from "./ApiTypes";
|
|
2
2
|
import { EnumOf } from "./Utils";
|
|
3
3
|
export declare const RequestErrorCode: {
|
|
4
|
-
readonly
|
|
5
|
-
readonly
|
|
6
|
-
readonly
|
|
7
|
-
readonly
|
|
4
|
+
readonly MISC_UNKNOWN_ERROR: "misc/unknown-error";
|
|
5
|
+
readonly REQUEST_NETWORK_ERROR: "request/network-error";
|
|
6
|
+
readonly REQUEST_INVALID_STATUS: "request/invalid-status";
|
|
7
|
+
readonly REQUEST_INVALID_CONFIG: "request/invalid-config";
|
|
8
|
+
readonly REQUEST_MISMATCH_RESPONSE_TYPE: "request/mismatch-response-type";
|
|
8
9
|
};
|
|
9
10
|
export declare type RequestErrorCode = EnumOf<typeof RequestErrorCode>;
|
|
10
11
|
export interface RequestError extends Error {
|
package/cjs/RequestError.js
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.convertToRequestError = exports.isRequestError = exports.RequestErrorCode = void 0;
|
|
4
4
|
exports.RequestErrorCode = {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
MISC_UNKNOWN_ERROR: "misc/unknown-error",
|
|
6
|
+
REQUEST_NETWORK_ERROR: "request/network-error",
|
|
7
|
+
REQUEST_INVALID_STATUS: "request/invalid-status",
|
|
8
|
+
REQUEST_INVALID_CONFIG: "request/invalid-config",
|
|
9
|
+
REQUEST_MISMATCH_RESPONSE_TYPE: "request/mismatch-response-type",
|
|
9
10
|
};
|
|
10
11
|
var isRequestError = function (error) {
|
|
11
12
|
return "isRequestError" in error;
|
package/cjs/Requester.js
CHANGED
|
@@ -162,7 +162,7 @@ var makeRequest = function (context) { return __awaiter(void 0, void 0, void 0,
|
|
|
162
162
|
throw RequestError_1.convertToRequestError({
|
|
163
163
|
error: new Error("[api-def] Invalid response status code '" + parsedResponse.status + "'"),
|
|
164
164
|
response: parsedResponse,
|
|
165
|
-
code: RequestError_1.RequestErrorCode.
|
|
165
|
+
code: RequestError_1.RequestErrorCode.REQUEST_INVALID_STATUS,
|
|
166
166
|
});
|
|
167
167
|
}
|
|
168
168
|
context.response = parsedResponse;
|
|
@@ -251,10 +251,10 @@ var parseError = function (context, rawError) { return __awaiter(void 0, void 0,
|
|
|
251
251
|
errorResponse = _a.sent();
|
|
252
252
|
_a.label = 4;
|
|
253
253
|
case 4:
|
|
254
|
-
code = ApiUtils_1.isNetworkError(rawError) ? RequestError_1.RequestErrorCode.
|
|
254
|
+
code = ApiUtils_1.isNetworkError(rawError) ? RequestError_1.RequestErrorCode.REQUEST_NETWORK_ERROR : RequestError_1.RequestErrorCode.MISC_UNKNOWN_ERROR;
|
|
255
255
|
if (errorResponse) {
|
|
256
256
|
if (!ApiUtils_1.isAcceptableStatus(errorResponse.status, context.computedConfig.acceptableStatus)) {
|
|
257
|
-
code = RequestError_1.RequestErrorCode.
|
|
257
|
+
code = RequestError_1.RequestErrorCode.REQUEST_INVALID_STATUS;
|
|
258
258
|
}
|
|
259
259
|
}
|
|
260
260
|
errorInfo = context.backend.getErrorInfo(rawError, errorResponse);
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import RequestBackend, { RequestBackendErrorInfo, RequestOperation } from "./RequestBackend";
|
|
2
2
|
import { ApiResponse } from "../ApiTypes";
|
|
3
|
-
import type { AxiosError, AxiosResponse
|
|
3
|
+
import type { AxiosError, AxiosResponse } from "axios";
|
|
4
4
|
import RequestContext from "../RequestContext";
|
|
5
5
|
export declare const isAxiosError: (error: Error) => error is AxiosError<any>;
|
|
6
6
|
export default class AxiosRequestBackend implements RequestBackend<AxiosResponse> {
|
|
7
|
-
|
|
7
|
+
readonly id = "axios";
|
|
8
|
+
constructor(axiosLibrary: any);
|
|
8
9
|
extractResponseFromError(error: Error): Promise<AxiosResponse | null | undefined>;
|
|
9
10
|
convertResponse<T>(context: RequestContext, response: AxiosResponse): Promise<ApiResponse<T>>;
|
|
10
11
|
makeRequest(context: RequestContext): RequestOperation<AxiosResponse>;
|
|
@@ -37,13 +37,17 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.isAxiosError = void 0;
|
|
40
|
+
var ApiUtils_1 = require("../ApiUtils");
|
|
41
|
+
var RequestError_1 = require("../RequestError");
|
|
40
42
|
var axios;
|
|
41
43
|
var isAxiosError = function (error) {
|
|
42
44
|
return "isAxiosError" in error;
|
|
43
45
|
};
|
|
44
46
|
exports.isAxiosError = isAxiosError;
|
|
45
47
|
var AxiosRequestBackend = /** @class */ (function () {
|
|
48
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
46
49
|
function AxiosRequestBackend(axiosLibrary) {
|
|
50
|
+
this.id = "axios";
|
|
47
51
|
axios = axiosLibrary;
|
|
48
52
|
}
|
|
49
53
|
AxiosRequestBackend.prototype.extractResponseFromError = function (error) {
|
|
@@ -58,7 +62,16 @@ var AxiosRequestBackend = /** @class */ (function () {
|
|
|
58
62
|
};
|
|
59
63
|
AxiosRequestBackend.prototype.convertResponse = function (context, response) {
|
|
60
64
|
return __awaiter(this, void 0, void 0, function () {
|
|
65
|
+
var inferredResponseType;
|
|
61
66
|
return __generator(this, function (_a) {
|
|
67
|
+
inferredResponseType = ApiUtils_1.inferResponseType(response.headers["Content-Type"]);
|
|
68
|
+
// expand to array buffer once we support that in inferResponseType
|
|
69
|
+
if (inferredResponseType === "text" && context.responseType === "json") {
|
|
70
|
+
throw RequestError_1.convertToRequestError({
|
|
71
|
+
error: new Error("[api-def] Expected '" + context.responseType + "' response, got '" + inferredResponseType + "'"),
|
|
72
|
+
code: RequestError_1.RequestErrorCode.REQUEST_MISMATCH_RESPONSE_TYPE,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
62
75
|
return [2 /*return*/, response];
|
|
63
76
|
});
|
|
64
77
|
});
|
|
@@ -2,12 +2,11 @@ import RequestBackend, { RequestBackendErrorInfo, RequestOperation } from "./Req
|
|
|
2
2
|
import { ApiResponse } from "../ApiTypes";
|
|
3
3
|
import RequestContext from "../RequestContext";
|
|
4
4
|
import { Fetch } from "../Utils";
|
|
5
|
-
import { ResponseType } from "../ApiConstants";
|
|
6
5
|
export default class FetchRequestBackend implements RequestBackend<Response> {
|
|
7
6
|
fetch: (((input: RequestInfo, init?: RequestInit | undefined) => Promise<Response>) & typeof fetch) | undefined;
|
|
7
|
+
readonly id = "fetch";
|
|
8
8
|
constructor(fetchLibrary?: Fetch);
|
|
9
9
|
extractResponseFromError(error: Error): Promise<Response | null | undefined>;
|
|
10
|
-
inferResponseType(response: Response): ResponseType;
|
|
11
10
|
convertResponse<T>(context: RequestContext, response: Response & {
|
|
12
11
|
__text?: string;
|
|
13
12
|
}, error?: boolean): Promise<ApiResponse<T>>;
|
|
@@ -54,6 +54,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
54
54
|
var Utils = require("../Utils");
|
|
55
55
|
var Utils_1 = require("../Utils");
|
|
56
56
|
var ApiConstants_1 = require("../ApiConstants");
|
|
57
|
+
var ApiUtils_1 = require("../ApiUtils");
|
|
58
|
+
var RequestError_1 = require("../RequestError");
|
|
57
59
|
var FetchError = /** @class */ (function (_super) {
|
|
58
60
|
__extends(FetchError, _super);
|
|
59
61
|
function FetchError() {
|
|
@@ -64,6 +66,7 @@ var FetchError = /** @class */ (function (_super) {
|
|
|
64
66
|
var FetchRequestBackend = /** @class */ (function () {
|
|
65
67
|
function FetchRequestBackend(fetchLibrary) {
|
|
66
68
|
this.fetch = Utils_1.getGlobalFetch();
|
|
69
|
+
this.id = "fetch";
|
|
67
70
|
if (fetchLibrary !== undefined) {
|
|
68
71
|
this.fetch = fetchLibrary;
|
|
69
72
|
}
|
|
@@ -80,20 +83,21 @@ var FetchRequestBackend = /** @class */ (function () {
|
|
|
80
83
|
});
|
|
81
84
|
});
|
|
82
85
|
};
|
|
83
|
-
FetchRequestBackend.prototype.inferResponseType = function (response) {
|
|
84
|
-
var contentType = response.headers.get("Content-Type");
|
|
85
|
-
if (contentType === null || contentType === void 0 ? void 0 : contentType.startsWith("json")) {
|
|
86
|
-
return "json";
|
|
87
|
-
}
|
|
88
|
-
return "text";
|
|
89
|
-
};
|
|
90
86
|
FetchRequestBackend.prototype.convertResponse = function (context, response, error) {
|
|
91
87
|
return __awaiter(this, void 0, void 0, function () {
|
|
92
|
-
var data, responseType, _a, error_1, status;
|
|
88
|
+
var data, inferredResponseType, responseType, _a, error_1, status;
|
|
93
89
|
return __generator(this, function (_b) {
|
|
94
90
|
switch (_b.label) {
|
|
95
91
|
case 0:
|
|
96
|
-
|
|
92
|
+
inferredResponseType = ApiUtils_1.inferResponseType(response.headers.get("Content-Type"));
|
|
93
|
+
responseType = error ? inferredResponseType : context.responseType;
|
|
94
|
+
// expand to array buffer once we support that in inferResponseType
|
|
95
|
+
if (inferredResponseType === "text" && context.responseType === "json") {
|
|
96
|
+
throw RequestError_1.convertToRequestError({
|
|
97
|
+
error: new Error("[api-def] Expected '" + context.responseType + "' response, got '" + inferredResponseType + "'"),
|
|
98
|
+
code: RequestError_1.RequestErrorCode.REQUEST_MISMATCH_RESPONSE_TYPE,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
97
101
|
_b.label = 1;
|
|
98
102
|
case 1:
|
|
99
103
|
_b.trys.push([1, 8, , 9]);
|
|
@@ -147,7 +151,11 @@ var FetchRequestBackend = /** @class */ (function () {
|
|
|
147
151
|
path += context.computedPath.startsWith("/")
|
|
148
152
|
? context.computedPath.substring(1)
|
|
149
153
|
: context.computedPath;
|
|
150
|
-
var
|
|
154
|
+
var origin = undefined;
|
|
155
|
+
if (typeof window !== "undefined") {
|
|
156
|
+
origin = window.origin;
|
|
157
|
+
}
|
|
158
|
+
var url = new URL(path, origin);
|
|
151
159
|
if (computedConfig.query) {
|
|
152
160
|
var queryKeys = Object.keys(computedConfig.query);
|
|
153
161
|
for (var i = 0; i < queryKeys.length; i++) {
|
|
@@ -2,6 +2,7 @@ import RequestBackend, { RequestBackendErrorInfo, RequestOperation } from "./Req
|
|
|
2
2
|
import { ApiResponse } from "../ApiTypes";
|
|
3
3
|
import RequestContext from "../RequestContext";
|
|
4
4
|
export default class MockRequestBackend implements RequestBackend<ApiResponse> {
|
|
5
|
+
readonly id = "mock";
|
|
5
6
|
convertResponse<T>(context: RequestContext, response: ApiResponse, error?: boolean): Promise<ApiResponse<T>>;
|
|
6
7
|
extractResponseFromError(error: Error): Promise<ApiResponse | null | undefined>;
|
|
7
8
|
private runRequest;
|
|
@@ -41,6 +41,7 @@ var Utils_1 = require("../Utils");
|
|
|
41
41
|
var RequestError_1 = require("../RequestError");
|
|
42
42
|
var MockRequestBackend = /** @class */ (function () {
|
|
43
43
|
function MockRequestBackend() {
|
|
44
|
+
this.id = "mock";
|
|
44
45
|
}
|
|
45
46
|
MockRequestBackend.prototype.convertResponse = function (context, response, error) {
|
|
46
47
|
return __awaiter(this, void 0, void 0, function () {
|
|
@@ -72,7 +73,7 @@ var MockRequestBackend = /** @class */ (function () {
|
|
|
72
73
|
if (!mockingFunc) {
|
|
73
74
|
throw RequestError_1.convertToRequestError({
|
|
74
75
|
error: new Error("[api-def] Attempted to run mocked request without mocking function"),
|
|
75
|
-
code: RequestError_1.RequestErrorCode.
|
|
76
|
+
code: RequestError_1.RequestErrorCode.REQUEST_INVALID_CONFIG,
|
|
76
77
|
});
|
|
77
78
|
}
|
|
78
79
|
req = {
|
|
@@ -104,7 +105,7 @@ var MockRequestBackend = /** @class */ (function () {
|
|
|
104
105
|
if (min > max) {
|
|
105
106
|
throw RequestError_1.convertToRequestError({
|
|
106
107
|
error: new Error("[api-def] Min delay cannot be greater than max delay"),
|
|
107
|
-
code: RequestError_1.RequestErrorCode.
|
|
108
|
+
code: RequestError_1.RequestErrorCode.REQUEST_INVALID_CONFIG,
|
|
108
109
|
});
|
|
109
110
|
}
|
|
110
111
|
delayMs = Utils_1.randInt(min, max);
|
|
@@ -123,7 +124,7 @@ var MockRequestBackend = /** @class */ (function () {
|
|
|
123
124
|
if (res.response === undefined) {
|
|
124
125
|
throw RequestError_1.convertToRequestError({
|
|
125
126
|
error: new Error("[api-def] Mocked API did not respond"),
|
|
126
|
-
code: RequestError_1.RequestErrorCode.
|
|
127
|
+
code: RequestError_1.RequestErrorCode.REQUEST_INVALID_CONFIG,
|
|
127
128
|
});
|
|
128
129
|
}
|
|
129
130
|
return [2 /*return*/, {
|
|
@@ -8,6 +8,7 @@ export interface RequestBackendErrorInfo {
|
|
|
8
8
|
code: string;
|
|
9
9
|
}
|
|
10
10
|
export default interface RequestBackend<R = any> {
|
|
11
|
+
readonly id: string;
|
|
11
12
|
makeRequest(context: RequestContext): RequestOperation<R>;
|
|
12
13
|
convertResponse<T>(context: RequestContext, response: R, error?: boolean): Promise<ApiResponse<T>>;
|
|
13
14
|
extractResponseFromError(error: Error): Promise<R | null | undefined>;
|
package/esm/ApiUtils.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { AcceptableStatus, ApiResponse, CancelledRequestError } from "./ApiTypes";
|
|
2
|
+
import { ResponseType } from "./ApiConstants";
|
|
2
3
|
export declare const isCancelledError: (error: Error) => error is CancelledRequestError;
|
|
3
4
|
export declare const isNetworkError: (error: Error) => boolean;
|
|
4
5
|
export declare const parseResponseDataToObject: (response: ApiResponse) => void;
|
|
5
6
|
export declare const isAcceptableStatus: (status: number, acceptableStatus?: AcceptableStatus[] | undefined) => boolean;
|
|
7
|
+
export declare const inferResponseType: (contentType: string | null | undefined) => ResponseType;
|
package/esm/ApiUtils.js
CHANGED
|
@@ -42,3 +42,11 @@ export var isAcceptableStatus = function (status, acceptableStatus) {
|
|
|
42
42
|
}
|
|
43
43
|
return (false);
|
|
44
44
|
};
|
|
45
|
+
var JSON_CONTENT_TYPES = ["text/json", "application/json"];
|
|
46
|
+
export var inferResponseType = function (contentType) {
|
|
47
|
+
var contentTypePart = contentType === null || contentType === void 0 ? void 0 : contentType.split(";")[0].trim();
|
|
48
|
+
if (contentTypePart && JSON_CONTENT_TYPES.includes(contentTypePart)) {
|
|
49
|
+
return "json";
|
|
50
|
+
}
|
|
51
|
+
return "text";
|
|
52
|
+
};
|
package/esm/RequestError.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { ApiResponse } from "./ApiTypes";
|
|
2
2
|
import { EnumOf } from "./Utils";
|
|
3
3
|
export declare const RequestErrorCode: {
|
|
4
|
-
readonly
|
|
5
|
-
readonly
|
|
6
|
-
readonly
|
|
7
|
-
readonly
|
|
4
|
+
readonly MISC_UNKNOWN_ERROR: "misc/unknown-error";
|
|
5
|
+
readonly REQUEST_NETWORK_ERROR: "request/network-error";
|
|
6
|
+
readonly REQUEST_INVALID_STATUS: "request/invalid-status";
|
|
7
|
+
readonly REQUEST_INVALID_CONFIG: "request/invalid-config";
|
|
8
|
+
readonly REQUEST_MISMATCH_RESPONSE_TYPE: "request/mismatch-response-type";
|
|
8
9
|
};
|
|
9
10
|
export declare type RequestErrorCode = EnumOf<typeof RequestErrorCode>;
|
|
10
11
|
export interface RequestError extends Error {
|
package/esm/RequestError.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export var RequestErrorCode = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
MISC_UNKNOWN_ERROR: "misc/unknown-error",
|
|
3
|
+
REQUEST_NETWORK_ERROR: "request/network-error",
|
|
4
|
+
REQUEST_INVALID_STATUS: "request/invalid-status",
|
|
5
|
+
REQUEST_INVALID_CONFIG: "request/invalid-config",
|
|
6
|
+
REQUEST_MISMATCH_RESPONSE_TYPE: "request/mismatch-response-type",
|
|
6
7
|
};
|
|
7
8
|
export var isRequestError = function (error) {
|
|
8
9
|
return "isRequestError" in error;
|
package/esm/Requester.js
CHANGED
|
@@ -158,7 +158,7 @@ var makeRequest = function (context) { return __awaiter(void 0, void 0, void 0,
|
|
|
158
158
|
throw convertToRequestError({
|
|
159
159
|
error: new Error("[api-def] Invalid response status code '" + parsedResponse.status + "'"),
|
|
160
160
|
response: parsedResponse,
|
|
161
|
-
code: RequestErrorCode.
|
|
161
|
+
code: RequestErrorCode.REQUEST_INVALID_STATUS,
|
|
162
162
|
});
|
|
163
163
|
}
|
|
164
164
|
context.response = parsedResponse;
|
|
@@ -247,10 +247,10 @@ var parseError = function (context, rawError) { return __awaiter(void 0, void 0,
|
|
|
247
247
|
errorResponse = _a.sent();
|
|
248
248
|
_a.label = 4;
|
|
249
249
|
case 4:
|
|
250
|
-
code = isNetworkError(rawError) ? RequestErrorCode.
|
|
250
|
+
code = isNetworkError(rawError) ? RequestErrorCode.REQUEST_NETWORK_ERROR : RequestErrorCode.MISC_UNKNOWN_ERROR;
|
|
251
251
|
if (errorResponse) {
|
|
252
252
|
if (!isAcceptableStatus(errorResponse.status, context.computedConfig.acceptableStatus)) {
|
|
253
|
-
code = RequestErrorCode.
|
|
253
|
+
code = RequestErrorCode.REQUEST_INVALID_STATUS;
|
|
254
254
|
}
|
|
255
255
|
}
|
|
256
256
|
errorInfo = context.backend.getErrorInfo(rawError, errorResponse);
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import RequestBackend, { RequestBackendErrorInfo, RequestOperation } from "./RequestBackend";
|
|
2
2
|
import { ApiResponse } from "../ApiTypes";
|
|
3
|
-
import type { AxiosError, AxiosResponse
|
|
3
|
+
import type { AxiosError, AxiosResponse } from "axios";
|
|
4
4
|
import RequestContext from "../RequestContext";
|
|
5
5
|
export declare const isAxiosError: (error: Error) => error is AxiosError<any>;
|
|
6
6
|
export default class AxiosRequestBackend implements RequestBackend<AxiosResponse> {
|
|
7
|
-
|
|
7
|
+
readonly id = "axios";
|
|
8
|
+
constructor(axiosLibrary: any);
|
|
8
9
|
extractResponseFromError(error: Error): Promise<AxiosResponse | null | undefined>;
|
|
9
10
|
convertResponse<T>(context: RequestContext, response: AxiosResponse): Promise<ApiResponse<T>>;
|
|
10
11
|
makeRequest(context: RequestContext): RequestOperation<AxiosResponse>;
|
|
@@ -34,12 +34,16 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
34
34
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
35
35
|
}
|
|
36
36
|
};
|
|
37
|
+
import { inferResponseType } from "../ApiUtils";
|
|
38
|
+
import { convertToRequestError, RequestErrorCode } from "../RequestError";
|
|
37
39
|
var axios;
|
|
38
40
|
export var isAxiosError = function (error) {
|
|
39
41
|
return "isAxiosError" in error;
|
|
40
42
|
};
|
|
41
43
|
var AxiosRequestBackend = /** @class */ (function () {
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
42
45
|
function AxiosRequestBackend(axiosLibrary) {
|
|
46
|
+
this.id = "axios";
|
|
43
47
|
axios = axiosLibrary;
|
|
44
48
|
}
|
|
45
49
|
AxiosRequestBackend.prototype.extractResponseFromError = function (error) {
|
|
@@ -54,7 +58,16 @@ var AxiosRequestBackend = /** @class */ (function () {
|
|
|
54
58
|
};
|
|
55
59
|
AxiosRequestBackend.prototype.convertResponse = function (context, response) {
|
|
56
60
|
return __awaiter(this, void 0, void 0, function () {
|
|
61
|
+
var inferredResponseType;
|
|
57
62
|
return __generator(this, function (_a) {
|
|
63
|
+
inferredResponseType = inferResponseType(response.headers["Content-Type"]);
|
|
64
|
+
// expand to array buffer once we support that in inferResponseType
|
|
65
|
+
if (inferredResponseType === "text" && context.responseType === "json") {
|
|
66
|
+
throw convertToRequestError({
|
|
67
|
+
error: new Error("[api-def] Expected '" + context.responseType + "' response, got '" + inferredResponseType + "'"),
|
|
68
|
+
code: RequestErrorCode.REQUEST_MISMATCH_RESPONSE_TYPE,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
58
71
|
return [2 /*return*/, response];
|
|
59
72
|
});
|
|
60
73
|
});
|
|
@@ -2,12 +2,11 @@ import RequestBackend, { RequestBackendErrorInfo, RequestOperation } from "./Req
|
|
|
2
2
|
import { ApiResponse } from "../ApiTypes";
|
|
3
3
|
import RequestContext from "../RequestContext";
|
|
4
4
|
import { Fetch } from "../Utils";
|
|
5
|
-
import { ResponseType } from "../ApiConstants";
|
|
6
5
|
export default class FetchRequestBackend implements RequestBackend<Response> {
|
|
7
6
|
fetch: (((input: RequestInfo, init?: RequestInit | undefined) => Promise<Response>) & typeof fetch) | undefined;
|
|
7
|
+
readonly id = "fetch";
|
|
8
8
|
constructor(fetchLibrary?: Fetch);
|
|
9
9
|
extractResponseFromError(error: Error): Promise<Response | null | undefined>;
|
|
10
|
-
inferResponseType(response: Response): ResponseType;
|
|
11
10
|
convertResponse<T>(context: RequestContext, response: Response & {
|
|
12
11
|
__text?: string;
|
|
13
12
|
}, error?: boolean): Promise<ApiResponse<T>>;
|
|
@@ -52,6 +52,8 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
|
52
52
|
import * as Utils from "../Utils";
|
|
53
53
|
import { getGlobalFetch } from "../Utils";
|
|
54
54
|
import { ResponseType } from "../ApiConstants";
|
|
55
|
+
import { inferResponseType } from "../ApiUtils";
|
|
56
|
+
import { convertToRequestError, RequestErrorCode } from "../RequestError";
|
|
55
57
|
var FetchError = /** @class */ (function (_super) {
|
|
56
58
|
__extends(FetchError, _super);
|
|
57
59
|
function FetchError() {
|
|
@@ -62,6 +64,7 @@ var FetchError = /** @class */ (function (_super) {
|
|
|
62
64
|
var FetchRequestBackend = /** @class */ (function () {
|
|
63
65
|
function FetchRequestBackend(fetchLibrary) {
|
|
64
66
|
this.fetch = getGlobalFetch();
|
|
67
|
+
this.id = "fetch";
|
|
65
68
|
if (fetchLibrary !== undefined) {
|
|
66
69
|
this.fetch = fetchLibrary;
|
|
67
70
|
}
|
|
@@ -78,20 +81,21 @@ var FetchRequestBackend = /** @class */ (function () {
|
|
|
78
81
|
});
|
|
79
82
|
});
|
|
80
83
|
};
|
|
81
|
-
FetchRequestBackend.prototype.inferResponseType = function (response) {
|
|
82
|
-
var contentType = response.headers.get("Content-Type");
|
|
83
|
-
if (contentType === null || contentType === void 0 ? void 0 : contentType.startsWith("json")) {
|
|
84
|
-
return "json";
|
|
85
|
-
}
|
|
86
|
-
return "text";
|
|
87
|
-
};
|
|
88
84
|
FetchRequestBackend.prototype.convertResponse = function (context, response, error) {
|
|
89
85
|
return __awaiter(this, void 0, void 0, function () {
|
|
90
|
-
var data, responseType, _a, error_1, status;
|
|
86
|
+
var data, inferredResponseType, responseType, _a, error_1, status;
|
|
91
87
|
return __generator(this, function (_b) {
|
|
92
88
|
switch (_b.label) {
|
|
93
89
|
case 0:
|
|
94
|
-
|
|
90
|
+
inferredResponseType = inferResponseType(response.headers.get("Content-Type"));
|
|
91
|
+
responseType = error ? inferredResponseType : context.responseType;
|
|
92
|
+
// expand to array buffer once we support that in inferResponseType
|
|
93
|
+
if (inferredResponseType === "text" && context.responseType === "json") {
|
|
94
|
+
throw convertToRequestError({
|
|
95
|
+
error: new Error("[api-def] Expected '" + context.responseType + "' response, got '" + inferredResponseType + "'"),
|
|
96
|
+
code: RequestErrorCode.REQUEST_MISMATCH_RESPONSE_TYPE,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
95
99
|
_b.label = 1;
|
|
96
100
|
case 1:
|
|
97
101
|
_b.trys.push([1, 8, , 9]);
|
|
@@ -145,7 +149,11 @@ var FetchRequestBackend = /** @class */ (function () {
|
|
|
145
149
|
path += context.computedPath.startsWith("/")
|
|
146
150
|
? context.computedPath.substring(1)
|
|
147
151
|
: context.computedPath;
|
|
148
|
-
var
|
|
152
|
+
var origin = undefined;
|
|
153
|
+
if (typeof window !== "undefined") {
|
|
154
|
+
origin = window.origin;
|
|
155
|
+
}
|
|
156
|
+
var url = new URL(path, origin);
|
|
149
157
|
if (computedConfig.query) {
|
|
150
158
|
var queryKeys = Object.keys(computedConfig.query);
|
|
151
159
|
for (var i = 0; i < queryKeys.length; i++) {
|
|
@@ -2,6 +2,7 @@ import RequestBackend, { RequestBackendErrorInfo, RequestOperation } from "./Req
|
|
|
2
2
|
import { ApiResponse } from "../ApiTypes";
|
|
3
3
|
import RequestContext from "../RequestContext";
|
|
4
4
|
export default class MockRequestBackend implements RequestBackend<ApiResponse> {
|
|
5
|
+
readonly id = "mock";
|
|
5
6
|
convertResponse<T>(context: RequestContext, response: ApiResponse, error?: boolean): Promise<ApiResponse<T>>;
|
|
6
7
|
extractResponseFromError(error: Error): Promise<ApiResponse | null | undefined>;
|
|
7
8
|
private runRequest;
|
|
@@ -39,6 +39,7 @@ import { delayThenReturn, randInt } from "../Utils";
|
|
|
39
39
|
import { convertToRequestError, RequestErrorCode } from "../RequestError";
|
|
40
40
|
var MockRequestBackend = /** @class */ (function () {
|
|
41
41
|
function MockRequestBackend() {
|
|
42
|
+
this.id = "mock";
|
|
42
43
|
}
|
|
43
44
|
MockRequestBackend.prototype.convertResponse = function (context, response, error) {
|
|
44
45
|
return __awaiter(this, void 0, void 0, function () {
|
|
@@ -70,7 +71,7 @@ var MockRequestBackend = /** @class */ (function () {
|
|
|
70
71
|
if (!mockingFunc) {
|
|
71
72
|
throw convertToRequestError({
|
|
72
73
|
error: new Error("[api-def] Attempted to run mocked request without mocking function"),
|
|
73
|
-
code: RequestErrorCode.
|
|
74
|
+
code: RequestErrorCode.REQUEST_INVALID_CONFIG,
|
|
74
75
|
});
|
|
75
76
|
}
|
|
76
77
|
req = {
|
|
@@ -102,7 +103,7 @@ var MockRequestBackend = /** @class */ (function () {
|
|
|
102
103
|
if (min > max) {
|
|
103
104
|
throw convertToRequestError({
|
|
104
105
|
error: new Error("[api-def] Min delay cannot be greater than max delay"),
|
|
105
|
-
code: RequestErrorCode.
|
|
106
|
+
code: RequestErrorCode.REQUEST_INVALID_CONFIG,
|
|
106
107
|
});
|
|
107
108
|
}
|
|
108
109
|
delayMs = randInt(min, max);
|
|
@@ -121,7 +122,7 @@ var MockRequestBackend = /** @class */ (function () {
|
|
|
121
122
|
if (res.response === undefined) {
|
|
122
123
|
throw convertToRequestError({
|
|
123
124
|
error: new Error("[api-def] Mocked API did not respond"),
|
|
124
|
-
code: RequestErrorCode.
|
|
125
|
+
code: RequestErrorCode.REQUEST_INVALID_CONFIG,
|
|
125
126
|
});
|
|
126
127
|
}
|
|
127
128
|
return [2 /*return*/, {
|
|
@@ -8,6 +8,7 @@ export interface RequestBackendErrorInfo {
|
|
|
8
8
|
code: string;
|
|
9
9
|
}
|
|
10
10
|
export default interface RequestBackend<R = any> {
|
|
11
|
+
readonly id: string;
|
|
11
12
|
makeRequest(context: RequestContext): RequestOperation<R>;
|
|
12
13
|
convertResponse<T>(context: RequestContext, response: R, error?: boolean): Promise<ApiResponse<T>>;
|
|
13
14
|
extractResponseFromError(error: Error): Promise<R | null | undefined>;
|
package/package.json
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "api-def",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0-alpha2",
|
|
4
4
|
"description": "Typed API definitions with middleware support",
|
|
5
5
|
"main": "cjs/index.js",
|
|
6
6
|
"types": "esm/index.d.ts",
|
|
7
7
|
"module": "esm/index.js",
|
|
8
8
|
"sideEffects": false,
|
|
9
|
-
"type": "module",
|
|
10
9
|
"scripts": {
|
|
11
10
|
"test": "npm run test:types && npm run test:lint && npm run test:unit",
|
|
12
11
|
"test:unit": "cross-env NODE_ENV=test jest",
|