[FIX] Correct the fail retur API to transmit the error from backend when compatible and wrat it when error occured
This commit is contained in:
parent
91849094cd
commit
1fe3cc3523
@ -4,389 +4,442 @@
|
|||||||
* @license MPL-2
|
* @license MPL-2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { RestErrorResponse } from "./model";
|
import { RestErrorResponse, isRestErrorResponse } from "./model";
|
||||||
|
|
||||||
export enum HTTPRequestModel {
|
export enum HTTPRequestModel {
|
||||||
DELETE = "DELETE",
|
DELETE = "DELETE",
|
||||||
GET = "GET",
|
GET = "GET",
|
||||||
PATCH = "PATCH",
|
PATCH = "PATCH",
|
||||||
POST = "POST",
|
POST = "POST",
|
||||||
PUT = "PUT",
|
PUT = "PUT",
|
||||||
}
|
}
|
||||||
export enum HTTPMimeType {
|
export enum HTTPMimeType {
|
||||||
ALL = "*/*",
|
ALL = "*/*",
|
||||||
CSV = "text/csv",
|
CSV = "text/csv",
|
||||||
IMAGE = "image/*",
|
IMAGE = "image/*",
|
||||||
IMAGE_JPEG = "image/jpeg",
|
IMAGE_JPEG = "image/jpeg",
|
||||||
IMAGE_PNG = "image/png",
|
IMAGE_PNG = "image/png",
|
||||||
JSON = "application/json",
|
JSON = "application/json",
|
||||||
MULTIPART = "multipart/form-data",
|
MULTIPART = "multipart/form-data",
|
||||||
OCTET_STREAM = "application/octet-stream",
|
OCTET_STREAM = "application/octet-stream",
|
||||||
TEXT_PLAIN = "text/plain",
|
TEXT_PLAIN = "text/plain",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RESTConfig {
|
export interface RESTConfig {
|
||||||
// base of the server: http(s)://my.server.org/plop/api/
|
// base of the server: http(s)://my.server.org/plop/api/
|
||||||
server: string;
|
server: string;
|
||||||
// Token to access of the data.
|
// Token to access of the data.
|
||||||
token?: string;
|
token?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RESTModel {
|
export interface RESTModel {
|
||||||
// base of the local API request: "sheep/{id}".
|
// base of the local API request: "sheep/{id}".
|
||||||
endPoint: string;
|
endPoint: string;
|
||||||
// Type of the request.
|
// Type of the request.
|
||||||
requestType?: HTTPRequestModel;
|
requestType?: HTTPRequestModel;
|
||||||
// Input type requested.
|
// Input type requested.
|
||||||
accept?: HTTPMimeType;
|
accept?: HTTPMimeType;
|
||||||
// Content of the local data.
|
// Content of the local data.
|
||||||
contentType?: HTTPMimeType;
|
contentType?: HTTPMimeType;
|
||||||
// Mode of the TOKEN in URL or Header (?token:${tokenInUrl})
|
// Mode of the TOKEN in URL or Header (?token:${tokenInUrl})
|
||||||
tokenInUrl?: boolean;
|
tokenInUrl?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ModelResponseHttp {
|
export interface ModelResponseHttp {
|
||||||
status: number;
|
status: number;
|
||||||
data: any;
|
data: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isNullOrUndefined(data: any): data is undefined | null {
|
function isNullOrUndefined(data: any): data is undefined | null {
|
||||||
return data === undefined || data === null;
|
return data === undefined || data === null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// generic progression callback
|
// generic progression callback
|
||||||
export type ProgressCallback = (count: number, total: number) => void;
|
export type ProgressCallback = (count: number, total: number) => void;
|
||||||
|
|
||||||
export interface RESTAbort {
|
export interface RESTAbort {
|
||||||
abort?: () => boolean;
|
abort?: () => boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rest generic callback have a basic model to upload and download advancement.
|
// Rest generic callback have a basic model to upload and download advancement.
|
||||||
export interface RESTCallbacks {
|
export interface RESTCallbacks {
|
||||||
progressUpload?: ProgressCallback;
|
progressUpload?: ProgressCallback;
|
||||||
progressDownload?: ProgressCallback;
|
progressDownload?: ProgressCallback;
|
||||||
abortHandle?: RESTAbort;
|
abortHandle?: RESTAbort;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RESTRequestType {
|
export interface RESTRequestType {
|
||||||
restModel: RESTModel;
|
restModel: RESTModel;
|
||||||
restConfig: RESTConfig;
|
restConfig: RESTConfig;
|
||||||
data?: any;
|
data?: any;
|
||||||
params?: object;
|
params?: object;
|
||||||
queries?: object;
|
queries?: object;
|
||||||
callback?: RESTCallbacks;
|
callback?: RESTCallbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
function replaceAll(input, searchValue, replaceValue) {
|
function replaceAll(input, searchValue, replaceValue) {
|
||||||
return input.split(searchValue).join(replaceValue);
|
return input.split(searchValue).join(replaceValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeTrailingSlashes(input: string): string {
|
function removeTrailingSlashes(input: string): string {
|
||||||
if (isNullOrUndefined(input)) {
|
if (isNullOrUndefined(input)) {
|
||||||
return "undefined";
|
return "undefined";
|
||||||
}
|
}
|
||||||
return input.replace(/\/+$/, "");
|
return input.replace(/\/+$/, "");
|
||||||
}
|
}
|
||||||
function removeLeadingSlashes(input: string): string {
|
function removeLeadingSlashes(input: string): string {
|
||||||
if (isNullOrUndefined(input)) {
|
if (isNullOrUndefined(input)) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return input.replace(/^\/+/, "");
|
return input.replace(/^\/+/, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RESTUrl({
|
export function RESTUrl({
|
||||||
restModel,
|
restModel,
|
||||||
restConfig,
|
restConfig,
|
||||||
params,
|
params,
|
||||||
queries,
|
queries,
|
||||||
}: RESTRequestType): string {
|
}: RESTRequestType): string {
|
||||||
// Create the URL PATH:
|
// Create the URL PATH:
|
||||||
let generateUrl = `${removeTrailingSlashes(
|
let generateUrl = `${removeTrailingSlashes(
|
||||||
restConfig.server
|
restConfig.server
|
||||||
)}/${removeLeadingSlashes(restModel.endPoint)}`;
|
)}/${removeLeadingSlashes(restModel.endPoint)}`;
|
||||||
if (params !== undefined) {
|
if (params !== undefined) {
|
||||||
for (let key of Object.keys(params)) {
|
for (let key of Object.keys(params)) {
|
||||||
generateUrl = replaceAll(generateUrl, `{${key}}`, `${params[key]}`);
|
generateUrl = replaceAll(generateUrl, `{${key}}`, `${params[key]}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
queries === undefined &&
|
||||||
|
(restConfig.token === undefined || restModel.tokenInUrl !== true)
|
||||||
|
) {
|
||||||
|
return generateUrl;
|
||||||
|
}
|
||||||
|
const searchParams = new URLSearchParams();
|
||||||
|
if (queries !== undefined) {
|
||||||
|
for (let key of Object.keys(queries)) {
|
||||||
|
const value = queries[key];
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
for (const element of value) {
|
||||||
|
searchParams.append(`${key}`, `${element}`);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
searchParams.append(`${key}`, `${value}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (
|
}
|
||||||
queries === undefined &&
|
if (restConfig.token !== undefined && restModel.tokenInUrl === true) {
|
||||||
(restConfig.token === undefined || restModel.tokenInUrl !== true)
|
searchParams.append("Authorization", `Bearer ${restConfig.token}`);
|
||||||
) {
|
}
|
||||||
return generateUrl;
|
return generateUrl + "?" + searchParams.toString();
|
||||||
}
|
|
||||||
const searchParams = new URLSearchParams();
|
|
||||||
if (queries !== undefined) {
|
|
||||||
for (let key of Object.keys(queries)) {
|
|
||||||
const value = queries[key];
|
|
||||||
if (Array.isArray(value)) {
|
|
||||||
for (const element of value) {
|
|
||||||
searchParams.append(`${key}`, `${element}`);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
searchParams.append(`${key}`, `${value}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (restConfig.token !== undefined && restModel.tokenInUrl === true) {
|
|
||||||
searchParams.append("Authorization", `Bearer ${restConfig.token}`);
|
|
||||||
}
|
|
||||||
return generateUrl + "?" + searchParams.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchProgress(
|
export function fetchProgress(
|
||||||
generateUrl: string,
|
generateUrl: string,
|
||||||
{
|
{
|
||||||
method,
|
method,
|
||||||
headers,
|
headers,
|
||||||
body,
|
body,
|
||||||
}: {
|
}: {
|
||||||
method: HTTPRequestModel;
|
method: HTTPRequestModel;
|
||||||
headers: any;
|
headers: any;
|
||||||
body: any;
|
body: any;
|
||||||
},
|
},
|
||||||
{ progressUpload, progressDownload, abortHandle }: RESTCallbacks
|
{ progressUpload, progressDownload, abortHandle }: RESTCallbacks
|
||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
const xhr: {
|
const xhr: {
|
||||||
io?: XMLHttpRequest;
|
io?: XMLHttpRequest;
|
||||||
} = {
|
} = {
|
||||||
io: new XMLHttpRequest(),
|
io: new XMLHttpRequest(),
|
||||||
};
|
};
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// Stream the upload progress
|
// Stream the upload progress
|
||||||
if (progressUpload) {
|
if (progressUpload) {
|
||||||
xhr.io?.upload.addEventListener("progress", (dataEvent) => {
|
xhr.io?.upload.addEventListener("progress", (dataEvent) => {
|
||||||
if (dataEvent.lengthComputable) {
|
if (dataEvent.lengthComputable) {
|
||||||
progressUpload(dataEvent.loaded, dataEvent.total);
|
progressUpload(dataEvent.loaded, dataEvent.total);
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
// Stream the download progress
|
});
|
||||||
if (progressDownload) {
|
}
|
||||||
xhr.io?.addEventListener("progress", (dataEvent) => {
|
// Stream the download progress
|
||||||
if (dataEvent.lengthComputable) {
|
if (progressDownload) {
|
||||||
progressDownload(dataEvent.loaded, dataEvent.total);
|
xhr.io?.addEventListener("progress", (dataEvent) => {
|
||||||
}
|
if (dataEvent.lengthComputable) {
|
||||||
});
|
progressDownload(dataEvent.loaded, dataEvent.total);
|
||||||
}
|
}
|
||||||
if (abortHandle) {
|
});
|
||||||
abortHandle.abort = () => {
|
}
|
||||||
if (xhr.io) {
|
if (abortHandle) {
|
||||||
console.log(`Request abort on the XMLHttpRequest: ${generateUrl}`);
|
abortHandle.abort = () => {
|
||||||
xhr.io.abort();
|
if (xhr.io) {
|
||||||
return true;
|
console.log(`Request abort on the XMLHttpRequest: ${generateUrl}`);
|
||||||
}
|
xhr.io.abort();
|
||||||
console.log(
|
return true;
|
||||||
`Request abort (FAIL) on the XMLHttpRequest: ${generateUrl}`
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
// Check if we have an internal Fail:
|
console.log(
|
||||||
xhr.io?.addEventListener("error", () => {
|
`Request abort (FAIL) on the XMLHttpRequest: ${generateUrl}`
|
||||||
xhr.io = undefined;
|
);
|
||||||
reject(new TypeError("Failed to fetch"));
|
return false;
|
||||||
});
|
};
|
||||||
|
}
|
||||||
// Capture the end of the stream
|
// Check if we have an internal Fail:
|
||||||
xhr.io?.addEventListener("loadend", () => {
|
xhr.io?.addEventListener("error", () => {
|
||||||
if (xhr.io?.readyState !== XMLHttpRequest.DONE) {
|
xhr.io = undefined;
|
||||||
return;
|
reject(new TypeError("Failed to fetch"));
|
||||||
}
|
|
||||||
if (xhr.io?.status === 0) {
|
|
||||||
//the stream has been aborted
|
|
||||||
reject(new TypeError("Fetch has been aborted"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Stream is ended, transform in a generic response:
|
|
||||||
const response = new Response(xhr.io.response, {
|
|
||||||
status: xhr.io.status,
|
|
||||||
statusText: xhr.io.statusText,
|
|
||||||
});
|
|
||||||
const headersArray = replaceAll(
|
|
||||||
xhr.io.getAllResponseHeaders().trim(),
|
|
||||||
"\r\n",
|
|
||||||
"\n"
|
|
||||||
).split("\n");
|
|
||||||
headersArray.forEach(function (header) {
|
|
||||||
const firstColonIndex = header.indexOf(":");
|
|
||||||
if (firstColonIndex !== -1) {
|
|
||||||
const key = header.substring(0, firstColonIndex).trim();
|
|
||||||
const value = header.substring(firstColonIndex + 1).trim();
|
|
||||||
response.headers.set(key, value);
|
|
||||||
} else {
|
|
||||||
response.headers.set(header, "");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
xhr.io = undefined;
|
|
||||||
resolve(response);
|
|
||||||
});
|
|
||||||
xhr.io?.open(method, generateUrl, true);
|
|
||||||
if (!isNullOrUndefined(headers)) {
|
|
||||||
for (const [key, value] of Object.entries(headers)) {
|
|
||||||
xhr.io?.setRequestHeader(key, value as string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
xhr.io?.send(body);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Capture the end of the stream
|
||||||
|
xhr.io?.addEventListener("loadend", () => {
|
||||||
|
if (xhr.io?.readyState !== XMLHttpRequest.DONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (xhr.io?.status === 0) {
|
||||||
|
//the stream has been aborted
|
||||||
|
reject(new TypeError("Fetch has been aborted"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Stream is ended, transform in a generic response:
|
||||||
|
const response = new Response(xhr.io.response, {
|
||||||
|
status: xhr.io.status,
|
||||||
|
statusText: xhr.io.statusText,
|
||||||
|
});
|
||||||
|
const headersArray = replaceAll(
|
||||||
|
xhr.io.getAllResponseHeaders().trim(),
|
||||||
|
"\r\n",
|
||||||
|
"\n"
|
||||||
|
).split("\n");
|
||||||
|
headersArray.forEach(function (header) {
|
||||||
|
const firstColonIndex = header.indexOf(":");
|
||||||
|
if (firstColonIndex !== -1) {
|
||||||
|
const key = header.substring(0, firstColonIndex).trim();
|
||||||
|
const value = header.substring(firstColonIndex + 1).trim();
|
||||||
|
response.headers.set(key, value);
|
||||||
|
} else {
|
||||||
|
response.headers.set(header, "");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
xhr.io = undefined;
|
||||||
|
resolve(response);
|
||||||
|
});
|
||||||
|
xhr.io?.open(method, generateUrl, true);
|
||||||
|
if (!isNullOrUndefined(headers)) {
|
||||||
|
for (const [key, value] of Object.entries(headers)) {
|
||||||
|
xhr.io?.setRequestHeader(key, value as string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xhr.io?.send(body);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RESTRequest({
|
export function RESTRequest({
|
||||||
restModel,
|
restModel,
|
||||||
restConfig,
|
restConfig,
|
||||||
data,
|
data,
|
||||||
params,
|
params,
|
||||||
queries,
|
queries,
|
||||||
callback,
|
callback,
|
||||||
}: RESTRequestType): Promise<ModelResponseHttp> {
|
}: RESTRequestType): Promise<ModelResponseHttp> {
|
||||||
// Create the URL PATH:
|
// Create the URL PATH:
|
||||||
let generateUrl = RESTUrl({ restModel, restConfig, data, params, queries });
|
let generateUrl = RESTUrl({ restModel, restConfig, data, params, queries });
|
||||||
let headers: any = {};
|
let headers: any = {};
|
||||||
if (restConfig.token !== undefined && restModel.tokenInUrl !== true) {
|
if (restConfig.token !== undefined && restModel.tokenInUrl !== true) {
|
||||||
headers["Authorization"] = `Bearer ${restConfig.token}`;
|
headers["Authorization"] = `Bearer ${restConfig.token}`;
|
||||||
|
}
|
||||||
|
if (restModel.accept !== undefined) {
|
||||||
|
headers["Accept"] = restModel.accept;
|
||||||
|
}
|
||||||
|
if (restModel.requestType !== HTTPRequestModel.GET) {
|
||||||
|
// if Get we have not a content type, the body is empty
|
||||||
|
if (restModel.contentType !== HTTPMimeType.MULTIPART) {
|
||||||
|
// special case of multi-part ==> no content type otherwise the browser does not set the ";bundary=--****"
|
||||||
|
headers["Content-Type"] = restModel.contentType;
|
||||||
}
|
}
|
||||||
if (restModel.accept !== undefined) {
|
}
|
||||||
headers["Accept"] = restModel.accept;
|
let body = data;
|
||||||
|
if (restModel.contentType === HTTPMimeType.JSON) {
|
||||||
|
body = JSON.stringify(data);
|
||||||
|
} else if (restModel.contentType === HTTPMimeType.MULTIPART) {
|
||||||
|
const formData = new FormData();
|
||||||
|
for (const name in data) {
|
||||||
|
formData.append(name, data[name]);
|
||||||
}
|
}
|
||||||
if (restModel.requestType !== HTTPRequestModel.GET) {
|
body = formData;
|
||||||
// if Get we have not a content type, the body is empty
|
}
|
||||||
if (restModel.contentType !== HTTPMimeType.MULTIPART) {
|
return new Promise((resolve, reject) => {
|
||||||
// special case of multi-part ==> no content type otherwise the browser does not set the ";bundary=--****"
|
let action: undefined | Promise<Response> = undefined;
|
||||||
headers["Content-Type"] = restModel.contentType;
|
if (
|
||||||
}
|
isNullOrUndefined(callback) ||
|
||||||
|
(isNullOrUndefined(callback.progressDownload) &&
|
||||||
|
isNullOrUndefined(callback.progressUpload) &&
|
||||||
|
isNullOrUndefined(callback.abortHandle))
|
||||||
|
) {
|
||||||
|
// No information needed: call the generic fetch interface
|
||||||
|
action = fetch(generateUrl, {
|
||||||
|
method: restModel.requestType,
|
||||||
|
headers,
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// need progression information: call old fetch model (XMLHttpRequest) that permit to keep % upload and % download for HTTP1.x
|
||||||
|
action = fetchProgress(
|
||||||
|
generateUrl,
|
||||||
|
{
|
||||||
|
method: restModel.requestType ?? HTTPRequestModel.GET,
|
||||||
|
headers,
|
||||||
|
body,
|
||||||
|
},
|
||||||
|
callback
|
||||||
|
);
|
||||||
}
|
}
|
||||||
let body = data;
|
action
|
||||||
if (restModel.contentType === HTTPMimeType.JSON) {
|
.then((response: Response) => {
|
||||||
body = JSON.stringify(data);
|
if (response.status >= 200 && response.status <= 299) {
|
||||||
} else if (restModel.contentType === HTTPMimeType.MULTIPART) {
|
const contentType = response.headers.get("Content-Type");
|
||||||
const formData = new FormData();
|
if (
|
||||||
for (const name in data) {
|
!isNullOrUndefined(restModel.accept) &&
|
||||||
formData.append(name, data[name]);
|
restModel.accept !== contentType
|
||||||
}
|
) {
|
||||||
body = formData;
|
reject({
|
||||||
}
|
name: "Model accept type incompatible",
|
||||||
return new Promise((resolve, reject) => {
|
time: Date().toString(),
|
||||||
let action: undefined | Promise<Response> = undefined;
|
status: 901,
|
||||||
if (
|
message: `REST Content type are not compatible: ${restModel.accept} != ${contentType}`,
|
||||||
isNullOrUndefined(callback) ||
|
statusMessage: "Fetch error",
|
||||||
(isNullOrUndefined(callback.progressDownload) &&
|
error: "rest-tools.ts Wrong type in the message return type",
|
||||||
isNullOrUndefined(callback.progressUpload) &&
|
} as RestErrorResponse);
|
||||||
isNullOrUndefined(callback.abortHandle))
|
} else if (contentType === HTTPMimeType.JSON) {
|
||||||
) {
|
response
|
||||||
// No information needed: call the generic fetch interface
|
.json()
|
||||||
action = fetch(generateUrl, {
|
.then((value: any) => {
|
||||||
method: restModel.requestType,
|
resolve({ status: response.status, data: value });
|
||||||
headers,
|
})
|
||||||
body,
|
.catch((reason: Error) => {
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// need progression information: call old fetch model (XMLHttpRequest) that permit to keep % upload and % download for HTTP1.x
|
|
||||||
action = fetchProgress(
|
|
||||||
generateUrl,
|
|
||||||
{
|
|
||||||
method: restModel.requestType ?? HTTPRequestModel.GET,
|
|
||||||
headers,
|
|
||||||
body,
|
|
||||||
},
|
|
||||||
callback
|
|
||||||
);
|
|
||||||
}
|
|
||||||
action
|
|
||||||
.then((response: Response) => {
|
|
||||||
if (response.status >= 200 && response.status <= 299) {
|
|
||||||
const contentType = response.headers.get("Content-Type");
|
|
||||||
if (
|
|
||||||
!isNullOrUndefined(restModel.accept) &&
|
|
||||||
restModel.accept !== contentType
|
|
||||||
) {
|
|
||||||
reject({
|
|
||||||
name: "Model accept type incompatible",
|
|
||||||
time: Date().toString(),
|
|
||||||
status: 901,
|
|
||||||
error: `REST check wrong type: ${restModel.accept} != ${contentType}`,
|
|
||||||
statusMessage: "Fetch error",
|
|
||||||
message: "rest-tools.ts Wrong type in the message return type",
|
|
||||||
} as RestErrorResponse);
|
|
||||||
} else if (contentType === HTTPMimeType.JSON) {
|
|
||||||
response
|
|
||||||
.json()
|
|
||||||
.then((value: any) => {
|
|
||||||
resolve({ status: response.status, data: value });
|
|
||||||
})
|
|
||||||
.catch((reason: any) => {
|
|
||||||
reject({
|
|
||||||
name: "API serialization error",
|
|
||||||
time: Date().toString(),
|
|
||||||
status: 902,
|
|
||||||
error: `REST parse json fail: ${reason}`,
|
|
||||||
statusMessage: "Fetch parse error",
|
|
||||||
message: "rest-tools.ts Wrong message model to parse",
|
|
||||||
} as RestErrorResponse);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
resolve({ status: response.status, data: response.body });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
reject({
|
|
||||||
name: "REST return no OK status",
|
|
||||||
time: Date().toString(),
|
|
||||||
status: response.status,
|
|
||||||
error: `${response.body}`,
|
|
||||||
statusMessage: "Fetch code error",
|
|
||||||
message: "rest-tools.ts Wrong return code",
|
|
||||||
} as RestErrorResponse);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((error: any) => {
|
|
||||||
reject({
|
reject({
|
||||||
name: "Request fail",
|
name: "API serialization error",
|
||||||
time: Date(),
|
time: Date().toString(),
|
||||||
status: 999,
|
status: 902,
|
||||||
error: error,
|
message: `REST parse json fail: ${reason}`,
|
||||||
statusMessage: "Fetch catch error",
|
statusMessage: "Fetch parse error",
|
||||||
message: "rest-tools.ts detect an error in the fetch request",
|
error: "rest-tools.ts Wrong message model to parse",
|
||||||
|
} as RestErrorResponse);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
resolve({ status: response.status, data: response.body });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// the answer is not correct not a 2XX
|
||||||
|
// clone the response to keep the raw data if case of error:
|
||||||
|
response
|
||||||
|
.clone()
|
||||||
|
.json()
|
||||||
|
.then((value: any) => {
|
||||||
|
if (isRestErrorResponse(value)) {
|
||||||
|
reject(value);
|
||||||
|
} else {
|
||||||
|
response
|
||||||
|
.text()
|
||||||
|
.then((dataError: string) => {
|
||||||
|
reject({
|
||||||
|
name: "API serialization error",
|
||||||
|
time: Date().toString(),
|
||||||
|
status: 903,
|
||||||
|
message: `REST parse error json with wrong type fail. ${dataError}`,
|
||||||
|
statusMessage: "Fetch parse error",
|
||||||
|
error: "rest-tools.ts Wrong message model to parse",
|
||||||
|
} as RestErrorResponse);
|
||||||
|
})
|
||||||
|
.catch((reason: any) => {
|
||||||
|
reject({
|
||||||
|
name: "API serialization error",
|
||||||
|
time: Date().toString(),
|
||||||
|
status: response.status,
|
||||||
|
message: `unmanaged error model: ??? with error: ${reason}`,
|
||||||
|
statusMessage: "Fetch ERROR parse error",
|
||||||
|
error: "rest-tools.ts Wrong message model to parse",
|
||||||
|
} as RestErrorResponse);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((reason: Error) => {
|
||||||
|
response
|
||||||
|
.text()
|
||||||
|
.then((dataError: string) => {
|
||||||
|
reject({
|
||||||
|
name: "API serialization error",
|
||||||
|
time: Date().toString(),
|
||||||
|
status: response.status,
|
||||||
|
message: `unmanaged error model: ${dataError} with error: ${reason}`,
|
||||||
|
statusMessage: "Fetch ERROR TEXT parse error",
|
||||||
|
error: "rest-tools.ts Wrong message model to parse",
|
||||||
|
} as RestErrorResponse);
|
||||||
|
})
|
||||||
|
.catch((reason: any) => {
|
||||||
|
reject({
|
||||||
|
name: "API serialization error",
|
||||||
|
time: Date().toString(),
|
||||||
|
status: response.status,
|
||||||
|
message: `unmanaged error model: ??? with error: ${reason}`,
|
||||||
|
statusMessage: "Fetch ERROR TEXT FAIL",
|
||||||
|
error: "rest-tools.ts Wrong message model to parse",
|
||||||
|
} as RestErrorResponse);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
})
|
||||||
|
.catch((error: Error) => {
|
||||||
|
if (isRestErrorResponse(error)) {
|
||||||
|
reject(error);
|
||||||
|
} else {
|
||||||
|
reject({
|
||||||
|
name: "Request fail",
|
||||||
|
time: Date(),
|
||||||
|
status: 999,
|
||||||
|
message: error,
|
||||||
|
statusMessage: "Fetch catch error",
|
||||||
|
error: "rest-tools.ts detect an error in the fetch request",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RESTRequestJson<TYPE>(
|
export function RESTRequestJson<TYPE>(
|
||||||
request: RESTRequestType,
|
request: RESTRequestType,
|
||||||
checker?: (data: any) => data is TYPE
|
checker?: (data: any) => data is TYPE
|
||||||
): Promise<TYPE> {
|
): Promise<TYPE> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
RESTRequest(request)
|
RESTRequest(request)
|
||||||
.then((value: ModelResponseHttp) => {
|
.then((value: ModelResponseHttp) => {
|
||||||
if (isNullOrUndefined(checker)) {
|
if (isNullOrUndefined(checker)) {
|
||||||
console.log(`Have no check of MODEL in API: ${RESTUrl(request)}`);
|
console.log(`Have no check of MODEL in API: ${RESTUrl(request)}`);
|
||||||
resolve(value.data);
|
resolve(value.data);
|
||||||
} else if (checker === undefined || checker(value.data)) {
|
} else if (checker === undefined || checker(value.data)) {
|
||||||
resolve(value.data);
|
resolve(value.data);
|
||||||
} else {
|
} else {
|
||||||
reject({
|
reject({
|
||||||
name: "Model check fail",
|
name: "Model check fail",
|
||||||
time: Date().toString(),
|
time: Date().toString(),
|
||||||
status: 950,
|
status: 950,
|
||||||
error: "REST Fail to verify the data",
|
error: "REST Fail to verify the data",
|
||||||
statusMessage: "API cast ERROR",
|
statusMessage: "API cast ERROR",
|
||||||
message: "api.ts Check type as fail",
|
message: "api.ts Check type as fail",
|
||||||
} as RestErrorResponse);
|
} as RestErrorResponse);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((reason: RestErrorResponse) => {
|
.catch((reason: RestErrorResponse) => {
|
||||||
reject(reason);
|
reject(reason);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RESTRequestVoid(request: RESTRequestType): Promise<void> {
|
export function RESTRequestVoid(request: RESTRequestType): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
RESTRequest(request)
|
RESTRequest(request)
|
||||||
.then((value: ModelResponseHttp) => {
|
.then((value: ModelResponseHttp) => {
|
||||||
resolve();
|
resolve();
|
||||||
})
|
})
|
||||||
.catch((reason: RestErrorResponse) => {
|
.catch((reason: RestErrorResponse) => {
|
||||||
reject(reason);
|
reject(reason);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user