I am doing a simple API call in a function. The API Response is fine in Postman it 280 ms to 340 ms. but in my Application it taks 5 to 10 mins. Here is my function.
const getSuggestions = async query => {
const filterToken = query.toLowerCase();
if (query.length < 3) {
setLoading(false);
return;
}
setLoading(true);
var myHeaders = new Headers();
myHeaders.append(
'Authorization',
'Basic xyzxyzxyzxyzxyzyzyzyzy',
);
myHeaders.append('Content-Type', 'application/json');
var raw = JSON.stringify({
query: filterToken,
language: 'en',
});
const requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw,
redirect: 'follow',
};
fetch(
'https://api.worldota.net/api/b2b/v3/search/multicomplete/',
requestOptions,
)
.then(response => response.json())
.then(response => {
const sections = [];
Object.keys(response.data).map((item, i) => {
sections.push({
title: item,
data: response.data[item],
});
});
setSuggestionsList(sections);
setLoading(false);
})
.catch(err => {
console.log(err);
setLoading(false);
});
};
when ever my search params are changed then i call this function. whats is the problem with my function. it was working fine last day. :(
Related
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?
Okay, I am still new in Javascript. As per title, how to fetch a single API url but with 4 different parameters. My goal is to display 4 different categories as the result
Example (I have 4 different categories):
const category = [1,2,3,4];
I want to make each category calls for an api
Method 1
To call category 1:
const url = 'http://www.myapiurl.com/thisapi';
const parameter = {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `USERID=userid&TOKEN=usertoken&CATEGORY=1`
};
fetch(url, options)
.then(response => response.json())
.then(object => {})
To call category 2:
const url = 'http://www.myapiurl.com/thisapi';
const parameter = {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `USERID=userid&TOKEN=usertoken&CATEGORY=2`
};
fetch(url, options)
.then(response => response.json())
.then(object => {})
To call category 3:
const url = 'http://www.myapiurl.com/thisapi';
const parameter = {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `USERID=userid&TOKEN=usertoken&CATEGORY=3`
};
fetch(url, options)
.then(response => response.json())
.then(object => {})
To call category 4:
const url = 'http://www.myapiurl.com/thisapi';
const parameter = {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `USERID=userid&TOKEN=usertoken&CATEGORY=4`
};
fetch(url, options)
.then(response => response.json())
.then(object => {})
Or maybe I can simplify them a bit like this:
Method 2
const parameter1 = {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `USERID=userid&TOKEN=usertoken&CATEGORY=1`
};
const parameter2 = {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `USERID=userid&TOKEN=usertoken&CATEGORY=2`
};
const parameter3 = {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `USERID=userid&TOKEN=usertoken&CATEGORY=3`
};
const parameter4 = {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `USERID=userid&TOKEN=usertoken&CATEGORY=4`
};
Promise.all([
fetch(url,parameter1).then(value => value.json()),
fetch(url,parameter2).then(value => value.json()),
fetch(url,parameter3).then(value => value.json()),
fetch(url,parameter4).then(value => value.json()),
])
.then((value) => {
console.log(value)
//json response
})
.catch((err) => {
console.log(err);
});
But all of these are very redundant and uneccesarry repetition. What if I have 50 categories? How do I simplify all of these Fetch API calls? Please give me an enlightment. Thanks in advance
You can take it a step further. Since your method, headers and part of the body are all identical, just extract that to one function. Custom-build the parameters to the category, then call fetch.
const thatPostFunction = category => {
const method = 'POST'
const headers = { 'Content-Type': 'application/x-www-form-urlencoded' }
const body = `USERID=userid&TOKEN=usertoken&CATEGORY=${category}`
return fetch(url, { method, headers, body })
}
const categories = [...category ids...]
const promises = categories.map(c => thatPostFunction(c))
Promise.all(promises)
.then((value) => {
console.log(value)
//json response
})
.catch((err) => {
console.log(err);
});
I would write a function to convert a category id to a Promise, and then write a wrapper function to convert an array of category ids to a Promise resolving to an array of fetch results:
const fetchCategory = (catId) => {
const url = 'http://www.myapiurl.com/thisapi';
const options = {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `USERID=userid&TOKEN=usertoken&CATEGORY=${catId}`
};
return fetch(url, options)
.then(response => response.json())
}
const fetchCategories = (categories) => Promise.all(categories.map(fetchCategory))
const categories = [1, 2, 3, 4]
fetchCategories(categories).then(categoryResults => {
// here categoryResults is an array of the fetch results for each category.
console.log(categoryResults)
})
<script>
// Faking out fetch for testing
const fetch = (url, opts) => Promise.resolve({
json: () => ({
categoryId: `${opts.body.slice(opts.body.lastIndexOf('=') + 1)}`,
more: 'here'
})
})
</script>
You can just create a function that runs all of them:
const categories = [1,2,3,4];
const postUrls = (items) => {
const promises = []
items.forEach(item => {
const url = 'http://www.myapiurl.com/thisapi';
const options = {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `USERID=userid&TOKEN=usertoken&CATEGORY=${item}`
};
const prms = fetch(url, options)
.then(response => response.json())
promises.push(prms)
})
return Promise.all(promises)
}
postUrls(categories)
.then(data => console.log('Done!'))
If your API is flexible then you may be able to ask for all 4 categories at the same time. I have seen APIs do it like this:
body: `USERID=userid&TOKEN=usertoken&CATEGORY=1,2,3,4`
And I have seen them do it like this:
body: `USERID=userid&TOKEN=usertoken&CATEGORY=1&CATEGORY=2&CATEGORY=3&CATEGORY=4`
Again, your API would need to be able to enumerate through the categories and return the results in some kind of object or array.
I am trying to fetch multiple requests in an order in React. There are 3 requests,
first one gathering encoded information from backend
get token from authentication server
use api with the token.
All of them must be in order. But I am having difficulties because of async fetch function. I can't reach fetch's response outside of .then() block.
To solve it, I used await / async. But it caused another problem. My 3 requests must be in a sequencial order. When I use async, order gets broken.
Here is the code.
class App extends Component {
constructor() {
super();
this.state = { code: '', encoded: '', access_token: '', refresh_token: '' };
}
getCarDetails() {
const carId = '2F3A228F6F66AEA580'
var query = 'https://api.mercedes-benz.com/experimental/connectedvehicle/v1/vehicles/'.concat(carId).concat('/doors')
fetch(query, {
method: 'GET',
headers: {
'Authorization': 'Bearer '.concat(this.state.access_token),
'accept': 'application/json'
}
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.log(err));
}
getToken() {
var post_data = {
grant_type: 'authorization_code',
code: this.state.code,
redirect_uri: 'http://localhost'
}
fetch('https://api.secure.mercedes-benz.com/oidc10/auth/oauth/v2/token', {
method: 'POST',
headers: new Headers({
'Authorization': 'Basic '.concat(this.state.encoded),
'Content-Type': 'application/x-www-form-urlencoded'
}),
body: queryString.stringify(post_data)
})
.then(res => res.json())
.then(data => this.setState({ access_token: data.access_token, refresh_token: data.refresh_token }))
.catch(err => console.log(err));
}
getEncodedClientIdAndClientSecret() {
if (this.state.code != null) {
fetch('http://localhost:8000/encodeClientIdAndSecret', {
method: 'POST'
})
.then(res => res.json())
.then(data => this.setState({ encoded: data.encoded }))
.catch(err => console.log(err));
}
}
componentDidMount() {
const values = queryString.parse(this.props.location.search)
this.setState({ code: values.code })
console.log(this.state)
this.getEncodedClientIdAndClientSecret();
console.log(this.state) //this state is empty
//this.getToken();
//this.getCarDetails();
}
AWAIT / ASYNC
async getEncodedClientIdAndClientSecret() {
if (this.state.code != null) {
const response = await fetch('http://localhost:8000/encodeClientIdAndSecret', {
method: 'POST'
})
const data = await response.json();
console.log(data)
}
}
If I put await / async, I am having sequence problem between 3 requests.
in order to use async await on methods like
await getEncodedClientIdAndClientSecret();
await getToken();
you need to first return a promise from those functions like:
getToken() {
var post_data = {
grant_type: 'authorization_code',
code: this.state.code,
redirect_uri: 'http://localhost'
}
return fetch('https://api.secure.mercedes-benz.com/oidc10/auth/oauth/v2/token', {
method: 'POST',
headers: new Headers({
'Authorization': 'Basic '.concat(this.state.encoded),
'Content-Type': 'application/x-www-form-urlencoded'
}),
body: queryString.stringify(post_data)
})
.then(res => res.json())
.then(data => this.setState({ access_token: data.access_token, refresh_token: data.refresh_token }))
.catch(err => console.log(err));
}
so it can wait for the promise to finish, othewise they will run in parallel and finish in random order.
I tried fetch to call api and passing credentials "include" to header which set cookies from server initially but on page refresh cookies got lost.
public post = async (payload:any, endpoint: string):Promise<any> => {
return new Promise((resolve, reject) => {
console.log(${config.baseUrl}${endpoint})
const URL = ${config.baseUrl}${endpoint};
fetch(URL, {
credentials: 'include',
method: 'POST',
body: JSON.stringify(payload),
headers: new Headers({
'Content-Type': 'application/json'
})
})
.then(data => data.json())
.then((data:any) => {
console.log("data", data)
const responsePayload = {
statusCode: data.status,
data: data
};
resolve(responsePayload);
})
.catch((error:any) => {
if (error.response === undefined) {
const errorpayload = {
statusCode: 503,
title: 'network error occured',
parameter: 'Network Error',
};
reject(errorpayload);
} else {
const errors = error.response.data.errors;
const errorPayload = {
statusCode: error.response.status,
data: error.response.data.errors,
};
reject(errorPayload);
}
});
});
};
Better read cookies on login and store it to loaclstorage and from there you can use it the way you want.
I am trying to fetch data from a Socrata API and then post it to my own database. When I run the function in node, I get the error "ReferenceError: fetch is not defined"
I am totally lost, and am wondering how to pull this off. I have been googling for the past four hours, and can't find anything.
My code:
const apiURL = "https://ftbserver.herokuapp.com/npos"
const soda = require('soda-js');
var consumer = new soda.Consumer('data.colorado.gov');
let stuff
consumer.query()
.withDataset('p3jp-z4tq')
.limit(2)
.where({ principalcity: 'Denver' })
// .order('namelast')
.getRows()
.on('success', function (rows) {
rows.map((nposNew) => {
let data = {
fein: nposNew.fein,
name: nposNew.name,
revenuetotal: nposNew.revenuetotal,
expensestotal: nposNew.expensestotal
}
fetch(apiURL, {
method: 'POST',
headers: new Headers({
'Content-Type': 'application/json'
}),
body: JSON.stringify(data)
})
.then(response => response.json())
.then(response => {
showSuccess(response.message)
setTimeout(() => (removeMsg()), 4000);
})
.catch(console.error);
})
})
.on('error', function (error) { console.error(error); });
// console.log(stuff);
// console.log(npost);