better swr mocks
This commit is contained in:
parent
45bbe7ba12
commit
b9c24772f5
@ -1,5 +1,7 @@
|
||||
export * from "./hooks/index.js";
|
||||
export * from "./utils/request.js";
|
||||
export * from "./utils/http-impl.browser.js";
|
||||
export * from "./utils/http-impl.sw.js";
|
||||
export * from "./utils/observable.js";
|
||||
export * from "./context/index.js";
|
||||
export * from "./components/index.js";
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import { Logger } from "@gnu-taler/taler-util";
|
||||
import { deprecate } from "util";
|
||||
|
||||
type HttpMethod =
|
||||
| "get"
|
||||
@ -63,6 +64,11 @@ type TestValues = {
|
||||
|
||||
const logger = new Logger("testing/mock.ts");
|
||||
|
||||
type MockedResponse = {
|
||||
queryMade: ExpectationValues;
|
||||
expectedQuery?: ExpectationValues;
|
||||
};
|
||||
|
||||
export abstract class MockEnvironment {
|
||||
expectations: Array<ExpectationValues> = [];
|
||||
queriesMade: Array<ExpectationValues> = [];
|
||||
@ -108,7 +114,7 @@ export abstract class MockEnvironment {
|
||||
qparam?: any;
|
||||
response?: ResponseType;
|
||||
},
|
||||
): { status: number; payload: ResponseType } | undefined {
|
||||
): MockedResponse {
|
||||
const queryMade = { query, params, auth: params.auth };
|
||||
this.queriesMade.push(queryMade);
|
||||
const expectedQuery = this.expectations[this.index];
|
||||
@ -116,11 +122,9 @@ export abstract class MockEnvironment {
|
||||
if (this.debug) {
|
||||
logger.info("unexpected query made", queryMade);
|
||||
}
|
||||
return undefined;
|
||||
return { queryMade };
|
||||
}
|
||||
const responseCode = this.expectations[this.index].query.code ?? 200;
|
||||
const mockedResponse = this.expectations[this.index].params
|
||||
?.response as ResponseType;
|
||||
|
||||
if (this.debug) {
|
||||
logger.info("tracking query made", {
|
||||
queryMade,
|
||||
@ -128,7 +132,7 @@ export abstract class MockEnvironment {
|
||||
});
|
||||
}
|
||||
this.index++;
|
||||
return { status: responseCode, payload: mockedResponse };
|
||||
return { queryMade, expectedQuery };
|
||||
}
|
||||
|
||||
public assertJustExpectedRequestWereMade(): AssertStatus {
|
||||
|
@ -17,12 +17,17 @@
|
||||
import { ComponentChildren, FunctionalComponent, h, VNode } from "preact";
|
||||
import { MockEnvironment } from "./mock.js";
|
||||
import { SWRConfig } from "swr";
|
||||
import * as swr__internal from "swr/_internal";
|
||||
import { Logger } from "@gnu-taler/taler-util";
|
||||
import { buildRequestFailed, RequestError } from "../index.browser.js";
|
||||
|
||||
const logger = new Logger("tests/swr.ts");
|
||||
|
||||
/**
|
||||
* Helper for hook that use SWR inside.
|
||||
*
|
||||
*
|
||||
* buildTestingContext() will return a testing context
|
||||
*
|
||||
*
|
||||
*/
|
||||
export class SwrMockEnvironment extends MockEnvironment {
|
||||
constructor(debug = false) {
|
||||
@ -32,47 +37,68 @@ export class SwrMockEnvironment extends MockEnvironment {
|
||||
public buildTestingContext(): FunctionalComponent<{
|
||||
children: ComponentChildren;
|
||||
}> {
|
||||
const __SAVE_REQUEST_AND_GET_MOCKED_RESPONSE = this.saveRequestAndGetMockedResponse.bind(this);
|
||||
const __SAVE_REQUEST_AND_GET_MOCKED_RESPONSE =
|
||||
this.saveRequestAndGetMockedResponse.bind(this);
|
||||
|
||||
function testingFetcher(params: any): any {
|
||||
const url = JSON.stringify(params);
|
||||
const mocked = __SAVE_REQUEST_AND_GET_MOCKED_RESPONSE<any, any>(
|
||||
{
|
||||
method: "get",
|
||||
url,
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
//unexpected query
|
||||
if (!mocked.expectedQuery) return undefined;
|
||||
const status = mocked.expectedQuery.query.code ?? 200;
|
||||
const requestPayload = mocked.expectedQuery.params?.request;
|
||||
const responsePayload = mocked.expectedQuery.params?.response;
|
||||
//simulated error
|
||||
if (status >= 400) {
|
||||
const error = buildRequestFailed(
|
||||
url,
|
||||
JSON.stringify(responsePayload),
|
||||
status,
|
||||
requestPayload,
|
||||
);
|
||||
//example error handling from https://swr.vercel.app/docs/error-handling
|
||||
throw new RequestError(error);
|
||||
}
|
||||
return responsePayload;
|
||||
}
|
||||
|
||||
const value: Partial<swr__internal.PublicConfiguration> & {
|
||||
provider: () => Map<any, any>;
|
||||
} = {
|
||||
use: [
|
||||
(useSWRNext) => {
|
||||
return (key, fetcher, config) => {
|
||||
//prevent the request
|
||||
//use the testing fetcher instead
|
||||
return useSWRNext(key, testingFetcher, config);
|
||||
};
|
||||
},
|
||||
],
|
||||
fetcher: testingFetcher,
|
||||
//These options are set for ending the test faster
|
||||
//otherwise SWR will create timeouts that will live after the test finished
|
||||
loadingTimeout: 0,
|
||||
dedupingInterval: 0,
|
||||
shouldRetryOnError: false,
|
||||
errorRetryInterval: 0,
|
||||
errorRetryCount: 0,
|
||||
//clean cache for every test
|
||||
provider: () => new Map(),
|
||||
};
|
||||
|
||||
return function TestingContext({
|
||||
children,
|
||||
}: {
|
||||
children: ComponentChildren;
|
||||
}): VNode {
|
||||
return h(
|
||||
SWRConfig,
|
||||
{
|
||||
value: {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
fetcher: (url: string, options: object) => {
|
||||
const mocked = __SAVE_REQUEST_AND_GET_MOCKED_RESPONSE(
|
||||
{
|
||||
method: "get",
|
||||
url,
|
||||
},
|
||||
{},
|
||||
);
|
||||
if (!mocked) return undefined;
|
||||
if (mocked.status > 400) {
|
||||
const e: any = Error("simulated error for testing");
|
||||
//example error handling from https://swr.vercel.app/docs/error-handling
|
||||
e.status = mocked.status;
|
||||
throw e;
|
||||
}
|
||||
return mocked.payload;
|
||||
},
|
||||
//These options are set for ending the test faster
|
||||
//otherwise SWR will create timeouts that will live after the test finished
|
||||
loadingTimeout: 0,
|
||||
dedupingInterval: 0,
|
||||
shouldRetryOnError: false,
|
||||
errorRetryInterval: 0,
|
||||
errorRetryCount: 0,
|
||||
//clean cache for every test
|
||||
provider: () => new Map(),
|
||||
},
|
||||
},
|
||||
children,
|
||||
);
|
||||
return h(SWRConfig, { value }, children);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
203
packages/web-util/src/utils/http-impl.browser.ts
Normal file
203
packages/web-util/src/utils/http-impl.browser.ts
Normal file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2022 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Imports.
|
||||
*/
|
||||
import {
|
||||
Logger,
|
||||
RequestThrottler,
|
||||
TalerErrorCode,
|
||||
TalerError,
|
||||
} from "@gnu-taler/taler-util";
|
||||
|
||||
import {
|
||||
HttpRequestLibrary,
|
||||
HttpRequestOptions,
|
||||
HttpResponse,
|
||||
Headers,
|
||||
} from "@gnu-taler/taler-util/http";
|
||||
|
||||
const logger = new Logger("browserHttpLib");
|
||||
|
||||
/**
|
||||
* An implementation of the [[HttpRequestLibrary]] using the
|
||||
* browser's XMLHttpRequest.
|
||||
*/
|
||||
export class BrowserHttpLib implements HttpRequestLibrary {
|
||||
private throttle = new RequestThrottler();
|
||||
private throttlingEnabled = true;
|
||||
|
||||
fetch(
|
||||
requestUrl: string,
|
||||
options?: HttpRequestOptions,
|
||||
): Promise<HttpResponse> {
|
||||
const requestMethod = options?.method ?? "GET";
|
||||
const requestBody = options?.body;
|
||||
|
||||
if (this.throttlingEnabled && this.throttle.applyThrottle(requestUrl)) {
|
||||
const parsedUrl = new URL(requestUrl);
|
||||
throw TalerError.fromDetail(
|
||||
TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED,
|
||||
{
|
||||
requestMethod,
|
||||
requestUrl,
|
||||
throttleStats: this.throttle.getThrottleStats(requestUrl),
|
||||
},
|
||||
`request to origin ${parsedUrl.origin} was throttled`,
|
||||
);
|
||||
}
|
||||
|
||||
return new Promise<HttpResponse>((resolve, reject) => {
|
||||
const myRequest = new XMLHttpRequest();
|
||||
myRequest.open(requestMethod, requestUrl);
|
||||
if (options?.headers) {
|
||||
for (const headerName in options.headers) {
|
||||
myRequest.setRequestHeader(headerName, options.headers[headerName]);
|
||||
}
|
||||
}
|
||||
myRequest.responseType = "arraybuffer";
|
||||
if (requestBody) {
|
||||
if (requestBody instanceof ArrayBuffer) {
|
||||
myRequest.send(requestBody);
|
||||
} else if (ArrayBuffer.isView(requestBody)) {
|
||||
myRequest.send(requestBody);
|
||||
} else if (typeof requestBody === "string") {
|
||||
myRequest.send(requestBody);
|
||||
} else {
|
||||
myRequest.send(JSON.stringify(requestBody));
|
||||
}
|
||||
} else {
|
||||
myRequest.send();
|
||||
}
|
||||
|
||||
myRequest.onerror = (e) => {
|
||||
logger.error("http request error");
|
||||
reject(
|
||||
TalerError.fromDetail(
|
||||
TalerErrorCode.WALLET_NETWORK_ERROR,
|
||||
{
|
||||
requestUrl,
|
||||
requestMethod,
|
||||
},
|
||||
"Could not make request",
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
myRequest.addEventListener("readystatechange", (e) => {
|
||||
if (myRequest.readyState === XMLHttpRequest.DONE) {
|
||||
if (myRequest.status === 0) {
|
||||
const exc = TalerError.fromDetail(
|
||||
TalerErrorCode.WALLET_NETWORK_ERROR,
|
||||
{
|
||||
requestUrl,
|
||||
requestMethod,
|
||||
},
|
||||
"HTTP request failed (status 0, maybe URI scheme was wrong?)",
|
||||
);
|
||||
reject(exc);
|
||||
return;
|
||||
}
|
||||
const makeText = async (): Promise<string> => {
|
||||
const td = new TextDecoder();
|
||||
return td.decode(myRequest.response);
|
||||
};
|
||||
const makeJson = async (): Promise<any> => {
|
||||
let responseJson;
|
||||
try {
|
||||
const td = new TextDecoder();
|
||||
const responseString = td.decode(myRequest.response);
|
||||
responseJson = JSON.parse(responseString);
|
||||
} catch (e) {
|
||||
throw TalerError.fromDetail(
|
||||
TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
|
||||
{
|
||||
requestUrl,
|
||||
requestMethod,
|
||||
httpStatusCode: myRequest.status,
|
||||
},
|
||||
"Invalid JSON from HTTP response",
|
||||
);
|
||||
}
|
||||
if (responseJson === null || typeof responseJson !== "object") {
|
||||
throw TalerError.fromDetail(
|
||||
TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
|
||||
{
|
||||
requestUrl,
|
||||
requestMethod,
|
||||
httpStatusCode: myRequest.status,
|
||||
},
|
||||
"Invalid JSON from HTTP response",
|
||||
);
|
||||
}
|
||||
return responseJson;
|
||||
};
|
||||
|
||||
const headers = myRequest.getAllResponseHeaders();
|
||||
const arr = headers.trim().split(/[\r\n]+/);
|
||||
|
||||
// Create a map of header names to values
|
||||
const headerMap: Headers = new Headers();
|
||||
arr.forEach(function (line) {
|
||||
const parts = line.split(": ");
|
||||
const headerName = parts.shift();
|
||||
if (!headerName) {
|
||||
logger.warn("skipping invalid header");
|
||||
return;
|
||||
}
|
||||
const value = parts.join(": ");
|
||||
headerMap.set(headerName, value);
|
||||
});
|
||||
const resp: HttpResponse = {
|
||||
requestUrl: requestUrl,
|
||||
status: myRequest.status,
|
||||
headers: headerMap,
|
||||
requestMethod: requestMethod,
|
||||
json: makeJson,
|
||||
text: makeText,
|
||||
bytes: async () => myRequest.response,
|
||||
};
|
||||
resolve(resp);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
|
||||
return this.fetch(url, {
|
||||
method: "GET",
|
||||
...opt,
|
||||
});
|
||||
}
|
||||
|
||||
postJson(
|
||||
url: string,
|
||||
body: any,
|
||||
opt?: HttpRequestOptions,
|
||||
): Promise<HttpResponse> {
|
||||
return this.fetch(url, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
...opt,
|
||||
});
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
// Nothing to do
|
||||
}
|
||||
}
|
205
packages/web-util/src/utils/http-impl.sw.ts
Normal file
205
packages/web-util/src/utils/http-impl.sw.ts
Normal file
@ -0,0 +1,205 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2022 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Imports.
|
||||
*/
|
||||
import {
|
||||
RequestThrottler,
|
||||
TalerErrorCode,
|
||||
TalerError,
|
||||
} from "@gnu-taler/taler-util";
|
||||
|
||||
import {
|
||||
Headers,
|
||||
HttpRequestLibrary,
|
||||
HttpRequestOptions,
|
||||
HttpResponse,
|
||||
} from "@gnu-taler/taler-util/http";
|
||||
|
||||
/**
|
||||
* An implementation of the [[HttpRequestLibrary]] using the
|
||||
* browser's XMLHttpRequest.
|
||||
*/
|
||||
export class ServiceWorkerHttpLib implements HttpRequestLibrary {
|
||||
private throttle = new RequestThrottler();
|
||||
private throttlingEnabled = true;
|
||||
|
||||
async fetch(
|
||||
requestUrl: string,
|
||||
options?: HttpRequestOptions,
|
||||
): Promise<HttpResponse> {
|
||||
const requestMethod = options?.method ?? "GET";
|
||||
const requestBody = options?.body;
|
||||
const requestHeader = options?.headers;
|
||||
const requestTimeout = options?.timeout ?? { d_ms: 2 * 1000 };
|
||||
|
||||
if (this.throttlingEnabled && this.throttle.applyThrottle(requestUrl)) {
|
||||
const parsedUrl = new URL(requestUrl);
|
||||
throw TalerError.fromDetail(
|
||||
TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED,
|
||||
{
|
||||
requestMethod,
|
||||
requestUrl,
|
||||
throttleStats: this.throttle.getThrottleStats(requestUrl),
|
||||
},
|
||||
`request to origin ${parsedUrl.origin} was throttled`,
|
||||
);
|
||||
}
|
||||
|
||||
let myBody: BodyInit | undefined = undefined;
|
||||
if (requestBody != null) {
|
||||
if (typeof requestBody === "string") {
|
||||
myBody = requestBody;
|
||||
} else if (requestBody instanceof ArrayBuffer) {
|
||||
myBody = requestBody;
|
||||
} else if (ArrayBuffer.isView(requestBody)) {
|
||||
myBody = requestBody;
|
||||
} else if (typeof requestBody === "object") {
|
||||
myBody = JSON.stringify(requestBody);
|
||||
} else {
|
||||
throw Error("unsupported request body type");
|
||||
}
|
||||
}
|
||||
|
||||
const controller = new AbortController();
|
||||
let timeoutId: any | undefined;
|
||||
if (requestTimeout.d_ms !== "forever") {
|
||||
timeoutId = setTimeout(() => {
|
||||
controller.abort(TalerErrorCode.WALLET_HTTP_REQUEST_GENERIC_TIMEOUT);
|
||||
}, requestTimeout.d_ms);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(requestUrl, {
|
||||
headers: requestHeader,
|
||||
body: myBody,
|
||||
method: requestMethod,
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
|
||||
const headerMap = new Headers();
|
||||
response.headers.forEach((value, key) => {
|
||||
headerMap.set(key, value);
|
||||
});
|
||||
return {
|
||||
headers: headerMap,
|
||||
status: response.status,
|
||||
requestMethod,
|
||||
requestUrl,
|
||||
json: makeJsonHandler(response, requestUrl, requestMethod),
|
||||
text: makeTextHandler(response, requestUrl, requestMethod),
|
||||
bytes: async () => (await response.blob()).arrayBuffer(),
|
||||
};
|
||||
} catch (e) {
|
||||
if (controller.signal) {
|
||||
throw TalerError.fromDetail(
|
||||
controller.signal.reason,
|
||||
{},
|
||||
`request to ${requestUrl} timed out`,
|
||||
);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
|
||||
return this.fetch(url, {
|
||||
method: "GET",
|
||||
...opt,
|
||||
});
|
||||
}
|
||||
|
||||
postJson(
|
||||
url: string,
|
||||
body: any,
|
||||
opt?: HttpRequestOptions,
|
||||
): Promise<HttpResponse> {
|
||||
return this.fetch(url, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
...opt,
|
||||
});
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
// Nothing to do
|
||||
}
|
||||
}
|
||||
|
||||
function makeTextHandler(
|
||||
response: Response,
|
||||
requestUrl: string,
|
||||
requestMethod: string,
|
||||
) {
|
||||
return async function getJsonFromResponse(): Promise<any> {
|
||||
let respText;
|
||||
try {
|
||||
respText = await response.text();
|
||||
} catch (e) {
|
||||
throw TalerError.fromDetail(
|
||||
TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
|
||||
{
|
||||
requestUrl,
|
||||
requestMethod,
|
||||
httpStatusCode: response.status,
|
||||
},
|
||||
"Invalid JSON from HTTP response",
|
||||
);
|
||||
}
|
||||
return respText;
|
||||
};
|
||||
}
|
||||
|
||||
function makeJsonHandler(
|
||||
response: Response,
|
||||
requestUrl: string,
|
||||
requestMethod: string,
|
||||
) {
|
||||
return async function getJsonFromResponse(): Promise<any> {
|
||||
let responseJson;
|
||||
try {
|
||||
responseJson = await response.json();
|
||||
} catch (e) {
|
||||
throw TalerError.fromDetail(
|
||||
TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
|
||||
{
|
||||
requestUrl,
|
||||
requestMethod,
|
||||
httpStatusCode: response.status,
|
||||
},
|
||||
"Invalid JSON from HTTP response",
|
||||
);
|
||||
}
|
||||
if (responseJson === null || typeof responseJson !== "object") {
|
||||
throw TalerError.fromDetail(
|
||||
TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
|
||||
{
|
||||
requestUrl,
|
||||
requestMethod,
|
||||
httpStatusCode: response.status,
|
||||
},
|
||||
"Invalid JSON from HTTP response",
|
||||
);
|
||||
}
|
||||
return responseJson;
|
||||
};
|
||||
}
|
@ -126,11 +126,12 @@ export async function defaultRequestHandler<T>(
|
||||
);
|
||||
return result;
|
||||
} else {
|
||||
const error = await buildRequestFailed(
|
||||
response,
|
||||
const dataTxt = await response.text();
|
||||
const error = buildRequestFailed(
|
||||
_url.href,
|
||||
dataTxt,
|
||||
response.status,
|
||||
payload,
|
||||
!!options.token,
|
||||
options,
|
||||
);
|
||||
throw new RequestError(error);
|
||||
@ -292,47 +293,58 @@ async function buildRequestOk<T>(
|
||||
};
|
||||
}
|
||||
|
||||
async function buildRequestFailed<ErrorDetail>(
|
||||
response: Response,
|
||||
export function buildRequestFailed<ErrorDetail>(
|
||||
url: string,
|
||||
dataTxt: string,
|
||||
status: number,
|
||||
payload: any,
|
||||
hasToken: boolean,
|
||||
options: RequestOptions,
|
||||
): Promise<
|
||||
maybeOptions?: RequestOptions,
|
||||
):
|
||||
| HttpResponseClientError<ErrorDetail>
|
||||
| HttpResponseServerError<ErrorDetail>
|
||||
| HttpResponseUnreadableError
|
||||
| HttpResponseUnexpectedError
|
||||
> {
|
||||
const status = response?.status;
|
||||
|
||||
| HttpResponseUnexpectedError {
|
||||
const options = maybeOptions ?? {};
|
||||
const info: RequestInfo = {
|
||||
payload,
|
||||
url,
|
||||
hasToken,
|
||||
hasToken: !!options.token,
|
||||
options,
|
||||
status: status || 0,
|
||||
};
|
||||
|
||||
const dataTxt = await response.text();
|
||||
// const dataTxt = await response.text();
|
||||
try {
|
||||
const data = dataTxt ? JSON.parse(dataTxt) : undefined;
|
||||
const errorCode = !data || !data.code ? "" : `(code: ${data.code})`;
|
||||
const errorHint =
|
||||
!data || !data.hint ? "Not hint." : `${data.hint} ${errorCode}`;
|
||||
|
||||
if (status && status >= 400 && status < 500) {
|
||||
const message =
|
||||
data === undefined
|
||||
? `Client error (${status}) without data.`
|
||||
: errorHint;
|
||||
|
||||
const error: HttpResponseClientError<ErrorDetail> = {
|
||||
type: ErrorType.CLIENT,
|
||||
status,
|
||||
info,
|
||||
message: data?.hint,
|
||||
message,
|
||||
payload: data,
|
||||
};
|
||||
return error;
|
||||
}
|
||||
if (status && status >= 500 && status < 600) {
|
||||
const message =
|
||||
data === undefined
|
||||
? `Server error (${status}) without data.`
|
||||
: errorHint;
|
||||
const error: HttpResponseServerError<ErrorDetail> = {
|
||||
type: ErrorType.SERVER,
|
||||
status,
|
||||
info,
|
||||
message: `${data?.hint} (code ${data?.code})`,
|
||||
message,
|
||||
payload: data,
|
||||
};
|
||||
return error;
|
||||
|
Loading…
Reference in New Issue
Block a user