api request returns undefined - rest

maybe is a stupid question but,
when I'm calling api from 'outside' function it always returns undefined,
for example:
actions.js
import axios from 'axios'
export function getProducts() {
axios.get('http://localhost:8000/api/products').then((response) => {
return response;
});
}
and then in a component:
mounted() {
this.products = getProducts();
console.log(this.products);
}
returns undefined
of course when I make a request from component it returns result
mounted() {
axios.get('http://localhost:8000/api/products').then((response) => {
this.products = response;
console.log(this.products);
});
}
Why is this happening and how can I solve this problem?
Thanks

You are returning the response value in the then callback of the axios.get call. However, your getProducts function doesn't return anything.
Simply return the axios.get call:
export function getProducts() {
return axios.get('http://localhost:8000/api/products');
}
Then, the result of getProducts will be the Promise returned by axios.get(). So, you can add a then callback on the result of getProducts and set you this.products that way:
mounted() {
getProducts().then(products => this.products = products);
}

Related

How to use refetch method to send different queries using useQuery in react-query

I'm working with react-query in ReactJS to build a website.
I have the following code, where I fetch some data using useQuery():
const { error, data: movie, status, refetch } = useQuery({
queryKey: 'key1',
queryFn: async () => {
return await Promise.all([
axios.get(`API-1.com/get-some-data`), /*getting some data from api-1 */
axios.get(`API-2.com/get-some-data`), /*getting some data from api-2 */
]).then(([api1, ap2]) => {
return { data1: api1, data2: api2 }
})
}
})
The problem I'm facing is getting somtimes a 404 response from one of the apis, so I need to refetch the data just from the other api that doesn't cause the error.
I tried to use the refetch method inside onError, but it can't be used with parameters.
onError: (error) => {
refetch() /* refetch can't be used with parameters */
},
How can I handle this problem?
I ended up doing the following:
Writing the fetching part in an external function (so I can call the function with parameters)
Adding a try-catch block inside the queryFn to handle the errors
/********* this is the function where I fetch the data. *********/.
/********* with a param that tells me if i'll call API-2 or not *********/
const fetchData = async ({ isDataFoundInApi2 }) => {
return await Promise.all([
axios.get(`API-1.com/get-some-data`),
(!isDataFoundInApi2 && axios.get(`API-2.com/get-some-data`)),
]).then(([api1, api2]) => {
return { data1: api1, data2: api2 }
})
/********* the useQuery where the above method is called *********/
/********* first it sends true as a bool value, then if no *********/
/********* data was found in API-2, it sends false *********/
/********* from `catch` to prevent the fetching from API-2 *********/
const { error, data: movie, status } = useQuery({
queryKey: 'key1',
queryFn: async () => {
try {
return await fetchData({})
} catch (error) {
if (error.response?.status === 404)
return await fetchData({ isDataFoundInApi2: true }) // true means call only the first api
}
},
})

Flow(InferError): Cannot call await with 'axios.get(...)' bound to 'p'

I'm getting some Flow errors using axios.
Cannot call await with 'axios.get(...)' bound to 'p' because:
Either property 'error_message' is missing in 'AxiosXHR'.
Or property 'data' is missing in 'Promise'
Here is my code, with an attempted type annotation. (Same error without the AxiosPromise<Object> annotation.) The error is on axios.get(url).
async handleAddressChange(): AxiosPromise<Object> {
const url = `https://maps.googleapis.com/maps/api/place/autocomplete/json?key=${GoogleMapsApiKey}&input=${this.state.address}`;
try {
const { data, error_message } = await axios.get(url);
if (error_message) throw Error(error_message);
this.setState({
addressPredictions: data.predictions,
showPredictions: true
});
} catch (err) {
console.warn(err);
}
}
Funny thing is that in another file axios gives no Flow problems:
export async function loginWithApi(creds: AuthParams) {
const res = await axios.get(ApiUrls.login, { params: creds });
return res.data;
}
I have import type { AxiosPromise, $AxiosXHR } from "axios"; in my file.
Anyone know how to fix this?
In case of error there will be no error_message in returned payload, but the error goes into the catch block.
Also, the handleAddressChange does not returns AxiosPromise, instead it returns implicit promise, as it defined with async
So, something like this:
async handleAddressChange(): Promise<void> {
const url = `https://maps.googleapis.com/maps/api/place/autocomplete/json?key=${GoogleMapsApiKey}&input=${this.state.address}`;
try {
const { data } = await axios.get(url);
this.setState({
addressPredictions: data.predictions,
showPredictions: true
});
} catch (err: AxiosError) {
new Error(err);
}
}
Might work for you. Note the AxiosError definition.
One extra note is that you can add returned payload into the AxiosPromise generic, i.e.:
type TExpectedLoginResponse = {
ok: boolean,
token: string
}
export async function loginWithApi(creds: AuthParams): AxiosPromise<TExpectedLoginResponse> {
const res = await axios.get(ApiUrls.login, { params: creds });
return res.data; // so now flow knows that res.data is type of TExpectedLoginResponse
}
Hope it helps.

Ionic Storage : Strange behavior?

I try to use the Ionic Storage module to store some values, for example my authentication token :
/**
* Get Token
*/
public get token(): string {
this.storage.get(this.LS_TOKEN).then((val) => {
console.log(val);
this._token.next(val);
console.log( this._token.getValue());
});
return this._token.getValue();
// return 'testtttt';
}
I try multiple things, return directly the value, set the value and return the variable...
But I always got a null, and the thing that is strange is that if I return a string directly it works, when I console.log the val it show the string that I want, but the return is always null..
What am I doing wrong ?
Edit :
In response of the first answer I have tried this :
/**
* Get Token
*/
public get token() {
this.tokenPromise().then(yourToken => {
console.log(yourToken);
return yourToken;
});
}
public tokenPromise() {
return new Promise((resolve, reject) => {
this.storage.get(this.LS_TOKEN).then((val) => {
resolve(val);
}).catch(ex => {
reject(ex);
});
});
}
My problem is the same, in my components when I try to use : console.log(this.sharedService.token);
It's still null
It is not working with your new token() method.
It is still asnychron. Im gonna show you:
public get token() {
return new Promise((resolve, reject)=>{
this.storage.get(this.LS_TOKEN).then((val) => {
resolve(val);
}).catch(ex=>{
reject(ex);
});
});
}
Now you can use your token from the sharedservice like this:
this.sharedService.token.then(token=>{
//use token here;
});
or you can use await, but the function who is calling it, must be async:
async useTokenFromService(){
let token = await this.sharedService.token;
console.log(token);
}
You are getting a Promise from the storage.get() method.
This means it is running asynchron.
You can return Promise.
public get token() {
return new Promise((resolve, reject)=>{
this.storage.get(this.LS_TOKEN).then((val) => {
resolve(val);
}).catch(ex=>{
reject(ex);
});
});
}
And you can receive this with an async function and await the result:
async loadToken(){
let loadedToken = await this.token();
// use your loadedToken here...
}
Or you can use the .then method from the promise like this:
loadToken(){
this.token().then(yourToken=>{
// use the token yourToken here...
});
}

cannot retrieve data from angular http

I'm trying to retrieve data from a collection in my mongodb using http module using the code below,
getPosts() {
return this.http.get('http://localhost:5005/blog/getposts').map(res => {
console.log("mapped result",res);
res.json()
});
}
It fails everytime with a response
Unexpected token < in JSON at position 0
at JSON.parse (<anonymous>)
at Response.webpackJsonp.../../../http/#angular/http.es5.js.Body.json (http.es5.js:797)
at MapSubscriber.project (auth.service.ts:45)
at MapSubscriber.webpackJsonp.../../../../rxjs/operators/map.js.MapSubscriber._next (map.js:79)
at MapSubscriber.webpackJsonp.../../../../rxjs/Subscriber.js.Subscriber.next (Subscriber.js:89)
at XMLHttpRequest.onLoad (http.es5.js:1226)
at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:425)
at Object.onInvokeTask (core.es5.js:3881)
at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:424)
at Zone.webpackJsonp.../../../../zone.js/dist/zone.js.Zone.runTask (zone.js:192)
but when I try it with postman, I'm getting the expected result which is this,
I'm returning the response from the service and subscribing its data from a component like this,
ngOnInit() {
this.auth.getPosts().subscribe(data => {
this.value = data.posts;
console.log("blog component",this.value)
},err => {
console.log(err);
})
}
What am I doing wrong? Any help would be much appreciated
You need to convert the response in map and subscribe to it to get the final JSON response
Updated code would look like this-
getPosts() {
return this.http.get('http://localhost:5005/blog/getposts')
.map(res => res.json())
.subscribe((data: any) => {
//console.log(data);
});
}
I hope this helps. :)
Try returning inside the .map()
getPosts() {
return this.http.get('http://localhost:5005/blog/getposts').map(res => {
console.log("mapped result",res);
return res.json()
});
}
}
or drop the brackets (this gives you an implied return),
getPosts() {
return this.http.get('http://localhost:5005/blog/getposts')
.map(res => res.json() );
}
}

GoogleAuth library loading with promises

I am trying to load google authentication library using promises, but I fail when I try to call gapi.auth2.getAuthInstance() and return it in promise;
Here's how I am doing this:
var loadPlatform = function ($q) {
var deferred = $q.defer(),
platform = document.createElement('script');
platform.src ='https://apis.google.com/js/platform.js';
platform.type = 'text/javascript';
platform.async = true;
platform.defer = true;
platform.onload = deferred.resolve;
platform.onerror = deferred.reject;
document.body.appendChild(platform);
return deferred.promise;
};
//I return this from other function
return loadPlatform($q)
.then(function () {
var deferred = $q.defer();
gapi.load('auth2', function () {
deferred.resolve(gapi.auth2);
});
return deferred.promise;
})
.then(function (auth2) {
//This function retuns Promise
//https://developers.google.com/identity/sign-in/web/reference#gapiauth2initparams
return auth2.init(params);
})
.then(function (GoogleAuth) {
//Here I should have solved GoogleAuth object
});
Everything works until I return auth2.init(params) then browser freezes.
What's happening here?
I just experienced the same issue.
It seems like you can't chain the init() promise of the auth2 object.
I had to wrap around it to avoid the browser freeze.
return new Promise<void>(resolve => {
gapi.auth2.init({
client_id: this._clientId,
scope: 'profile'
}).then(() => resolve());
})
Also it was interesting that I could not apply the resolve function directly.
.then(resolve);
Update
As said above, the returned object of the init() call is not a promise, it is kind of a wrapper and only returns a real promise once you called the .then method
return gapi.auth2.init({
client_id: this._clientId,
scope: 'profile'
}).then();
// Auth2 only returns a promise, when we chained into the PromiseLike object once.