Nesting a http request inside list of promises - javascript

I have a service function that returns a list of promises:
getData(user) {
return this.$q.all({
userInfo: this.$http.get(this.buildUrl('user.getinfo', user)),
userTopArtists: this.$http.get(this.buildUrl('user.gettopartists', user)),
userChart: this.$http.get(this.buildUrl('user.getWeeklyChartList', user))
}).then(resp => {
return resp;
}).catch(err => {
this.$q.reject('Error' + err.status);
})
}
, which I'm calling inside my controller:
validateUser() {
this.error = null;
this.service.getData(this.$scope.username)
.then(resp => {
if (resp.userInfo.data.user) {
this.service.storeUserData('userData', JSON.stringify(resp));
this.$location.path('/profile');
} else {
this.error = resp.userInfo.data.message;
}
})
}
Works fine until now but what I'm looking for is manipulating what data I get from the userChart request in particular.
I want to manipulate the json I get from calling userChart, store some of it inside of an array and make another request that returns data using the stored array object values from the initial request as parameters.
So basically I don't need the json from userChart, I just need to use to it make a nested(?) request using some of its data.

If you return a promise from the then the caller of the original promise will wait until the nested promise is resolved. It does not matter if the caller was your service using $q.all or something else, it is chained.
This shows just the relevant code, it located in your service with everything else being unchanged.
userChart: this.$http.get(this.buildUrl('user.getWeeklyChartList', user))
.then((result) => {
// additional manipulation if needed on result
// second call to http and return the resulting promise
return this.$http.doSomething('');
});

I haven't tried this, but maybe you could do something with the result of that call as soon as it comes back? Something like this?
getData(user) {
return this.$q.all({
userInfo: this.$http.get(this.buildUrl('user.getinfo', user)),
userTopArtists: this.$http.get(this.buildUrl('user.gettopartists', user)),
userChart: this.$http.get(this.buildUrl('user.getWeeklyChartList', user)).
then(function(response) {
// Do something with the successful response
}, function(response) {
// Do something for the failed response
})
}).then(resp => {
return resp;
}).catch(err => {
this.$q.reject('Error' + err.status);
})
}

If I understood yours needs you should first get the charts response and then use that response to call the other webservices, so something like this should work:
validateUser() {
this.getData({})
.then(function (response) {
// response containing 'userInfo' and 'userTopArtists'
console.log(arguments);
});
}
getData(user) {
const me = this;
return me.$http.get('https://jsonplaceholder.typicode.com/users')
.then(function (charts) {
return me.$q.all({
// use charts as param for other calls...
userInfo: me.$http.get('https://jsonplaceholder.typicode.com/users'),
userTopArtists: me.$http.get('https://jsonplaceholder.typicode.com/users')
});
})
.catch(err => {
me.$q.reject('Error' + err.status);
});
}

Related

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));

Data coming in Service Response but showing 'undefined' from where it is called - JavaScript | React

I am calling an API which in turns gives me data back. When I am trying to store that data in variable and then console.log, the result is undefined. Why is it happening? How to fix this?
someService.js
getItems: () => {
axios.get('https://jsonplaceholder.typicode.com/users/')
.then( response => {
console.log(response.data); //gives me an array of 10 items
return response.data;
})
}
someReducer.js
case "GET_ITEM_LIST": {
let data = getItemsAPI.getItems();
console.log(data); //gives undefined
return {
...state,
items: data
}
}
With your case, you fetching API from server as asynchronous:
Try to you async/await like this:
export default {
fetch: async (state, { type, payload }) => {
// ....
case "GET_ITEM_LIST": {
let data = await getItemsAPI.getItems();
console.log(data); // you will see data here
return {
...state,
items: data
}
}
// ....
}
}
You need to return promise and await for result as its async. Notice return before axios that returns promise that you can work on. (I'm editing in mobile and I guess formatting is bad. If it worked, will update later)
getItems: () => {
return axios.get('https://jsonplaceholder.typicode.com/users/')
.then( response => {
console.log(response.data); //gives me an array of 10 items
return response.data;
})
}
Then, await getItems() or getItems().then() wherever you need.

Return an API response from a Promise.then() in AngularJS

I'm new in AngularJS and wanted to write a function in AngularJS, which tries to delete a user. On success it should return a boolean, which determines if he was succesfully deleted.
Anyway, the extracted result out of the promise always returns true, even if the Api-Response is false. I tried extracting the response as written here: Return value from a promise in Angular. I also tried other links, but none of them really helped me solving my problem.
user.controller.js:
deleteUser(user) {
const self = this;
self.userActionPromise = self.userService.deleteUser(user.id).then(deleted => {
if (deleted) {
self.messagesService.successMessage('user.DELETE_SUCCESS');
self.loadUsers();
} else {
self.messagesService.errorMessage('user.DELETE_FAILURE');
}
});
}
user.rest.service.js:
self.user = $resource(config.restServerUrl + 'users/:id', {id: '#id'}, {
delete: {method: 'DELETE'}
});
deleteUser(id) {
return this.user.delete({id: id}).$promise.then(deleted => {
return !!deleted;
});
}
result of
return this.user.delete({id: id}).$promise.then(deleted => {
return !!deleted;
})
always return true when request finished.
If you want to cover fail result:
return this.user.delete({id: id}).$promise.then(deleted => {
return deleted;
}, function (error) {
return error;
})
second function will be executed when server return an error
https://www.baeldung.com/spring-boot-custom-error-page
Http responce statusCode should say that came an error, like 500 (https://developer.yahoo.com/social/rest_api_guide/http-response-codes.html).
When you return status code 200, and result false, it just say to angularjs that request finished successfuly and result of it false

How to Inspect fetch call and Return same Call

I need a way of taking a promise, calling .then on it to inspect the returned value, and then to return this promise exactly as it was to other parts of the system. The context is I'm trying to modify the fetch API from a GraseMonkey script so that I can modify the data returned. I inspect this by calling .json() on the response. However if I don't modify the data, I need to return an object exactly representing the original call to the fetch API so that the page's code sees no difference. But when I have tried returning the object, I get an error that the response has already been consumed and now I'm lost in a stack of Promises that I can't seem to get to work out (I'm not a JS native)
The code below is what I have already and it works, but it's not really acceptable as it duplicates every other request that's not being mangled.
function newFetch(){
if (needsToBeModified(arguments[0])) {
response = null;
return oldFetch.apply(this, arguments)
.then(r => {
response = r;
return r.json();
})
.then(
j => {
j = processJSON(j);
return new Promise((resolve, rej) => {
response.json = () => new Promise((resolve, reject) => resolve(j));
resolve(response);
});
},
(fail) => {
return oldFetch.apply(this, arguments)
//How can I avoid making this call here again?
}
);
} else {
return oldFetch.apply(this, arguments);
}
}
Please could someone tell me a way of peeking at the json, and if this throws an error, returning the original promise from fetch without needing to make the call again?
Thanks.
fetch() returns a promise that resolves to a response object. One of the methods on that response object is .clone() which sounds like it does just what you want. From the doc for .clone():
The clone() method of the Response interface creates a clone of a response object, identical in every way, but stored in a different variable.
clone() throws a TypeError if the response Body has already been used. In fact, the main reason clone() exists is to allow multiple uses of Body objects (when they are one-use only.)
I think you can use that like this:
function newFetch(){
let p = oldFetch.apply(this, arguments);
if (needsToBeModified(arguments[0])) {
let origResponse, cloneResponse;
return p.then(r => {
origResponse = r;
cloneResponse = r.clone();
return r.json();
}).then(j => {
j = processJSON(j);
// monkey patch .json() so it is a function that resolves to our modified JSON
origResponse.json = () => Promise.resolve(j);
return origResponse;
}, fail => {
// return clone of original response
if (cloneResponse) {
return cloneResponse;
} else {
// promise was rejected earlier, don't have a clone
// need to just propagate that rejection
throw fail;
}
});
} else {
return p;
}
}
Like #jfriend suggested, you will need to clone the response so that your caller can consume it again after you inspected the JSON:
function newFetch(urlOrRequest) {
var promise = oldFetch.apply(this, arguments);
if (needsToBeModified(urlOrRequest)) {
return promise.then(response =>
response.clone().json().then(obj => {
const result = Promise.resolve(processJSON(obj));
response.json = () => result;
return response;
}, jsonErr => {
return response;
})
);
} else {
return promise;
}
}
Or better yet, instead of returning the old, unaltered response with a patched json method, just create a new one:
function newFetch(urlOrRequest) {
var promise = oldFetch.apply(this, arguments);
if (needsToBeModified(urlOrRequest)) {
return promise.then(response =>
response.clone().json().then(obj => {
const result = JSON.stringify(processJSON(obj));
return new Response(result, response);
}, jsonErr => response)
);
} else {
return promise;
}
}
Alternatively, the easiest way to go would be to defer your processJSON call into the overwritten json method:
…
if (needsToBeModified(urlOrRequest)) {
return promise.then(response =>
response.json = function() {
return Response.prototype.json.call(this).then(processJSON);
};
return response;
});
}
…
I think I understand that question to say that sometimes you need to alter the result of an async operation depending it's arguments
There's no need to perform the operation twice, and I think the OP code can be dramatically simplified as follows:
function newFetch() {
return oldFetch.apply(this, arguments).then(r => {
return (needsToBeModified(arguments[0]))? processJSON(r.json()) : r;
});
}

Returning data from Axios API [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 months ago.
I am trying to use a Node.JS application to make and receive API requests. It does a get request to another server using Axios with data it receives from an API call it receives. The second snippet is when the script returns the data from the call in. It will actually take it and write to the console, but it won't send it back in the second API.
function axiosTest() {
axios.get(url)
.then(function (response) {
console.log(response.data);
// I need this data here ^^
return response.data;
})
.catch(function (error) {
console.log(error);
});
}
...
axiosTestResult = axiosTest();
response.json({message: "Request received!", data: axiosTestResult});
I'm aware this is wrong, I'm just trying to find a way to make it work. The only way I can seem to get data out of it is through console.log, which isn't helpful in my situation.
The issue is that the original axiosTest() function isn't returning the promise. Here's an extended explanation for clarity:
function axiosTest() {
// create a promise for the axios request
const promise = axios.get(url)
// using .then, create a new promise which extracts the data
const dataPromise = promise.then((response) => response.data)
// return it
return dataPromise
}
// now we can use that data from the outside!
axiosTest()
.then(data => {
response.json({ message: 'Request received!', data })
})
.catch(err => console.log(err))
The function can be written more succinctly:
function axiosTest() {
return axios.get(url).then(response => response.data)
}
Or with async/await:
async function axiosTest() {
const response = await axios.get(url)
return response.data
}
Guide on using promises
Info on async functions
I know this post is old. But i have seen several attempts of guys trying to answer using async and await but getting it wrong. This should clear it up for any new references
UPDATE: May 2022
This answer is still having lots of interest and have updated it to use arrow functions
const axiosTest = async () {
try {
const {data:response} = await axios.get(url) //use data destructuring to get data from the promise object
return response
}
catch (error) {
console.log(error);
}
}
you can populate the data you want with a simple callback function,
let's say we have a list named lst that we want to populate,
we have a function that pupulates pupulates list,
const lst = [];
const populateData = (data) => {lst.push(data)}
now we can pass the callback function to the function which is making the axios call and we can pupulate the list when we get data from response.
now we make our function that makes the request and pass populateData as a callback function.
function axiosTest (populateData) {
axios.get(url)
.then(function(response){
populateData(response.data);
})
.catch(function(error){
console.log(error);
});
}
The axios library creates a Promise() object. Promise is a built-in object in JavaScript ES6. When this object is instantiated using the new keyword, it takes a function as an argument. This single function in turn takes two arguments, each of which are also functions — resolve and reject.
Promises execute the client side code and, due to cool Javascript asynchronous flow, could eventually resolve one or two things, that resolution (generally considered to be a semantically equivalent to a Promise's success), or that rejection (widely considered to be an erroneous resolution). For instance, we can hold a reference to some Promise object which comprises a function that will eventually return a response object (that would be contained in the Promise object). So one way we could use such a promise is wait for the promise to resolve to some kind of response.
You might raise we don't want to be waiting seconds or so for our API to return a call! We want our UI to be able to do things while waiting for the API response. Failing that we would have a very slow user interface. So how do we handle this problem?
Well a Promise is asynchronous. In a standard implementation of engines responsible for executing Javascript code (such as Node, or the common browser) it will resolve in another process while we don't know in advance what the result of the promise will be. A usual strategy is to then send our functions (i.e. a React setState function for a class) to the promise, resolved depending on some kind of condition (dependent on our choice of library). This will result in our local Javascript objects being updated based on promise resolution. So instead of getters and setters (in traditional OOP) you can think of functions that you might send to your asynchronous methods.
I'll use Fetch in this example so you can try to understand what's going on in the promise and see if you can replicate my ideas within your axios code. Fetch is basically similar to axios without the innate JSON conversion, and has a different flow for resolving promises (which you should refer to the axios documentation to learn).
GetCache.js
const base_endpoint = BaseEndpoint + "cache/";
// Default function is going to take a selection, date, and a callback to execute.
// We're going to call the base endpoint and selection string passed to the original function.
// This will make our endpoint.
export default (selection, date, callback) => {
fetch(base_endpoint + selection + "/" + date)
// If the response is not within a 500 (according to Fetch docs) our promise object
// will _eventually_ resolve to a response.
.then(res => {
// Lets check the status of the response to make sure it's good.
if (res.status >= 400 && res.status < 600) {
throw new Error("Bad response");
}
// Let's also check the headers to make sure that the server "reckons" its serving
//up json
if (!res.headers.get("content-type").includes("application/json")) {
throw new TypeError("Response not JSON");
}
return res.json();
})
// Fulfilling these conditions lets return the data. But how do we get it out of the promise?
.then(data => {
// Using the function we passed to our original function silly! Since we've error
// handled above, we're ready to pass the response data as a callback.
callback(data);
})
// Fetch's promise will throw an error by default if the webserver returns a 500
// response (as notified by the response code in the HTTP header).
.catch(err => console.error(err));
};
Now we've written our GetCache method, lets see what it looks like to update a React component's state as an example...
Some React Component.jsx
// Make sure you import GetCache from GetCache.js!
resolveData() {
const { mySelection, date } = this.state; // We could also use props or pass to the function to acquire our selection and date.
const setData = data => {
this.setState({
data: data,
loading: false
// We could set loading to true and display a wee spinner
// while waiting for our response data,
// or rely on the local state of data being null.
});
};
GetCache("mySelelection", date, setData);
}
Ultimately, you don't "return" data as such, I mean you can but it's more idiomatic to change your way of thinking... Now we are sending data to asynchronous methods.
Happy Coding!
axiosTest() needs to return axios.get, which in turn returns a Promise.
From there, then can be used to execute a function when said Promise resolves.
See Promise for more info.
Alternatively, await can be used from within the scope of some async function.
// Dummy Url.
const url = 'https://jsonplaceholder.typicode.com/posts/1'
// Axios Test.
const axiosTest = axios.get
// Axios Test Data.
axiosTest(url).then(function(axiosTestResult) {
console.log('response.JSON:', {
message: 'Request received',
data: axiosTestResult.data
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.js"></script>
IMO extremely important rule of thumb for your client side js code is to keep separated the data handling and ui building logic into different funcs, which is also valid for axios data fetching ... in this way your control flow and error handlings will be much more simple and easier to manage, as it could be seen from this
ok fetch
and this
NOK fetch
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
function getUrlParams (){
var url_params = new URLSearchParams();
if( window.location.toString().indexOf("?") != -1) {
var href_part = window.location.search.split('?')[1]
href_part.replace(/([^=&]+)=([^&]*)/g,
function(m, key, value) {
var attr = decodeURIComponent(key)
var val = decodeURIComponent(value)
url_params.append(attr,val);
});
}
// for(var pair of url_params.entries()) { consolas.log(pair[0]+ '->'+ pair[1]); }
return url_params ;
}
function getServerData (url, urlParams ){
if ( typeof url_params == "undefined" ) { urlParams = getUrlParams() }
return axios.get(url , { params: urlParams } )
.then(response => {
return response ;
})
.catch(function(error) {
console.error ( error )
return error.response;
})
}
// Action !!!
getServerData(url , url_params)
.then( response => {
if ( response.status === 204 ) {
var warningMsg = response.statusText
console.warn ( warningMsg )
return
} else if ( response.status === 404 || response.status === 400) {
var errorMsg = response.statusText // + ": " + response.data.msg // this is my api
console.error( errorMsg )
return ;
} else {
var data = response.data
var dataType = (typeof data)
if ( dataType === 'undefined' ) {
var msg = 'unexpected error occurred while fetching data !!!'
// pass here to the ui change method the msg aka
// showMyMsg ( msg , "error")
} else {
var items = data.dat // obs this is my api aka "dat" attribute - that is whatever happens to be your json key to get the data from
// call here the ui building method
// BuildList ( items )
}
return
}
})
</script>
After 6 hours of fluttering, I realized it was a one-line problem. If you are interfering with the axios life-cycle, you may have forgotten this line:
componentDidMount() {
this.requestInterceptor = axios.interceptors.request.use((request) => {
this.updateApiCallFor(request.url, true);
return request;
});
this.responseInterceptor = axios.interceptors.response.use((response) => {
this.updateApiCallFor(response.config.url, false);
return response; // THIS LINE IS IMPORTANT !
}, (error) => {
this.updateApiCallFor(error.config.url, false);
throw error;
});
async makes a function return a Promise
await makes a function wait for a Promise
code async/await
// https://www.npmjs.com/package/axios
const axios = require('axios')
/* --- */
async function axiosTest() {
let promiseAxios = axios.get( 'https://example.com' )
/* --- */
console.log( await promiseAxios )
}
/* --- */
axiosTest()
replit.com Stackoverflow - Returning data from Axios API
replit.com Stackoverflow - How to return values from async
code async/await with return
// https://www.npmjs.com/package/axios
const axios = require('axios')
/* --- */
async function axiosTest() {
console.log( await promiseAxios() )
}
/* --- */
axiosTest()
/* --- */
// create function for promise axios and return it
function promiseAxios() {
return axios.get( 'https://example.com' )
}
replit.com Stackoverflow - Returning data from Axios API - return
replit.com Stackoverflow - How to return values from async - return
Try this,
function axiosTest() {
axios.get(url)
.then(response => response.data)
.catch(error => error);
}
async function getResponse () {
const response = await axiosTest();
console.log(response);
}
getResponse()
It works, but each function where you want to get the response needs to be an async function or use an additional .then() callback.
function axiosTest() {
axios.get(url)
.then(response => response.data)
.catch(error => error);
}
async function getResponse () {
axiosTest().then(response => {
console.log(response)
});
}
getResponse()
If anyone knows a way to avoid this please do tell.
Also checkout Katsiaryna (Kate) Lupachova's article on Dev.to. I think it will help.
async handleResponse(){
const result = await this.axiosTest();
}
async axiosTest () {
return await axios.get(url)
.then(function (response) {
console.log(response.data);
return response.data;})
.catch(function (error) {
console.log(error);
});
}
You can find check https://flaviocopes.com/axios/#post-requests url and find some relevant information in the GET section of this post.
You can use Async - Await:
async function axiosTest() {
const response = await axios.get(url);
const data = await response.json();
}

Categories

Resources