I'm currently developing a webapp in Vuejs. I created a Mixin that I can access globally which handles any request to my api:
export default {
data() {
return {
apiURL: 'http://example.com/api',
timeout: 10000,
};
},
methods: {
callAPI(method, url, body) {
this.$http({
url: this.apiURL + url,
method,
body,
timeout: this.timeout,
})
.then((response) =>
response,
(response) => {
if (response.data.error) {
this.error = response.data.error;
} else {
this.error = 'We can\'t connect to the server. Please try again in a few minutes.';
}
return response;
});
// return 'test';
},
},
};
Now, in some of my components I call the api function:
const api_response = this.callAPI('POST', '/auth', credentials);
alert (api_response);
It works fine, but one thing doesn't work as expected. I expect my api_response constant to have the value of response but it is always undefined. So every time I got this alert with undefined. How is that possible? When I uncomment the return 'test' line it works: I got an alert with test, but it doesn't seem to work within the this.$http part...
Your callAPI has no return statement, so it returns undefined. If it returned your $http call, it still would not give you response, but would be a Promise, so you would want to do something like
let api_response;
this.callAPI('POST', '/auth', credentials).then((response) => api_response = response);
Related
I am trying to implement the following logic: call login then if response is ok, call method for retrieving user data.
Login action
loginUser({commit,dispatch}, credentials) {
const form = new URLSearchParams();
form.append("login", credentials.login);
form.append("password", credentials.password);
const formConfig = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
};
return Axios.post(loginUrl, form, formConfig).then(
(response) => {
commit('setErrorMessage', '', {root: true});
commit('setAuthenticated', response.headers[authorization]);
dispatch('getUserByLoginAuth',credentials.login);
},
(error) => {
if (error.response.status===500){
commit('setErrorMessage', error.response.data.message, {root: true});
} else {
commit('setErrorMessage', error.response.data, {root: true});
}
});
},
The second action dispatched from the one above:
getUserByLoginAuth({commit, getters}, login) {
return getters.authenticatedAxios.get(userUrl + '/find', {
params: {
login: login
}
}).then(
(response) => {
commit('setErrorMessage', '', {root: true});
commit('setUser', response.data);
},
(error) => {
commit('setErrorMessage', error.response.data, {root: true});
});
},
This action is called from the second time only(as I understand it is related to promise).
Here is a code from component which dispatches login action
this.$store.dispatch('loginUser', this.credentials).then(() => {
this.errorMessage = this.getError;
if (this.errorMessage.length) {
this.errorOccurred = true;
}
this.$router.push({path: '/user/' + this.getId});
});
this.errorOccurred = false;
},
Here also I am not sure if I am doing routing in correct place. As I understand then will work with promise from getUser so errorMessage from login might be lost. I would like to prevent it and make dispatch of getUser correctly from the first time
I don't entirely follow what you're asking but this seems likely to be a problem:
dispatch('getUserByLoginAuth',credentials.login);
The problem isn't the call itself. The problem is that it's kicking off a new asynchronous action without chaining it onto the existing promises. From the perspective of loginUser everything is done, it won't wait for getUserByLoginAuth.
The result will be that the then in your component will be called before getUserByLoginAuth is done. I would imagine this is why it seems to work the second time, because it's picking up the relevant data from the previous call.
The solution would be simply to change it to:
return dispatch('getUserByLoginAuth',credentials.login);
By putting in a return it adds it to the promise chain, so loginUser won't be treated as complete until getUserByLoginAuth is done.
I've read all the related questions and watched the Firebase videos re Promises and I still can't get rid of the above error. The attached code runs fine locally, yet when done from cloud functions I keep on getting this error. Any help would appreciated!
exports.enquiry = functions.firestore.document('users/{userId}/enquiries/{enquiryId}')
.onCreate((snap, context) => {
let enquiryDoc = snap.data();
let {
uid,
type
} = enquiryDoc;
function ResponseGeneration(type) {
switch (type) {
case 'type1':
{
Response = 5;
return Promise.resolve(Response);
}
case 'type2':
{
var body = `<QUOTA><DATE>20181203</DATE></QUOTA>`;
const call = request.post({
url: "xxx",
port: 443,
method: "POST",
headers: {
'Content-Type': 'text/xml',
},
body: body,
json: false
})
.then((parsedBody) => {
console.log(parsedBody.statusCode);
console.log(parsedBody);
return xml2js(parsedBody);
})
.then((js) => {
console.log('JSON.stringify(js):', JSON.stringify(js));
var json = JSON.stringify(js);
var jsonParsed = JSON.parse(json);
if (jsonParsed.hasOwnProperty('Error')) {
Response = jsonParsed['Error']['Message'];
} else {
Response = jsonParsed['RESULT'];
}
console.log("Response: ", Response);
return Promise.resolve(Response);
}).catch(function(err) {
console.log("error from post:", err);
// return Promise.resolve(err);
});
return Promise.all(call); //also tried with Promise.resolve
}
default:
return Promise.resolve(0.0);
}
}
ResponseGeneration(type).then((response) => {
return snap.ref.update({
quote: response,
status: 'quoted',
quoteId: context.params.enquiryId
});
});
});
As you can see, it returns Promises everywhere, yet Firestore console keeps printing:
Function returned undefined, expected Promise or value
I'm not quite seeing where else it might be missing a promise. Any help?
Your top level function called by onCreate() isn't returning anything, thus the error.
You need to return the Promise from your call to ResponseGeneration:
return ResponseGeneration(type).then((response) => {
return snap.ref.update({
quote: response,
status: 'quoted',
quoteId: context.params.enquiryId
});
});
I am trying to increase the timeout time of my React app. I am using axios, so initially I tried:
axios.post('/gene_info', postData, {timeout: timeoutVal});
It did not work, and there is the respective thread that deals with it:
https://github.com/axios/axios/issues/647
So, I tried the following code:
let CancelToken = axios.CancelToken;
const source = CancelToken.source();
try {
let response = null;
setTimeout(() => {
if (response === null) {
source.cancel();
}
}, 60 * 1500 * 1000);
response = await axios.post('/gene_info', postData, {cancelToken: source.token});
console.log(response);
} catch (error) {
console.log(error);
}
And it is not working either. The request times out and I see the empty response error, even though on the Node.js backend I see that the result is returned correctly. On the backend I am making a very long running request to Neo4j database. I got a suspicion that maybe it timeouts, so I added to neo4j.config file the following lines:
unsupported.dbms.executiontime_limit.enabled=true
unsupported.dbms.executiontime_limit.time=99999999999999s
That I found here:
How to configure a query timeout in Neo4j 3.0.1
and restarted neo4j but it did not help either. Here is what I see in the terminal:
I am not sure what this POST /gene_info - - ms - - means, whether the problem is still on the front end, or the back end, but I have a suspicion that neo4j now times out, but it is still calculating the result which I see using console.log() statements. Any suggestions would be greatly appreciated.
Update
I tried using Reacts fetch, but still not working. Here is the code:
fetchWithTimeout = (url, postData, timeout) => {
let didTimeOut = false;
new Promise(function(resolve, reject) {
const timeout = setTimeout(function() {
didTimeOut = true;
reject(new Error('Request timed out'));
}, timeout);
fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
timeout: timeout,
body: JSON.stringify(postData)
})
.then(function(response) {
// Clear the timeout as cleanup
clearTimeout(timeout);
if(!didTimeOut) {
console.log('fetch good! ', response);
resolve(response);
}
})
.catch(function(err) {
console.log('fetch failed! ', err);
// Rejection already happened with setTimeout
if(didTimeOut) return;
// Reject with error
reject(err);
});
})
.then(function() {
// Request success and no timeout
console.log('good promise, no timeout! ');
})
.catch(function(err) {
// Error: response error, request timeout or runtime error
console.log('promise error! ', err);
});
}
Then I am calling this function like that:
let postData = {"jsonData": geneNameArr,
"datasetName": this.props.datasetName};
this.fetchWithTimeout('/gene_info', postData, timeout).then((response) => {
console.log("fetchWithTimeout is done!");
console.log(response);
});
Update
I tried using axios.create() function with no success:
const axiosInstance = axios.create({
baseURL: '/gene_info',
timeout: timeout
});
axiosInstance.post('', postData).then((response) => {
console.log("axios request is done with create() method");
console.log(response);
});
If nothing seems to work on the front end, I would think it is the timeout that comes from the neo4j driver, even though somehow the results are returned. Here is the code I am using for the driver:
router.post('/gene_info', function(req, res) {
...
...
var driver = dbUtils.driver;
const session = driver.session();
session.run(
full_query,
{}
).then(result => {
const exprData = chartService.prepareGeneInfoData(result, '');
res.json({
exprData
});
session.close();
});
})
Or maybe it can also be express.Router(); that I am using for treating get and post requests on the backend with Node.js
If you want to configure your timeout in axios, you can use,
const axiosInstance = axios.create({
baseURL: "http://example.com/api/",
timeout: 5000
});
Replace 5000 with your timeout value needed.
Ultimately I found the solution that worked here:
Node Express specific timeout value per route
And I used the setConnectionTimeout() function in the following way:
router.post('/gene_info', setConnectionTimeout('12h'), function(req, res) {
...
})
I have a search of weather for some cities. I would like to create info modal when a user tries to find a city that is not in the base. In this case I receive 404 error from my API.
I fetch the data every time when user click on search button. I use axios to do it and whole project is based on React and Redux. Everything is clear for me but I have a problem with pass valid response to payload.
How should I do it? In an another file and use react component lifecycle?
action.js
export function fetchWeather(city) {
const url = `${ROOT_URL}&q=${city}`;
axios.get(url)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
return {
type: FETCH_WEATHER,
payload: request
};
}
In your example the return will be called before Axios completes it's API call, because it's asynchronous. One solution to this is to put the return inside the .then like this:
export function fetchWeather(city) {
const url = `${ROOT_URL}&q=${city}`;
axios.get(url)
.then(function (response) {
// won't get called until the API call completes
console.log(response);
return {
type: FETCH_WEATHER,
payload: response.data
};
})
.catch(function (error) {
// won't get called until the API call fails
console.log(error);
return {
type: FETCH_WEATHER_ERROR,
payload: error
};
});
}
You should also return an error in the catch if the API call is unsuccessful.
In your snippet, request will always be undefined because axios.get is an async operation and return happens before axios.get finishes execution. You do something like this:
export async function fetchWeather(city) {
try {
const request = await axios.get(`${ROOT_URL}&q=${city}`);
// server returned a 2XX response (success)
return {
type: FETCH_WEATHER,
payload: request
};
} catch(error) {
// Network failure or 4XX or 5XX response.
return {
type: FETCH_WEATHER_FAIL
payload: error
}
}
}
So I'm trying for multiple ways to get error response status from my axios HTTP call and something weird is happening.
getData() {
axios.get(`/api/article/getObserved.php`, axiosConfig)
.then(response => {
console.log('success');
console.log(response);
})
.catch(err => {
console.log('error');
console.log(err.status);
console.log(err.response.status)
});
}
So I'm calling my getObserved endpoint and although it's returning http_response_code(503); it's going to .then() part because it console log 'success' string.
this is output from console:
GET http://localhost/obiezaca/v2/api/article/getObserved.php 503 (Service Unavailable)
success favouriteArticles.vue?31bd:83
I've done hundreds of calls like this and this .catch was always catching error even tho I'm not throwing exception like in other lenguages I would do. However I also tried like this:
getData() {
axios.get(`/api/article/getObserved.php`, axiosConfig)
.then(response => {
console.log('success');
console.log(response);
}, function (err) {
console.log('error');
console.log(err.status);
console.log(err.response.status);
})
.catch(err => {
console.log('error');
console.log(err.status);
console.log(err.response.status)
});
}
But it still doesn't console 'error' although I have this 503 bad request returned from my endpoint. Why?
I also would like to add that I dont think my endpoint is not working correctly because I was testing it with tests and manually by cURL and POSTMAN and everything was fine.
Edit since response is undefined when I don't get data from my endpoint and I need to handle only one error (there is data or not) I have just do something like this:
getData() {
axios.get(`/api/article/getObserved.php`, axiosConfig)
.then(response => {
if(response) {
this.articles = response.data.records;
} else {
this.noFavourite = true;
this.articles = [];
}
});
and it's working. I'll pray to not get into same issue with some call where I'll need to handle several different errors.
This issue was related to my httpInterceptor
import axios from 'axios';
import { store } from '../store/store';
export default function execute() {
axios.interceptors.request.use(function(config) {
const token = store.state.token;
if(token) {
config.headers.Authorization = `Bearer ${token}`;
//console.log(config);
return config;
} else {
return config;
}
}, function(err) {
return Promise.reject(err);
});
axios.interceptors.response.use((response) => {
return response;
}, (err) => {
console.log(err.response.status)
return Promise.reject(err); // i didn't have this line before
});
}
which wasn't returning promise on error response so after in promise of http call it somehow treated it as success. After adding return Promise.reject(err); inside my interceptor it's working fine