how to import and export asynchronous function on javascript? - javascript

i have this asynchronous function
//example get
async getDatafromAPINODE(url) {
try {
let respond = await axios.get(API_URL_NODE + url, {
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + this.state.tokenUser,
},
});
if (respond.status >= 200 && respond.status < 300) {
console.log("respond Post Data", respond);
}
return respond;
} catch (err) {
let respond = err;
console.log("respond Post Data err", err);
return respond;
}
}
how can i make this function export-able ? so i can use in another file with import

ok this what im doing
//asyncFunction.js
export const getDatafromAPINODE = async (url, props) => {
try {
let respond = await axios.get(API_URL_NODE + url, {
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + props,
},
});
if (respond.status >= 200 && respond.status < 300) {
console.log("respond Post Data", respond);
}
return respond;
} catch (err) {
let respond = err;
console.log("respond Post Data err", err);
return respond;
}
};
then i called using
import {getDatafromAPINODE} from '../../../helper/asyncFunction'
as you can see im using 2 args url and props, the props will be used for getting the token for my need

Related

HTTP function times out when subscribing an FCM token to a topic in Cloud Function

Minimum reproducible code:
index.ts:
import * as admin from "firebase-admin"
import fetch, { Headers } from "node-fetch";
interface BarPayload {
topic: string,
token: string,
}
exports.bar = functions.https.onCall(async (data, context) => {
if (data != null) {
const payload: BarPayload = {
topic: data.topic,
token: data.token,
}
const url = `https://${location}-${project}.cloudfunctions.net/subscribeToTopic`
await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
topic: payload.topic,
token: payload.token,
}),
})
}
return null;
});
export const subscribeToTopic = functions.https.onRequest(async (req, res) => {
const payload = req.body as BarPayload;
fetch('https://iid.googleapis.com/iid/v1/' + payload.token + '/rel/topics/' + payload.topic, {
method: 'POST',
headers: new Headers({
'Authorization': 'key=AA...Wp9',
'Content-Type': 'application/json'
})
}).then(response => {
if (response.status < 200 || response.status >= 400) {
res.sendStatus(299)
}
}).catch(error => {
console.error(error);
res.sendStatus(299)
})
return Promise.resolve();
})
I'm running bar in Flutter and I see the timeout error in Logs Explorer:
textPayload: "Function execution took 60051 ms. Finished with status: timeout"
But if I change my subscribeToTopic from HTTP function to a callable function, then it works fine. For example:
exports.subscribeToTopic = functions.https.onCall(async (data, context) => {
fetch('https://iid.googleapis.com/iid/v1/' + data.token + '/rel/topics/' + data.topic, {
method: 'POST',
headers: new Headers({
'Authorization': 'key=AA...Wp9',
'Content-Type': 'application/json'
})
}).then(response => {
if (response.status < 200 || response.status >= 400) {
console.log('Error = ' + response.error);
}
}).catch(error => {
console.error(error);
})
return null;
});
(I know I'm making some trivial mistake, and I'm new to Typescript. Any help would be appreciated :)
You should not do return Promise.resolve(); in the HTTPS Cloud Function:
HTTPS Cloud Functions shall be terminated with with send(), redirect() or end();
return Promise.resolve(); is executed before the asynchronous call to fetch is complete.
The following should do the trick (untested):
export const subscribeToTopic = functions.https.onRequest(async (req, res) => {
try {
const payload = req.body as BarPayload;
const response = await fetch('https://iid.googleapis.com/iid/v1/' + payload.token + '/rel/topics/' + payload.topic, {
method: 'POST',
headers: new Headers({
'Authorization': 'key=AA...Wp9',
'Content-Type': 'application/json'
})
});
if(response.status < 200 || response.status >= 400) {
res.status(299).send();
}
} catch (error) {
res.status(400).send();
}
})
However I don't understand why you separate your business logic in two Cloud Functions. Why don't you directly fetch https://iid.googleapis.com within the bar Callable Cloud Function?

EXPO React Native - AXIOS + FORMDATA PROBLEM

i have an issue with POST request inside my app.
part of code :
if (imagesResults !== undefined) {
imagesResults.forEach((el) => {
let localUri = el.uri;
let filename = localUri.split("/").pop();
let match = /\.(\w+)$/.exec(filename);
let type = match ? `image/${match[1]}` : `image`;
formData.append("saleImages[]", {
uri: localUri,
name: filename,
type: type,
});
});
}
console.log("FORMDATA", formData);
const axiosConfig = {
headers: {
Authorization: "Bearer " + user.token,
"content-type": "application/x-www-form-urlencoded",
Accept: "application/json",
},
};
try {
axios
.post(`${API}/sales/${saleId}/edit`, formData, axiosConfig)
.then((res) => {
// console.log("RES", JSON.stringify(res.data));
bottomSheetRef.current.snapToIndex(0);
setTimeout(() => {
bottomSheetRef.current.close();
dispatch(setLoadingApiAction(false));
navigation.navigate("My Ads");
}, 3000);
})
.catch((err) => {
console.log("error", err);
// setErrors(err.response.data.errors);
navigation.navigate("My Ads");
alert("SOMETHING IS WRONG!");
dispatch(setLoadingApiAction(false));
});
} catch (error) {
console.log("ERROR CATCH", error);
dispatch(setLoadingApiAction(false));
}
};
so what is happening, i fire my API, and i get 200 but just after i get 200 it return me also a network error and goes into .catch part.
This is only happening in ANDROID DEVICE , IOS working totally fine.
I am using a HTTPS , also i tried to set type of the image hardcoded into "image/jpeg" but i got the same problem.

How to wait until request.get finish then conduct the next block in node.js

I am new to NodeJS and I am working on a request.get problem. My goal is simply have a function that request the web, and when request finished, the function returns the result, otherwise it returns an error message.
Here's the function that I used for request:
var artistNameIdMap = {};
var getPopularArtists = async () => {
//https://nodejs.org/api/http.html#http_http_request_options_callback
var options = {
url: CONSTANTS.API_ENDPOINTS.playlist_endpoint + subpath,
headers: { 'Authorization': 'Bearer ' + access_token,
'Accept': 'application/json',
'Content-Type': 'application/json'},
json: true
}
request.get(options, function(error, response, body) {
if (response.statusCode === 200){
console.log("inside");
artistNameIdMap = getArtistNameIdMap(body, artistNameIdMap);
} else {
res.send("get popular error");
return {};
}
})
console.log("outside");
return artistNameIdMap;
module.exports = {
GetPopularArtists: getPopularArtists
}
And this function is included in a getPopular.js file. I would like to call the function in another file playlist.js.
In playlist.js, I wrote
const getPopular = require('./controllers/getPopular');
router.get("/BPM/:BPM", (req, res) =>{
const artistNameIdMap = getPopular.GetPopularArtists();
console.log(artistNameIdMap);
let BPM = req.params.BPM;
res.send(BPM);
})
However the result I got is
outside
Promise { {} }
inside
It seems like the return was before the request gives back the information. I wonder what should I write to make sure that I can obtain the correct artistNameIdMap at playlist.js.
Though you've already accepted an answer, there are a couple of additional things I can add. First, the request() library has been deprecated and it is not recommended for new code. Second, there is a list of recommended alternatives here. Third, all these alternatives support promises natively as that is the preferred way to program asynchronous code in modern nodejs programming.
My favorite alternative is got() because I find it's interface simple and clean to use and it has the features I need. Here's how much simpler your code would be using got():
const got = require('got');
let artistNameIdMap = {};
async function getPopularArtists() {
const options = {
headers: { 'Authorization': 'Bearer ' + access_token,
'Accept': 'application/json',
'Content-Type': 'application/json'},
};
const url = CONSTANTS.API_ENDPOINTS.playlist_endpoint + subpath;
let results = await got(url, options).json();
// update local cache object
artistNameIdMap = getArtistNameIdMap(results, artistNameIdMap);
return artistNameIdMap;
}
module.exports = {
GetPopularArtists: getPopularArtists
}
Note: The caller should supply error handling based on the returned promise.
GetPopularArtists().then(results => {
console.log(results);
}).catch(err => {
console.log(err);
});
Since you want to use Promises, use it like this
const getPopularArtists = () => new Promise((resolve, reject) {
const options = {
url: CONSTANTS.API_ENDPOINTS.playlist_endpoint + subpath,
headers: {
'Authorization': 'Bearer ' + access_token,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
json: true
}
request.get(options, (error, response, body) => {
if (error) {
reject(error);
} else if (response.statusCode === 200) {
console.log("inside");
resolve(getArtistNameIdMap(body, artistNameIdMap));
} else {
reject("get popular error");
}
});
});
module.exports = {
GetPopularArtists: getPopularArtists
}
And use it like
const getPopular = require('./controllers/getPopular');
router.get("/BPM/:BPM", async (req, res) =>{
try {
const artistNameIdMap = await getPopular.GetPopularArtists();
console.log(artistNameIdMap);
let BPM = req.params.BPM;
res.send(BPM);
} catch(err) {
res.send(err);
}
})
Alternatively, without promises, you'll need to use a callback
Using callbacks:
const getPopularArtists = (callback) => {
const options = {
url: CONSTANTS.API_ENDPOINTS.playlist_endpoint + subpath,
headers: { 'Authorization': 'Bearer ' + access_token,
'Accept': 'application/json',
'Content-Type': 'application/json'},
json: true
}
request.get(options, function(error, response, body) {
if (error) {
callback(error);
} else if (response.statusCode === 200){
console.log("inside");
callback(null, getArtistNameIdMap(body, artistNameIdMap));
} else {
callback("get popular error");
}
})
};
module.exports = {
GetPopularArtists: getPopularArtists
}
And use it like:
const getPopular = require('./controllers/getPopular');
router.get("/BPM/:BPM", (req, res) =>{
getPopular.GetPopularArtists((err, artistNameIdMap) => {
if (err) {
// handle error here
} else {
console.log(artistNameIdMap);
let BPM = req.params.BPM;
res.send(BPM);
}
});
});

Node.js Access Values from Anonymous function

Good morning!
I've been struggling to get a specific value returned from my function:
const getFolders = function (PID){
var token = getStoredToken()
request.get({
url: 'https://api.procore.com/vapid/folders',
headers: {
Authorization: "Bearer " + token.access_token
},
json: {
company_id: '12594',
project_id: PID
}
}, function test(err, response, body){
return body
})
// I NEED THE RETURN VALUE OF THE ABOVE FUNCTION HERE SO I CAN ACCESS WHEN CALLING getFolders()
}
Is this possible? If so, how?
Thanks!
Usually there will be three ways dealing with asynchronous stuff:
callback
promise
async/await
callback:
const getFolders = function(PID, callback) {
var token = getStoredToken()
request.get({
url: 'https://api.procore.com/vapid/folders',
headers: {
Authorization: "Bearer " + token.access_token
},
json: {
company_id: '12594',
project_id: PID
}
}, function(err, response, body) {
callback(body)
})
}
getFolders(pid, (v) => {
console.log(v)
})
promise:
const getFolders = function(PID, callback) {
return new Promise((resolve, reject) => {
var token = getStoredToken()
request.get({
url: 'https://api.procore.com/vapid/folders',
headers: {
Authorization: "Bearer " + token.access_token
},
json: {
company_id: '12594',
project_id: PID
}
}, function(err, response, body) {
if (err) {
return reject(err)
}
resolve(body)
})
})
}
getFolders(pid)
.then(v => {
console.log(v)
}).catch(error => {
console.error(error)
})
async/await:
Due to async/await is actually a syntax sugar, the getFolders function is the same as using promise's, the difference is when you call it:
(async function() {
try {
let v = await getFolders(pid)
console.log(v)
} catch(e) {
console.error(e)
}
})()
Not sure if this solve your confusion.
The way you are expecting is wrong, the test function which you have passed to request.get method is a callback function which will execute in asychronous manner , it means whenever your API responds from the server, that callback function will get execute.
So before that you are expecting the response (body) below the request method, which is wrong.
In this case you just have to write some other function to call this get method and in callback function you can easily access that response or just write your code in that test function itself.
like below - :
request.get({
url: 'https://api.procore.com/vapid/folders',
headers: {
Authorization: "Bearer " + token.access_token
},
json: {
company_id: '12594',
project_id: PID
}
}, function test(err, response, body){
// instead of returning body
// use the body here only
let result = body;
// your code here
})
Or the other way -:
const getFolders = function (PID){
var token = getStoredToken();
this.get(function(err, response, body){
// do whatever you want with the response now
updateFolder()
})
}
function get(callback){
request.get({
url: 'https://api.procore.com/vapid/folders',
headers: {
Authorization: "Bearer " + token.access_token
},
json: {
company_id: '12594',
project_id: PID
}
}, callback)
}

Axios multiple request on interceptor

I'm using the library axios in my react app.
I'm having a problem with the interceptor.
My question is let say I have three requests happening concurrently and I don't have the token, the interceptor calling the getUserRandomToken three time, I want the interceptor will wait until I'm getting the token from the first request and then continue to the others.
P.S. the token he is with an expiration date so I also checking for it and if the expiration date is not valid I need to create a new token.
This is the interceptor:
axios.interceptors.request.use(
config => {
/*I'm getting the token from the local storage
If there is any add it to the header for each request*/
if (tokenExist()) {
config.headers.common["token"] = "...";
return config;
}
/*If there is no token i need to generate it
every time create a random token, this is a axios get request*/
getUserRandomToken()
.then(res => {
/*add the token to the header*/
config.headers.common["token"] = res;
return config;
})
.catch(err => {
console.log(err);
});
},
function(error) {
// Do something with request error
return Promise.reject(error);
}
);
How about singleton object that will handle the token generations? something similar to this:
const tokenGenerator ={
getTokenPromise: null,
token: null,
getToken(){
if (!this.getTokenPromise){
this.getTokenPromise = new Promise(resolve=>{
/*supposed to be a http request*/
if (!this.token){
setTimeout(()=>{
this.token = 'generated';
resolve(this.token);
},0)
}else{
resolve(this.token);
}
})
}
return this.getTokenPromise;
}
you can reference this same object from the interceptors.
see example: JS FIddle
reference: reference
You can return a Promise from interceptor callback to "wait" until promise fullfiles (this will fit your case). Check out this example:
function axiosCall () {
return new Promise((resolve, reject) => {
Axios.post(URL, {apiKey}).then((response) => {
resolve(response.data.message);
}).catch((error) => {
reject(error);
});
});
}
instance.interceptors.request.use((config) => {
return axiosCall().then((tokenResponse) => {
setWebCreds(tokenResponse);
config.headers.Authorization = `Bearer ${tokenResponse}`;
return Promise.resolve(config)
}).catch(error => {
// decide what to do if you can't get your token
})
}, (error) => {
return Promise.reject(error);
});
More details here: https://github.com/axios/axios/issues/754
Following code doing certain tasks:
Update Token on 401
Make a queue of failed requests while the token is refreshing.
Restore the original request after token refreshing.
Once the peculiar request is given 200, remove it from the queue.
Config.js
import axios from 'axios';
import { AsyncStorage } from 'react-native';
import { stateFunctions } from '../../src/sharedcomponent/static';
const APIKit = axios.create({
baseURL: '',
timeout: 10000,
withCredentials: true,
});
const requestArray = [];
// Interceptor for Request
export const setClientToken = token => {
APIKit.interceptors.request.use(
async config => {
console.log('Interceptor calling');
let userToken = await AsyncStorage.getItem('userToken');
userToken = JSON.parse(userToken);
config.headers = {
'Authorization': `Bearer ${userToken}`,
'Accept': 'application/json',
"Content-Type": "application/json",
"Cache-Control": "no-cache",
}
// console.log('caling ' , config)
return config;
},
error => {
Promise.reject(error)
});
};
// Interceptor for Response
APIKit.interceptors.response.use(
function (response) {
if (requestArray.length != 0) {
requestArray.forEach(function (x, i) {
if (response.config.url == x.url) {
requestArray.splice(i, 1);
}
});
}
return response;
},
function (error) {
const originalRequest = error.config;
requestArray.push(originalRequest);
let reqData = "username=" + number + "&password=" + pin + "&grant_type=password" + "&AppType=2" + "&FcmToken=null";
// console.log('error ' , error);
if (error.message === "Request failed with status code 401" || error.statuscode === 401) {
if (!originalRequest._retry) {
originalRequest._retry = true;
return axios({
method: 'post',
url: '/api/login',
data: reqData,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Cache-Control": "no-cache",
}
})
.then(res => {
let response = res.data;
console.log('successfull Login', response)
if (res.data.StatusCode == 200) {
AsyncStorage.setItem('userToken', JSON.stringify(response.access_token));
stateFunctions.UserId = response.UserId;
stateFunctions.CustomerContactID = response.CustomerContactID;
let obj = {
access_token: response.access_token,
token_type: response.token_type,
expires_in: response.expires_in,
UserId: response.UserId,
CustomerContactID: response.CustomerContactID,
Mobile: response.Mobile,
StatusCode: response.StatusCode
}
AsyncStorage.setItem('logindetail', JSON.stringify(obj));
if (requestArray.length != 0) {
requestArray.forEach(x => {
try {
console.log(x, "request Url");
x.headers.Authorization = `Bearer ${response.access_token}`;
x.headers["Content-Type"] = "application/x-www-form-urlencoded";
APIKit.defaults.headers.common["Authorization"] = `Bearer${response.access_token}`;
APIKit(x)
} catch (e) {
console.log(e)
}
});
}
return APIKit(originalRequest);
}
})
.catch(err => {
console.log(err);
});
}
}
return Promise.reject(error);
}
);
export default APIKit;
Home.js
gettingToken = async () => {
let userToken = await AsyncStorage.getItem('userToken');
userToken = JSON.parse(userToken);
await setClientToken(userToken);
}

Categories

Resources