Catch request in service worker and respond with different image url - javascript

I have this fetch function in my service worker and i try to respond with a different image when the pwa is offline. The fetch function inside the catch throws: Uncaught (in promise) TypeError: Failed to fetch.
self.addEventListener('fetch', (e) => {
if (e.request.method === 'GET') {
e.respondWith(
caches.match(e.request).then((cachedResponse) => {
return cachedResponse || fetch(e.request.url)
.then((res) => {
return res;
}).catch(() => {
//if it is a image then
let url1 = e.request.url.replace(".jpg", "_mini.jpg");
return fetch(url1);
/* Or like this
caches.match(url1).then((cResp) => {
return cResp;
})
*/
})
})
)
}
});
Is it not possible to catch an error when you are offline and respond with a "mini" alternativ image or what do i do wrong?

You are returning cachedResponse if it exists, that prevents your replacement logic from being reached. Try to remove cachedResponse ||.
This can be removed as well:
.then((res) => {
return res;
})
Also, if you're offline the return fetch(url1); won't work because the fetch from a Service Worker won't trigger another FetchEvent recursively. So you have to return caches.match(url1) instead, implying it has been cached before.

Related

Can I display an error if the api cannot return the search?

So I am building an player tracker for players in the NBA, if someone misspells the players name or types a random thing that the api cannot fetch how can I alert that?
function getResults (query) {
fetch(`https://www.balldontlie.io/api/v1/players?search=${searchbox.value}`)
.then(player =>{
return player.json()
}) .then(displayResults);
};
function displayResults(player){
playerName.innerHTML = player.data[0].first_name;
playerLastName.innerHTML = player.data[0].last_name;
teamName.innerHTML = player.data[0].team.full_name;
playerPos.innerHTML = player.data[0].position;
}
If the request is actually throwing an error, you can use a .catch() to catch errors before they're thrown, like this:
function getResults (query) {
fetch(`https://www.balldontlie.io/api/v1/players?search=${searchbox.value}`)
.then(player => {
return player.json()
})
.then(displayResults)
.catch(displayError);
};
function displayError(error) {
// Parse and display your error in the UI
}
However, if the request is properly formatted and the API is available then fetch() will still give you the response without throwing an error. In this case, you can check the status of the response in your .then():
function getResults (query) {
fetch(`https://www.balldontlie.io/api/v1/players?search=${searchbox.value}`)
.then(response => {
if (response.ok) {
return response.json()
}
// If `response.ok` is `false`, you can get the status code for more information on why, or the API may send an error message in the body:
console.log(response.status) // Check http://httpstatuses.com/ for more info on the different statuses
response.json()
})
.then(displayResults)
.catch(displayError);
};

JS Promises - catch() doesn't return anything

I'm fetching data from an API in that way, and i trying to catch an 404 error on it if the user search for a invalid city but is not working.
const search = evt => {
if (evt.key === "Enter") {
fetch(`${api.base}weather?q=${query}&units=metric&APPID=${api.key}`)
.then(res => res.json())
.then(result => {
setWeather(result);
setQuery('');
}).catch(() => console.log("error"));
}
}
console
See the documentation: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
The Promise returned from fetch() won’t reject on HTTP error status even if the response is an HTTP 404 or 500. Instead, it will resolve normally (with ok status set to false), and it will only reject on network failure or if anything prevented the request from completing.
You have to use the response parameter provided by .then(response => {...}) and check response.ok or response.status to get an 404 (or 500) error.
Your code works well, as you can see:
const search = evt => {
if (evt.key === "Enter") {
fetch('http://dfsdfsdfdsfsdfdfs.com')
.then(res => res.json())
.catch(() => console.log("error"));
}
}
search({key : 'Enter'});
But an error code from the server is not considered as an error with fetch so you have to parse the response yourself and react accordingly.
You can use res.ok that will return true if the status code is in the 200-299 range. For more information you can check the Response object documentation
As mentioned the docs, since fetch doesn't do a catch on 404 or 500 status, you can mimic the behavior by throwing an error and catching in the catch section.
fetch(`${api.base}weather?q=${query}&units=metric&APPID=${api.key}`)
.then((response) => {
if(response.status == 404){
throw '404 page not found';
}
return response.json();
})
.then((response) => {
console.log('your JSON string ',response);
})
.catch((err) => {
console.error(err);
});
I was able to get the error that way:
const search = evt => {
if (evt.key === "Enter") {
fetch(`${api.base}weather?q=${query}&units=metric&APPID=${api.key}`)
.then(res => res.json())
.then(result => {
setWeather(result);
setQuery('');
}).then((data) => {
if (data === undefined) {
alert("City not found");
}
});
}
}

Service worker run event waitUntil() based on some condition

I am trying to implement a cache-then-network strategy in the service worker which updates the cache in the background. I want to avoid unnecessary fetch requests, so came up with the following solution -
function cache_then_network(event) {
var updated = false;
event.respondWith(
caches.open(staticCacheName)
.then(cache => cache.match(event.request)
.then((response) => {
if (response) {
return response;
}
else {
return fetch(event.request)
.then((response) => {
const resClone = response.clone();
return caches.open(staticCacheName)
.then((cache) => {
cache.put(event.request, response);
updated = true;
return resClone;
})
})
}
})
)
)
if (!updated) {
event.waitUntil(update(event.request))
}
}
The update function updates the cache by fetching the request using the network.The issue is that the updated variable is always false, causing the update function to run everytime.
I'm not well versed with service workers, and the code is basically stitched up from multiple sources. So alternative/better solutions are welcome. My ultimate goal is to cache first, fetch from network in background, and set a flag which tells whether the content has changed or not.
The Service worker offline-cookbook has all the answers -
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.open('mysite-dynamic').then(function(cache) {
return cache.match(event.request).then(function(response) {
var fetchPromise = fetch(event.request).then(function(networkResponse) {
cache.put(event.request, networkResponse.clone());
return networkResponse;
})
return response || fetchPromise;
})
})
);
});

Return data from Promise and store it in variable after API Call

I´m pretty new to Promises and found many examples here how to access the actual value which is always done with console.log. But my goal is to store the result in a variable and work with it.
getdata = () =>
fetch(
"https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=MSFT&outputsize=full&apikey=demo"
)
.then(response => {
if (response.status === 200) {
return response.json();
} else {
throw new Error("This is an error");
}
})
.then(data => {
console.log(data);
});
getdata();
This code works. Can you help me to rewrite it that the getdata() function allows me to store the result in a variable. Return does not work since I will receive another pending Promise.
You can do it like this:
getdata = () =>
fetch(
"https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=MSFT&outputsize=full&apikey=demo"
).then(response => {
if (response.status === 200) {
return response.json();
} else {
throw new Error("This is an error");
}
});
getdata().then(data => {
//I can do whatever with data
});
Of course you would also want to handle the scenario where the request failed, so you could also chain a .catch(). Alternately, if you have your build process configured for it, you can use async and await so you could do:
try {
const data = await getdata();
} catch(err) {
}
This would need to be in a function marked as async
Well at first we need to declare a variable let's say temp. Then use fetch API to request our query with URL. If server status is 200 then it will return a promise, we need to use then method by passing any argument (res, response, r anything...) and then a fat arrow function (=>) so that we can make the response as json format. After then we need to use another then method to return the json output and assign the value to our declared temp variable.
But if there is any error like 500, 400, 404 server error we need to use catch method with err argument and console it out.
let temp;
fetch('https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=MSFT&outputsize=full&apikey=demo')
.then(res => res.json())
.then(data => temp = data)
.catch(err => console.log(err));

Catch() not handling 404

I'm making a script to fetch some data from my api:
const success = (response) => {
console.log(response);
};
const failed = (error) => {
console.log(error);
};
axios.$http.get('/somedata')
.then((response) => {
success(response.data);
})
.catch((error) => {
failed(error);
});
/somepage is a non-existing page so it returns a 404. But the catch is not handling this. Why not? In my console I have the error TypeError: Cannot read property 'data' of undefined. Why does it not run the failed() function? I don't understand.
Found out it was related to a custom interceptor handling 401-errors (but not 404 errors)...
Judging by the error message, it looks like "success(response.data);" is being called. Is it possible the server is successfully returning a page that says something like "Error 404" rather than actually returning http response code 404?
You could impliment a check for 404s.
axios.$http.get('/somedata')
.then(response => {
if(response.status !== 404) //or any status code really
success(response.data);
else
failed(response)
})
.catch((error) => {
failed(error);
});
Then again what you probably want to check for is to make sure it's a 200 that returns.
axios.$http.get('/somedata')
.then(response => {
if(response.status === 200)
success(response.data);
else
failed(response)
})
.catch((error) => {
failed(error);
});

Categories

Resources