Merge api request using promise - javascript

Due to the api of a plugin I'm using not working properly. I need to merge the two different requests. I am using the thunk below.
I can get a response but I cannot seem to check for response.ok, and return the combined data:
export function fetchCategories() {
const firstPage =
"http://wordpress.rguc.co.uk/index.php/wp-json/tribe/events/v1/categories?per_page=60&page=1";
const secondPage =
"http://wordpress.rguc.co.uk/index.php/wp-json/tribe/events/v1/categories?per_page=60&page=2";
return dispatch => {
dispatch(isLoading(true));
Promise.all([fetch(firstPage), fetch(secondPage)])
.then(response => {
// check for ok here
response.ForEach(response => {
if (!response.ok) throw Error(response.statusText);
});
dispatch(isLoading(false));
return response;
})
.then(response => response.json())
// dispatch combined data here
.then(data => dispatch(fetchSuccessCategories(data)))
.catch(() => dispatch(hasErrored(true)));
};
}
Any ideas?

You are doing the check for .ok fine because it's in a loop, but your response is actually an array of two Response objects, it does not have a .json() method. You could do Promise.all(responses.map(r => r.json())), but I would recommend to write a helper function that does the complete promise chaining for one request and then call that twice:
function fetchPage(num) {
const url = "http://wordpress.rguc.co.uk/index.php/wp-json/tribe/events/v1/categories?per_page=60&page="+num;
return fetch(url).then(response => {
if (!response.ok)
throw new Error(response.statusText);
return response.json();
});
}
export function fetchCategories() {
return dispatch => {
dispatch(isLoading(true));
Promise.all([fetchPage(1), fetchPage(2)]).then(data => {
dispatch(isLoading(false));
dispatch(fetchSuccessCategories(merge(data)));
}, err => {
dispatch(isLoading(false));
dispatch(hasErrored(true));
});
};
}

Related

Exsport function with Api call then import it on another page and wait for data

I'm new to all this export, import, async so please bare with me.
I have one file where I make API call and export that function so it can be used across other pages.
Of course on other page when function is invoked data payload is not yet there so i get undefind. So i tried to implement async (first time).
Please correct me if this is even possible or I I need some other method.
app.js:
export function inboxMeniIkona () {
//let req = xxxx
fetch(req)
.then(response => {
if (response.ok) {
return response.json()
} else {
throw new Error('NETWORK RESPONSE ERROR')
}
})
.then(data => {
return new Promise(resolve => {
return data // data here is allright
});
})
.catch(error => console.error('FETCH ERROR:', error))
}
And then I tried on other page:
import { inboxMeniIkona } from '~/app'
async function asyncCall() {
console.log('calling');
const result = await inboxMeniIkona();
console.log(result);
// expected output: "resolved"
}
asyncCall();
I'm still getting
CONSOLE LOG: calling
CONSOLE LOG: undefined
Please advise
Add async in your functions and await in your fecth and return it like this.
export async function inboxMeniIkona () {
//let req = xxxx
return await fetch(req)
.then(response => {
if (response.ok) {
return response.json()
} else {
throw new Error('NETWORK RESPONSE ERROR')
}
})
.then(data => {
return data // data here is allright
})
.catch(error => console.error('FETCH ERROR:', error))
}

Vue store dispatch error response not being passed to UI

I'm trying to get the error response from my Vue store dispatch method, into my component, so I can tell the user if the save failed or not.
store/userDetails.js
const state = {
loading: {
user_details: false,
}
}
const getters = {
// Getters
}
const actions = {
save({commit, dispatch, rootState}, payload) {
commit('setLoading', {name: 'users', value: true});
axios(
_prepareRequest('post', api_endpoints.user.details, rootState.token, payload)
).then((response) => {
if (response.data) {
commit('setState', {name: 'user_details', value: response.data.units});
commit('setLoading', {name: 'user_details', value: false});
dispatch(
'CommonSettings/setSavingStatus',
{components: {userDetails: "done"}},
{root:true}
);
}
}).catch((error)=> {
console.log(error)
return error
}
)
}
My component method
views/Users.vue
send() {
this.$store.dispatch({
type: 'Users/save',
userDetails: this.current
}).then(response => {
console.log(response)
});
},
Above, I'm logging out the response in two places.
The response in my store/userDetails.js file is logged out fine, but it's not being passed to my send() function in my component - it comes up as undefined. Any reason why it wouldn't be passed through? Is this the correct way to do this?
This works for me. Try this solution.
store.js
actions: {
save(context, payload) {
console.log(payload);
return new Promise((resolve, reject) => {
axios(url)
.then((response) => {
resolve(response);
})
.catch((error) => {
reject(error);
});
});
},
},
My Component method
App.vue
save(){
this.$store.dispatch("save", dataSendToApi).then((response)=>{
console.log(response)
})
}
Try returning axios call in the Store Action:
// add return
return axios(
_prepareRequest('post', api_endpoints.user.details, rootState.token, payload)
)
.then() // your stuff here
.catch() // your stuff here
If that won't work, use Promise in the Store Action. Like this:
return new Promise((resolve, reject) => {
return axios() // simplify for readibility reason, do your stuff here
.then((response) => {
//... your stuff here
resolve(response) // add this line
})
.catch((error) => {
// ... your stuff here
reject(error) // add this line
})
})
you should return a promise, reference link:vue doc

Cache.match(request) returns undefined in service-worker for JSONP requests

Below you can see my first attempt at creating a service-worker and the problem with this code is that it never returns cached response since cache.match(request) in addUrlToCache function is always returning undefined. Does anyone have any ideas as to why it's not finding cached requests?
import API from 'top-secret'
const PHOTOS_CACHE = 'photos-cache'
const OBJECTS_CACHE = 'objects-cache'
const urlCacheData = [
{
cacheKey: OBJECTS_CACHE,
url: API.apiUrlGetObjects
},
{
cacheKey: PHOTOS_CACHE,
url: API.apiUrlGetPhotos
}
]
function addUrlToCache (request, cacheKey) {
return caches
.open(cacheKey)
.then(cache => cache.match(request))
.then(cachedResponse => {
if (cachedResponse) {
return cachedResponse
}
return fetch(request).then(response => {
caches.open(cacheKey).then(cache => cache.put(request, response))
return response.clone()
})
})
}
function clearCache () {
return caches.keys().then(cacheNames => {
const promisesToDeleteCache = cacheNames.map(cacheName =>
caches.delete(cacheName)
)
return Promise.all(promisesToDeleteCache)
})
}
self.addEventListener('activate', event => {
event.waitUntil(clearCache())
})
self.addEventListener('fetch', event => {
const urlToCache = urlCacheData.find(item =>
event.request.url.includes(item.url)
)
if (urlToCache) {
event.respondWith(
addUrlToCache(event.request, urlToCache.cacheKey)
)
}
})
After you fetch request in your addUrltoCache function replace
fetch(request).then(response => {
caches.open(cacheKey).then(cache => cache.put(request, response))
return response.clone()
})
with,
return fetch(request).then(response => {
caches.open(cacheKey).then(cache => cache.put(request, response.clone()))
return response;
})
because you should clone first and then return the response.In your code you have already used your response to put value in cache.
I've just figured out that the problem was that I had JSONP requests with random callback values like bla-bla/api?callback=jsonp_randomNumber, so url would be different every time I make a request because of the random number thing, that's why cache.match check wouldn't work.
I fixed it by hardcoding callback value in the config of the jsonp library that I used (jsonp-fetch in my case).

Axios prints value on console but returns undefined

I have quite an issue for some time and is getting on my nerves and it doesn't make sense. I have used axios on my react frontend and it works perfect when assigning the get value to the state. But when using it in a normal javascript code, I appear to have this following issue: i can print the object's value in the console but it will return only undefined.. Here is my code:
login = () => {
let data;
axios.get('https://myaddress/authenticate')
.then(response => {
data = response;
console.log('data here', data);
})
.catch(error => {
console.error('auth.error', error);
});
console.log('eee', data);
return data;
};
Here we are talking about axios strictly.
You can't return an ajax response because it's asynchronous. You should wrap your function into a promise or pass a callback to login
UPDATE: As #Thilo said in the comments, async/await would be another option, but it will let you set the response to data tho ...
1. Wrap into a promise
login = () => new Promise((resolve, reject)=>{
axios.get('https://myaddress/authenticate')
.then(response => {
resolve(response)
})
.catch(error => {
reject(error)
});
});
// Usage example
login()
.then(response =>{
console.log(response)
})
.catch(error => {
console.log(error)
})
2. Pass a callback
login = (callback) => {
axios.get('https://myaddress/authenticate')
.then(response => {
callback(null,response)
})
.catch(error => {
callback(error,null)
});
};
// Usage example
login((err, response)=>{
if( err ){
throw err;
}
console.log(response);
})
3. Async/Await
login = async () => {
// You can use 'await' only in a function marked with 'async'
// You can set the response as value to 'data' by waiting for the promise to get resolved
let data = await axios.get('https://myaddress/authenticate');
// now you can use a "synchronous" data, only in the 'login' function ...
console.log('eee', data);
return data; // don't let this trick you, it's not the data value, it's a promise
};
// Outside usage
console.log( login() ); // this is pending promise
In ES7/ES8 you can do async/await like a boss:
login = () => {
return new Promise((resolve, reject) => {
axios.get('https://myaddress/authenticate')
.then(response => {
resolve(response)
})
.catch(error => {
console.error('auth.error', error);
reject(error)
});
});
};
async function getData() {
try{
const data = await login()
} catch(error){
// handle error
}
return data;
}
getData()
.then((data) => console.log(data));

Angular 2 Observables

I'm building an app to get some events from facebook, take a look:
EventComponent:
events: Object[] = [];
constructor(private eventService: EventService) {
this.eventService.getAll()
.subscribe(events => this.events = events)
}
EventService:
getAll() {
const accessToken = 'xxxxxxxxxxx';
const batch = [{...},{...},{...},...];
const body = `access_token=${accessToken}&batch=${JSON.stringify(batch)}`;
return this.http.post('https://graph.facebook.com', body)
.retry(3)
.map(response => response.json())
}
AuthenticationService:
getAccessToken() {
return new Promise((resolve: (response: any) => void, reject: (error: any) => void) => {
facebookConnectPlugin.getAccessToken(
token => resolve(token),
error => reject(error)
);
});
}
I have a few questions:
1) How can I set an interval to update the events every 60 seconds?
2) The value of accessToken will actually come from a promise, should I do something like this?
getAll() {
const batch = [{...},{...},{...},...];
this.authenticationService.getAccessToken().then(
accessToken => {
const body = `access_token=${accessToken}&batch=${JSON.stringify(batch)}`;
return this.http.post('https://graph.facebook.com', body)
.retry(3)
.map(response => response.json())
},
error => {}
);
}
3) If yes, how can I also handle errors from the getAccessToken() promise since I'm returning just the Observer?
4) The response from the post request will not return an array of objects by default, I'll have to make some manipulation. Should I do something like this?
return this.http.post('https://graph.facebook.com', body)
.retry(3)
.map(response => response.json())
.map(response => {
const events: Object[] = [];
// Manipulate response and push to events...
return events;
})
Here are the answers to your questions:
1) You can leverage the interval function of observables:
getAll() {
const accessToken = 'xxxxxxxxxxx';
const batch = [{...},{...},{...},...];
const body = `access_token=${accessToken}&batch=${JSON.stringify(batch)}`;
return Observable.interval(60000).flatMap(() => {
return this.http.post('https://graph.facebook.com', body)
.retry(3)
.map(response => response.json());
});
}
2) You could leverage at this level the fromPromise function of observables:
getAll() {
const batch = [{...},{...},{...},...];
return Observable.fromPromise(this.authenticationService.getAccessToken())
.flatMap(accessToken => {
const body = `access_token=${accessToken}&batch=${JSON.stringify(batch)}`;
return this.http.post('https://graph.facebook.com', body)
.retry(3)
.map(response => response.json())
});
}
3) You can leverage the catch operator to handle errors:
getAll() {
const batch = [{...},{...},{...},...];
return Observable.fromPromise(this.authenticationService.getAccessToken())
.catch(() => Observable.of({})) // <-----
.flatMap(accessToken => {
const body = `access_token=${accessToken}&batch=${JSON.stringify(batch)}`;
return this.http.post('https://graph.facebook.com', body)
.retry(3)
.map(response => response.json())
});
}
In this case, when an error occurs to get the access token, an empty object is provided to build the POST request.
4) Yes sure! The map operator allows you to return what you want...
Put the event inside a timeout block and set the interval of 60s. setTimeout(() => {},60000).
Using Template string is totally fine but you're telling its value comes from a promise. If your whole block of code is inside resolve function of promise this should fine. So it depends on where your code is. And why promises .In A2 it's recommended to use Observables and not promises. Don't mix them.
You're not returning anything in the error function. So if you return error from that block you'll get error data in case of error. error => erroror error => { return error; }.
Exactly you should you map to get the response and manipulate it and return just the array from that function. .map(resp => { return resp.array}). Since respons is in JSON format now you have to get array from it and return it. you can do as much modifications you want before returning it.
Feel free to edit the answer...

Categories