Fatch Api Solution
/*
Parses the JSON returned by a network request
@param {object} response A response from a network request
@return {object} The parsed JSON, status from the response
*/
function parseJSON(response) {
return new Promise((resolve) => response.json()
.then((json) => resolve({
status: response.status,
ok: response.ok,
json,
})));
}
/*
Requests a URL, returning a promise
@param {string} url The URL we want to request
@param {object} [options] The options we want to pass to "fetch"
@return {Promise} The request promise
*/
export default function request(url, options) {
return new Promise((resolve, reject) => {
fetch(endpoint + url, options)
.then(parseJSON)
.then((response) => {
if (response.ok) {
return resolve(response.json);
}
// extract the error from the server's json
return reject(response.json.meta.error);
})
.catch((error) => reject({
networkError: error.message,
}));
});
}
For me, fny answers really got it all. since fetch is not throwing error, we need to throw/handle the error ourselves. Posting my solution with async/await. I think it's more strait forward and readable
Solution 1: Not throwing an error, handle the error ourselves
async _fetch(request) {
const fetchResult = await fetch(request); //Making the req
const result = await fetchResult.json(); // parsing the response
if (fetchResult.ok) {
return result; // return success object
}
const responseError = {
type: 'Error',
message: result.message || 'Something went wrong',
data: result.data || '',
code: result.code || '',
};
const error = new Error();
error.info = responseError;
return (error);
}
Here if we getting an error, we are building an error object, plain JS object and returning it, the con is that we need to handle it outside. How to use:
const userSaved = await apiCall(data); // calling fetch
if (userSaved instanceof Error) {
debug.log('Failed saving user', userSaved); // handle error
return;
}
debug.log('Success saving user', userSaved); // handle success
Solution 2: Throwing an error, using try/catch
async _fetch(request) {
const fetchResult = await fetch(request);
const result = await fetchResult.json();
if (fetchResult.ok) {
return result;
}
const responseError = {
type: 'Error',
message: result.message || 'Something went wrong',
data: result.data || '',
code: result.code || '',
};
let error = new Error();
error = { ...error, ...responseError };
throw (error);
}
Here we are throwing and error that we created, since Error ctor approve only string, Im creating the plain Error js object, and the use will be:
try {
const userSaved = await apiCall(data); // calling fetch
debug.log('Success saving user', userSaved); // handle success
} catch (e) {
debug.log('Failed saving user', userSaved); // handle error
}
Solution 3: Using customer error
async _fetch(request) {
const fetchResult = await fetch(request);
const result = await fetchResult.json();
if (fetchResult.ok) {
return result;
}
throw new ClassError(result.message, result.data, result.code);
}
And:
class ClassError extends Error {
constructor(message = 'Something went wrong', data = '', code = '') {
super();
this.message = message;
this.data = data;
this.code = code;
}
}
function makeRequest(url, options) {
return new Promise((resolve, reject) => {
fetch(url, options)
.then(handleResponse)
.then(response => JSON.parse(response))
.then((json) => resolve(json))
.catch((error) => {
try {
reject(JSON.parse(error))
}
catch(e) {
reject(error)
}
})
})
}
function handleResponse(response) {
return response.json()
.then((json) => {
// Modify response to include status ok, success, and status text
let modifiedJson = {
success: response.ok,
status: response.status,
statusText: response.statusText ? response.statusText : json.error || '',
response: json
}
// If request failed, reject and return modified json string as error
if (! modifiedJson.success) return Promise.reject(JSON.stringify(modifiedJson))
// If successful, continue by returning modified json string
return JSON.stringify(modifiedJson)
})
}
// Then I use it in other files like so. First declare any options, if needed.
const options = {
// your options... method: POST, headers, cors, etc.
}
// Then make the request using the promise function
makeRequest(/oauth/token, options)
.then((data) => console.log(data)) // do something great with data
.catch(error => console.log(error)) // do something useful with error
function handleErrors(response) {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
}
fetch("http://httpstat.us/500")
.then(handleErrors)
.then(response => console.log("ok") )
.catch(error => console.log(error) );
const fetchUsers = async () => {
try {
const res = await fetch('https://reqres.in/api/users');
if (!res.ok) {
throw new Error(res.status);
}
const data = await res.json();
console.log(data);
} catch (error) {
console.log(error);
}
}
fetchUsers();