Koha/koha-tmpl/intranet-tmpl/prog/js/vue/fetch/http-client.js
Jonathan Druart df3acf3d68
Bug 35199: (bug 34448 follow-up) Fix error handling in http-client.js
From bug bug 34448.

386         // Submit the form, get 500
387         cy.intercept("POST", "/api/v1/erm/agreements", {
388             statusCode: 500,
389             error: "Something went wrong",
390         });
391         cy.get("#agreements_add").contains("Submit").click();
392         cy.get("main div[class='dialog alert']").contains(
393             "Something went wrong: SyntaxError: Unexpected end of JSON input"
394         );

This is wrong: we are now showing a JS error (SyntaxError) instead of the expected 500: internal server error!

The problem was that a regular 500 does not have anything in the body,
and _fetchJSON didn't handle that ( JSON.parse(text) ).
If the body of the response does not contain anything we need to get the
text from statusText (which contains "Internal Server Error" in case of
500).

Test plan:
1. Make sure all cypress tests pass
2. Confirm the above:
Raise an exception from a given route (/agreements for instance) and
confirm that the error displayed on the interface is correct (ie. not
SyntaxError, but "Error: Internal Server Error")

For QA:
* This change is covered properly in Dialog_spec.ts, no need to redo it in
every other test files.
* Without the following change in count, we see:
"Something went wrong: Error: Error: Internal Server Error" because
setError is called twice. We don't need to set the error from count, it
has been set from _fetchJSON already.
-            error => {
-                setError(error.toString());
-            }
+            error => {}

Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
2023-10-31 16:45:50 -03:00

158 lines
4.2 KiB
JavaScript

import { setError, submitting, submitted } from "../messages";
class HttpClient {
constructor(options = {}) {
this._baseURL = options.baseURL || "";
this._headers = options.headers || {
"Content-Type": "application/json;charset=utf-8",
};
}
async _fetchJSON(
endpoint,
headers = {},
options = {},
return_response = false,
mark_submitting = false
) {
let res, error;
if (mark_submitting) submitting();
await fetch(this._baseURL + endpoint, {
...options,
headers: { ...this._headers, ...headers },
})
.then(response => {
if (!response.ok) {
return response.text().then(text => {
let message;
if (text) {
let json = JSON.parse(text);
message =
json.error ||
json.errors.map(e => e.message).join("\n") ||
json;
} else {
message = response.statusText;
}
throw new Error(message);
});
}
return return_response ? response : response.json();
})
.then(result => {
res = result;
})
.catch(err => {
error = err;
setError(err);
})
.then(() => {
if (mark_submitting) submitted();
});
if (error) throw Error(error);
return res;
}
get(params = {}) {
return this._fetchJSON(params.endpoint, params.headers, {
...params.options,
method: "GET",
});
}
getAll(params = {}) {
let url =
params.endpoint +
"?" +
new URLSearchParams({
_per_page: -1,
...(params.params && params.params),
...(params.query && { q: JSON.stringify(params.query) }),
});
return this._fetchJSON(url, params.headers, {
...params.options,
method: "GET",
});
}
post(params = {}) {
const body = params.body
? typeof params.body === "string"
? params.body
: JSON.stringify(params.body)
: undefined;
return this._fetchJSON(
params.endpoint,
params.headers,
{
...params.options,
body,
method: "POST",
},
false,
true
);
}
put(params = {}) {
const body = params.body
? typeof params.body === "string"
? params.body
: JSON.stringify(params.body)
: undefined;
return this._fetchJSON(
params.endpoint,
params.headers,
{
...params.options,
body,
method: "PUT",
},
false,
true
);
}
delete(params = {}) {
return this._fetchJSON(
params.endpoint,
params.headers,
{
parseResponse: false,
...params.options,
method: "DELETE",
},
true,
true
);
}
count(params = {}) {
let res;
return this._fetchJSON(params.endpoint, params.headers, {}, 1).then(
response => {
if (response) {
return response.headers.get("X-Total-Count");
}
},
error => {}
);
}
patch(params = {}) {
const body = params.body
? typeof params.body === "string"
? params.body
: JSON.stringify(params.body)
: undefined;
return this._fetchJSON(params.endpoint, params.headers, {
...params.options,
body,
method: "PATCH",
});
}
}
export default HttpClient;