Save fetched JSON data to sessionStorage - javascript

I just figured out how to write an async/await function to fetch data from an API, and it's working, but it's hitting the API like crazy. So now I'm trying to save the fetched data to sessionStorage and only fetch from the API if the data isn't in the sessionStorage.
Here's my code:
const fetchMeetingData = async () => {
console.log('api hit')
try {
const response = await fetch(https://sheet.best...)
const data = await response.json()
validate(data) // Clean data to remove null key values
return data
} catch (e) {
console.log('Fetch error with getMeetingData()')
}
}
const filterMeetings = async (filters) => {
meetings = await fetchMeetingData()
meetings.forEach((meeting) => {
meeting.time2 = moment(meeting.time, ["h:mm A"]).format("HHmm")
})
let today = moment().format("dddd").toString()
let hour = moment().format('HHmm').toString()
let filteredMeetings = meetings.filter(function (matches) {
if (document.querySelector('#select-day').selectedIndex === 0 && filters.searchText === '') {
return matches.day === today &&
moment(matches.time, ["h:mm A"]).format("HHmm") > hour
} else {
return true
}
})
Here's what I've tried:
const fetchMeetingData = async () => {
console.log('api hit')
try {
const response = await fetch(https://sheet.best...)
const data = await response.json()
validate(data) // Clean data to remove null key values
sessionStorage.setItem('meetingData', JSON.stringify(data)) // added this line
return data
} catch (e) {
console.log('Whoa! Fetch error with getMeetingData()')
}
}
I'm not really sure where to go from here, or if this is even the correct approach. My noob instinct was to do something like this, which didn't work.
savedMeetingData = sessionStorage.getItem('meetingData')
const getSavedMeetingData = async () => {
if (savedMeetingData) {
meetings = savedMeetingData
return meetings
} else {
fetchMeetingData()
meetings = await data
return meetings
}
const filterMeetings = async (filters) => {
meetings = await getSavedMeetingData() // replaces call to fetchMeetingData
meetings.forEach((meeting) => {
meeting.time2 = moment(meeting.time, ["h:mm A"]).format("HHmm")
})
I'm not sure if that's exactly the code I was trying but it's close. The problem was the API was still getting hit, even though the data was stored successfully to sessionStorage.
I'd really appreciate some help and/or suggestions on how to clarify this question.
SOLUTION:
Based on answer from #Christian
// StackOverflow Q/A
async function getMeetingData() {
const preLoadedData = sessionStorage.getItem('meetingData')
if(!preLoadedData) {
try {
const response = await fetch('https://sheet.best...')
const data = await response.json()
validate(data)
sessionStorage.setItem('meetingData', JSON.stringify(data))
console.log('api hit')
return data
} catch (e) {
console.log('Whoa! Fetch error with getMeetingData()')
}
} else {
console.log('no api hit!!!')
return JSON.parse(preLoadedData)
}
}
async function getSavedMeetingData() {
const meetings = await getMeetingData()
return meetings
}
const filterMeetings = async (filters) => {
meetings = await getSavedMeetingData()
meetings.forEach((meeting) => {
meeting.time2 = moment(meeting.time, ["h:mm A"]).format("HHmm")
})

If you could be more explicit on what exactly did not work it would be great :) (did not save data in sessionStorage?, could not retrieve it?, etc...). Anyway, maybe you could try something like this and see if it helps:
async function getSavedMeetingData() {
const meetingData = await getMeetingData();
}
async function getMeetingData() {
const preloadedData = sessionStorage.getItem('meetingData');
if (!preloadedData) {
try {
const response = await fetch('https://myapiurl.com/');
const data = validate(response.json());
sessionStorage.setItem('meetingData', JSON.stringify(data));
return data;
} catch (e) {
console.log('Whoa! Fetch error with getMeetingData()');
}
} else {
return JSON.parse(preloadedData);
}
}
One more reminder (just in case), keep in mind you are saving this to sessionStorage, so if you close the tab do not expect to have the information saved, in that case you should use localStorage.

Related

How do I update my list after POST if im using a different endpoint?

I need help with updating my list after POST. I can't see any answers online. Usually what I will just do is push object into array but I think in my case is different.
This function uses 2 api endpoint. The first api will get the list data. The weather api will base from the first api endpoint data, iterate through the list and get the data of the city that matches the name.
async getPreviousWeather() {
let endpoint = "/api/";
let promises = [];
try {
const response1 = await axios.get(endpoint);
this.cities = response1.data;
for (let i = 0; i < this.cities.length; i++) {
const response2 = await axios.get(
`https://api.openweathermap.org/data/2.5/weather?q=${this.cities[i].city_name}&units=metric&appid={API_KEY}`
);
this.infos.push(response2.data);
}
} catch (error) {
console.log(error);
}
},
Now this endpoint post data from the first endpoint. The only problem that I have here is how to update the list on post. I don't know how to push it or i tried calling this.getPreviousWeather(); what happens is it adds the new data but also adds the previous ones.
async onSubmit() {
let endpoint = "/api/";
try {
const response = await axios.post(endpoint, {
city_name: this.city_query,
});
this.city_query = null;
this.getPreviousWeather();
} catch (error) {
console.log(error);
}
},
created() {
this.getPreviousWeather();
},
I created the answer I'm not sure if it is effective but it works.
methods: {
async onSubmit() {
let endpoint1 = `https://api.openweathermap.org/data/2.5/weather?q=${this.city_query}&units=metric&appid={API_KEY}`;
let endpoint2 = "/api/";
try {
const response1 = await axios.get(endpoint1);
const response2 = await axios.post(endpoint2, {
city_name: this.city_query,
});
this.city_query = null;
if (this.error) {
this.error = null;
}
this.infos.push(response1.data);
} catch (error) {
console.log(error);
}
},

useQuery always returning undefined data in react-query

I'm new to react-query and I'm trying to move all of my API calls into a new file, out of the useQuery calls.
Unfortunately when I do this all of my data is undefined.
I do see the network calls in the network tab, it just isn't being set properly in useQuery.
Thanks in advance for any help on how to change my code to fix this!
// this works
const { loading, data, error } = useQuery([conf_id], async () => {
const { data } = await axios.get(API_URL + '/event/' + conf_id)
return data
});
// this doesn't work - data is undefined
const axios = require('axios');
const getEventById = async () => {
const { data } = await axios.get(API_URL + '/event/2541' + '?noyear=true');
return data.data;
};
const { loading, data, error } = useQuery('conf_id', getEventById});
// the below variants don't work either
// const { loading, data, error } = useQuery('conf_id', getEventById()});
// const { loading, data, error } = useQuery('conf_id', async () => await getEventById()});
// const { loading, data, error } = useQuery('conf_id', async () => await
// const { data } = getEventById(); return data
// });
An AxiosResponse has a data attribute from which you can access the actual API JSON response.
Like you pointed out, this:
async () => {
const { data } = await axios.get(API_URL + '/event/' + conf_id)
return data
}
Should suffice for the fetching function.
So the final implementation should look like
const axios = require('axios');
const getEventById = async () => {
const { data } = await axios.get(API_URL + '/event/2541' + '?noyear=true');
return data;
};
const { loading, data, error } = useQuery('conf_id', getEventById);
The data you get from the useQuery should be undefined on the first render and once the server responds it will change to whatever the response is.

Confused by async behavior

I'm using a try/catch to make some fetch requests, then I am extracting the title from the HTML and adding it to my object 'sleekResponse'
When I try to parse the body and add it to that object I'm having issues with the return value not including the title that I extracted from the HTML
I know this has something to do with asynchronicity, or my shallow understanding of Promises, but I can't tell why the return value is different from the value it's logging just before it's sent.
async function fetchUrl(url) {
console.log(url);
try {
const myInit = {
mode: 'cors'
}
let sleekResponse = {};
await fetch(url, myInit).then(function (response) {
sleekResponse.redirected = response.redirected;
sleekResponse.status = response.status;
return response;
})
.then((response) => titleWait(response))
.then((res) => sleekResponse.title = res)
function titleWait(response) {
Promise.resolve(response.text()).then((res) => {
a = res.split('<title>');
b = a[1].split('</title>')
sleekResponse.title = b[0];
return sleekResponse;
})
console.log(sleekResponse);
return sleekResponse;
}
console.log(sleekResponse); // This logs the correct value
return sleekResponse; // when it's returned it doesn't show the title that was added
} catch (err) {
return `${err}`;
}
}
I've tried so many things I don't remember everything that I tried. I know that I'm missing something that might be obvious, but I still don't understand why the console.log value is different from the value returned one line later.
The main issue is that titleWait doesn't return its own promise:
function titleWait(response) {
return Promise.resolve(response.text()).then((res) => {
a = res.split('<title>');
b = a[1].split('</title>')
sleekResponse.title = b[0];
return sleekResponse;
});
}
It's still a very convoluted way to write it. This is better:
async function titleWait(response) {
const res = await response.text());
const a = res.split('<title>');
const b = a[1].split('</title>')
sleekResponse.title = b[0];
return sleekResponse;
}
i hope i can a litel help
this basic fetch();
const response = await fetch('your url')
const data = await response.json();
console.log(data);

React jsonserver promise result issue

I am creating a react/ redux app with json fake api server I am trying to add a login and trying to get data from json fake api server, data is showing and all ok , but data is always resulting as a promise and the required data is inside the promise. i tried many ways to distructure but throwing errors , could anyone help me on this,
my axios request
const urlss = "http://localhost:5000/users";
export const userslist = async () => {
const r = await axios.get(urlss);
const data = r.data;
return data;
};
const newout2 = userslist();
const newout = newout2;
console.log(newout);
the place where I am using it
export const login = (credentials) => (dispatch) => {
return new Promise((resolve, reject) => {
const matchingUser =
newout2 &&
newout2.find(({ username }) => username === credentials.username);
if (matchingUser) {
if (matchingUser.password === credentials.password) {
dispatch(setUser(matchingUser));
resolve(matchingUser);
} else {
dispatch(setUser(null));
reject("Password wrong");
}
} else {
dispatch(setUser(null));
reject("No user matching");
}
});
};
i am getting this error
You are using then in your userslist method while awaiting in an async method. drop the then and just use proper await inside an async method.
const urlss = "http://localhost:5000/users";
export const userslist = async () => {
const r = await axios.get(urlss);
const data = r.data;
return data;
};

can i make the async.retry method retry even on successfull queries but based on a condition

I'm studying the node.js module async,I want to find out if there is a way to change the async.retry method to retry even on successfull operations but stop based on some condition or response let's say its an api call.
According to its docs ,the function will continue trying the task on failures until it succeeds.if it succeeds it will only run only that time But how can i make it work the same on successfull operations and make it stop on some condition ?
const async = require('async');
const axios = require('axios');
const api = async () => {
const uri = 'https://jsonplaceholder.typicode.com/todos/1';
try {
const results = await axios.get(uri);
return results.data;
} catch (error) {
throw error;
}
};
const retryPolicy = async (apiMethod) => {
async.retry({ times: 3, interval: 200 }, apiMethod, function (err, result) {
// should retry untill the condition is met
if (result.data.userId == 5) {
// stop retring
}
});
};
retryPolicy(api);
Yes, You can just throw a custom error if condition is not met. Would be something like that:
const async = require('async');
const axios = require('axios');
const api = async () => {
const uri = 'https://jsonplaceholder.typicode.com/todos/1';
try {
const results = await axios.get(uri);
if(typeof result.data.userId != 'undefined' && result.data.userId == 5){ // change this condition to fit your needs
return results.data;
}else{
throw {name : "BadDataError", message : "I don't like the data I got"};
}
} catch (error) {
throw error;
}
};
I don't think this is possible.
On the async.retry documentation you can find this description:
Attempts to get a successful response from task no more than times
times before returning an error. If the task is successful, the
callback will be passed the result of the successful task. If all
attempts fail, the callback will be passed the error and result (if
any) of the final attempt.
However, using the delay function given here, you can do what you want another way:
const async = require('async');
const axios = require('axios');
const delay = (t, val) => {
return new Promise((resolve) => {
setTimeout(() => { resolve(val) }, t);
});
}
const api = async () => {
const uri = 'https://jsonplaceholder.typicode.com/todos/1';
try {
const results = await axios.get(uri);
return results.data;
} catch (error) {
throw error;
}
};
const retryPolicy = async (apiMethod) => {
const times = 3
const interval = 200
let data
for (count = 0; count < 3; count++) {
try {
data = await apiMethod()
catch(e) {
console.log(e)
await delay(interval)
continue
}
if (data.userId === 5) {
break;
}
await delay(interval)
}
// do something
};
retryPolicy(api);

Categories