I try to hijack a specific GraphQL-Request via the service-worker to fake the response from data in my IndexedDB, but I get an error that the event already has been responded to. The fetching is working for cached files, if the fetched data is not in the cache it will use the network. If there is no network there will be an offline fallback. How can I orchestrate my Promises that I can also hijack requests to my GraphQL API and a specific Query (operationName), because it seems i messed up with async event.respondWith calls ?
self.addEventListener('fetch', function (event) {
if (event.request.url === __GRAPHQL_URL__) {
event.request.clone().json().then(({operationName, variables}) => {
switch (operationName) {
case 'getOfflineFacilities':
//when a fetch is matching there will be the error
event.respondWith(serveOfflineFacilities());
}
});
}else{
event.respondWith(
caches.match(event.request).then(function (response) {
console.log("cache or network fallback");
return response || fetch(event.request);
}).catch(function () {
console.log("offline fallback");
return caches.match('/index.html');
})
);
}
});
Error when there is a GraphQL Query that is hitting __GRAPHQL_URL__ and my operationName
sw.js:41 Uncaught (in promise) DOMException: Failed to execute 'respondWith' on 'FetchEvent': The event has already been responded to.
It's sparsely documented, but you need to call the respondWith
method immediately in the handler. If the event handler exits and respondWith
had not been called, the request will be handled so that the default response is served. respondWith
will check the dispatch flag
that is only set during the event handler call - when you only call it from a promise callback, you will get the "The event has already been responded to" exception.
So you need to change your code to pass the whole promise to respondWith
:
if (event.request.url === __GRAPHQL_URL__) {
event.respondWith(event.request.clone().json().then(({operationName, variables}) => {
// ^^^^^^^^^^^^^^^^^^
switch (operationName) {
case 'getOfflineFacilities':
return serveOfflineFacilities();
// ^^^^^^
}
}));
// ^
}