Detect fetch API request on web page in JavaScript - javascript

Background: I am working with the Shopify ScriptTag which allows me to add a JavaScript file on the storefront. All I have is that script file.
Current Behaviour: There is an option, "Buy It Now", which allow customers to checkout directly by skipping Add To Cart. When they click on Buy It Now, Shopify sends a fetch() POST request to checkouts.json to create the checkout.
Problem: I need to detect that this "fetch request happened" in my own JavaScript file.
self.addEventListener('fetch', event => {
console.log("event happened");
});
I have tried Fetch Event API, but it seems to be only working in Service Worker scope.
Is there a possibility to detect this?
Like we can detect XMLHttpRequest by overriding its open method using prototypal inheritance.

const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.initiatorType === "fetch") {
console.log('Fetch request detected to', entry.name);
}
}
});
observer.observe({
entryTypes: ["resource"]
});
fetch('https://cors-anywhere.herokuapp.com/')
.then(res => res.text())
.then(text => console.log(text.split('\n')[0]));
Using Performance Observer. Thanks to #guest271314.

Yes, you can overwrite window.fetch with your own function that calls the original window.fetch after (or before) running your own code:
const nativeFetch = window.fetch;
window.fetch = function(...args) {
console.log('detected fetch call');
return nativeFetch.apply(window, args);
}
fetch('https://cors-anywhere.herokuapp.com/')
.then(res => res.text())
.then(text => console.log(text.split('\n')[0]));

Related

React native fetch data

I have a problem with fetch data. My friend creates Rest Api.
There is my fun:
const AnyCors = `https://cors-anywhere.herokuapp.com/`;
const urlAllBus = `http://207.185.72.111:15430/stops?size=15`;
fetchBusStop = () => {
return new Promise((resolve, rejects) => {
fetch(AnyCors+urlAllBus)
.then((result) => {
if (!result.ok) throw result.json();
return result.json();
})
.then((result) => {
console.log(result);
resolve(result);
})
.catch((error) =>
error.then((body) => {
console.log('Bad', body);
rejects(body);
}),
);
});
};
I create an app with react-native. When I use only urlAllBus my virtual machine work fine. The problem is with a physical machine. When I try using my fun with urlAllbus in chrome I get a problem with CORS so I used AnyCors+urlAllBus and everything works fine. But in the virtual and physical machine there solutions not work. I don't know what I should do
You friend's API should accept CORS by adding a Access-Control-Allow-Origin: * header to its responses to allow any website to access it. They can also limit access to a specific site by setting the header to the base URL of such site, like Access-Control-Allow-Origin: http://example.com.
If the API is express-based, I hightly recommend the cors package for the job, as it makes it a single-line change.
Otherwise, tell them to give this MDN page a read for more information about CORS :)

Make local storage that can't be changed

Is there a way to make local-storage (or some other client side storage) impossible for users to change in the dev tools? Say I have a feature in which the user needs to pay money for or complete a challenge to get, and the program wants to check if the user has that feature. How can I stop people from going into the developer tools and manually adding that feature?
The closest thing to what ypu decribe is a JWT.
The token would contain this config and is signed with encryption, so the user won't be able to alter the config value without corrupting the token.
However, of course if you are doing this logic on the client side they could always find other ways of manipulating this. E.g. intercepting your JavaScript and altering it never check permissions at all.
You will always be better off handling security server side, then you could choose to only serve these scripts to people who have paid for them.
You can use indexedDB, Which use can't modify by themself.
Code for Angular 9. I have use localforage.
import * as localforage from 'localforage';
// store particular key details
setDataInIndexedDB(key, value) {
return localforage.setItem(key, JSON.stringify(value))
.then(() => { })
.catch(() => { });
}
// fetch particular key details
async getDataFromIndexedDB(key) {
return new Promise((resolve, reject) => {
localforage.getItem(key)
.then((result: any) => {
resolve(JSON.parse(result));
})
.catch((err) => {
reject(err);
});
});
}
// For Remove Particular Field/Key
removeDataFromIndexedDB(key) {
return new Promise((resolve, reject) => {
localforage.removeItem(key)
.then((result: any) => {
const remove = 'Key Removed';
return resolve(remove);
}).catch((err) => {
return reject(err);
});
});
}
// Database has been entirely deleted.
clearDataFromIndexedDB() {
return localforage.clear();
}
Edit IndexedDB

Auto-update solution for PWA Apps

I want to turn my normal website into a progressive web app. For that everything is finished. The Website is responsible and I already set up a manifest. Now the last part comes to me. The ServiceWorker to save the website to the cache of the device. My problem is that I can not find a simple solution for that. Because for my website it is important that the user runs the new version every time I made an update. Do you know a solution how let the ServiceWorker check if anything changed once the user opens the app and after that delete the old cache and make a new one based on the new files and the new code?
It would be very great, when somebody could provide a code example.
My HTML SIDE:
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('./sw.js')
.then(reg => console.log(reg))
.catch(err => console.log(err));
}
</script>
AND HERE THE sw.js:
self.addEventListener('install', event => event.waitUntil(
caches.open('web_pwa').then(cache => cache.add('/'))
));
self.addEventListener('fetch', event => event.respondWith(
caches.open('web_pwa')
.then(cache => cache.match(event.request))
.then(response => response || fetch(event.request))
));
Short description: Update SW file a bit and handle removing old cache in activate event.
Detailed description
Whenever you do changes in your code files (other than sw.js). You need to trigger both the install and activate events in service worker. In order to update your changes.
In order to trigger these events the sw.js should be updated even a single bit. (simply atleast a character).
By convention developers handle this by maintaining Versioning. Also it will be easy to add and delete caches.
const version = 'v2';
self.addEventListener('install', res => {
caches.open(version).then(cache => {
cache.addAll(caches);
});
console.log('[sw] Installed successfully :');
// self.skipWaiting();
});
self.addEventListener('fetch', event => event.respondWith(
caches.open(version)
.then(cache => cache.match(event.request))
.then(response => response || fetch(event.request))
));
If you need to directly update the sw.js inspite of user's status then uncomment the self.skipWaiting() as it skips waiting for activation and gets activated immediately.
Inside activate event is where you have to delete the old caches based on cache version.
self.addEventListener('activate', event => {
caches.keys().then(function(cacheNames) {
cacheNames.forEach(function(cacheName) {
if (cacheName !== version) {
caches.delete(cacheName);
}
});
});
}

Redirect/ Routing issues in React and Express

I am creating a flight search app that makes external api calls. The data will be reorganized and returned in search results component.
On submit, the data is sent to express and takes about 10 seconds or more to complete all the api calls.
I think I need a loader at some point for during the delay of api calls, but also I am unsure of how to send/render the data.
As it stands, I have two pages home.js- '/' where i make the search and is sent to the server side, and prices.js- '/search' which when loaded fetches the data from the json file. but i do not have them connected
Both files work but I need to connect them. When I press submit, the user inputs are sent to server and the api calls are made but in order to see the results i have to manually refresh localhost:3000/search.
In express app after all the api calls, I tried res.redirect method, however the error given was setting the headers after sent to the client.
In react, I tried after submitting, to redirect to the search page. However I could not get it to redirect and also as soon as the /search page is called, it fetches the data from the file. This will happen before the api has finished writing to file and therefore the previous search results will render.
--in app.js
setTimeout(() => {
Promise.all([promise, promise2]).then(values => {
return res.redirect('http://localhost:3000/search');
});
}, 25000);
I had to wrap the api calls in promises so it will only redirect after all is written to file.
(in react prices.js)
componentDidMount() {
fetch('/search')
.then(res => {
return res.json()
})
.then(res => {
console.log(res.toString());
this.setState({flightData: res});
})
.catch(error => console.log(error));
}
home.js
home.js
```
onChange = (e) => {
this.setState({
originOne: e.target.value, originTwo: e.target.value});
};
onSubmit = (e) => {
e.preventDefault();
const { originOne, originTwo ,redirectToResult} = this.state;
};
```
app.js - I have all the functions calling each other in a waterfall style ( probably not the best way I know)
app.post('/', function getOrigins(req,res) {
var OrigOne;
var OrigTwo;
....
function IataCodeSearchOrg1(res, OrigOne, OrigTwo) {
...
findPrices(res,A,B)
}
function findPrices(res, A, B) {
promise = new Promise(function (resolve) {
...
}
}
All the methods are called within eachother. The api calls are in a loop and after each iteration they are written to the json file.
All these functions are in the app.post method and i tried to res.redirect but it did not work.
EDIT:
You can't redirect server-side from an XHR request. You would need to redirect client-side.
e.g.
componentDidMount() {
fetch('/search')
.then(res => res.json())
...
.then(() => window.location = '/myredirecturl')
}

React Service Worker fetch event listener never executes for external API requests

I'm creating a PWA using React.
My Service Worker seems to be working fine except for the fetch event listener, which does not execute when a GET HTTP request fires within my React app using the fetch API to get data from an external API on the web.
Where should I be placing my fetch event listener?
Does it work for external requests or only for requests to files that are part of the app?
Please let me know if you notice any issues with my code below.
I'm using the boilerplate Service Worker file that comes when using create-react-app to start a new project.
Here is my code:
(The execution never gets into the window.addEventListener('fetch', ...) part)
function registerValidSW(swUrl) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
window.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then((response) => {
if (response) {
return response
}
return fetch(event.request).then(response => {
caches.open('fetch').then((cache) => {
cache.put(event.request, response.clone());
});
return response;
})
}
)
);
});
console.log('New content is available; please refresh.');
} else {
// static files caching
cacheStaticFiles();
// external api data caching
cacheApiData();
// At this point, everything has been precached
console.log('Content is now cached for offline use.');
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}
So I ran into this issue. It turns out that CRA actually compiles that service worker into a different service-worker.js file in your build folder, and that gets registered. If you append your code to the end of that file it will work, but annoyingly you'd have to do that on every build.
I'm using this addin: https://www.npmjs.com/package/cra-append-sw to append it automatically instead.
At present it had this minor issue, which requires running it with a different option: https://github.com/tszarzynski/cra-append-sw/issues/18

Categories

Resources