I am trying to fetch 20 random users data from 'https://randomuser.me/api' and in some cases, I get the 503 Service Unavailable error.
I tried to resolve the problem with this kind of code.
async function fetchDriver() {
const driver = await fetch(driverUrl)
.then((response) => {
if (response.status === 200) {
return response.json();
}
if (response.status === 503) {
return fetchDriver();
}
})
.then((data) => console.log(data))
.catch((error) => {
console.log(error);
fetchDriver();
});
return driver;
}
do {
const geoPosition = fetchGeoPosition();
const phoneNumber = fetchPhoneNumber();
const licenseNumber = fetchLicense(3);
const speed = fetchSpeed(60, 200);
const driver = fetchDriver();
const first = driver.name.first;
const last = driver.name.last;
fetchedCars.push({
licenseNumber,
first,
last,
phoneNumber,
geoPosition,
speed,
favorite: false,
more: false,
});
} while (fetchedCars.length < 20);
But console.log(data) in some cases still shows the value of undefined and I just don't know what to do with this.
random user API has a rate limiter. use this to fetch multiple users in one request (for example 20 users):
https://randomuser.me/api/?results=20
check the documentation here
This GitHub thread mentions the rate-limiting and the solution I've included
Related
I'm adding the claim to a user's profile that he or she paid for something, though, after the payment this attribute isn't visible. I'm running the functions on an emulator on a local host.
This is the code I'm using:
If the paypal function has been handled succesfully through paypalHandleOrder, then the function addPaidClaim is invoked.
onApprove: (data, actions) => {
paypalHandleOrder({ orderId: data.orderID }).then(
addPaidClaim(currentUser).then(
alert("THANKS FOR ORDERING!"),
// currentUser.getIdTokenResult().then(idTokenResult => {
// console.log(idTokenResult.claims)
// })
)
.catch((err) => {
return err;
})
);}
addPaidClaim is a firebase cloud function, which goes as follows:
exports.addPaidClaim = functions.https.onCall((data, context) => {
// get user and add custom claim (paid)
return admin.auth().setCustomUserClaims(data.uid, {
paid: true,
}).then(() => {
return {
message: `Success! ${data.email} has paid the course`,
};
}).catch((err) => {
return err;
});
});
I've refreshed the page and checked the user attributes afterwards through console.log on the user to see if the attribute had been added, but this is not the case. I can't find attribute paid inside the idTokenResult object. What should I do? I also find it hard to make sense of what's happening inside the function addPaidClaim. It's not returning an error when I look at the logs on my firebase console, and not much information is given, besides that the function has been invoked.
Okay, I know this question is pretty old. But I found a way just yesterday after 3 days searching over the solution. After we set up a new claim for a new user using, we need to refresh the client's getIdTokenResult(true) in the app. These are the ways I did it in Flutter Dart until a new user with updated claim managed to use it:
FirebaseAuth auth = FirebaseAuth.instance;
Future<Map<String, dynamic>> signInWithGoogle() async {
Map<String, dynamic> output = {};
final googleUser = await googleSignIn.signIn();
if (googleUser == null) {
log("Firebase => Gmail account doesn't exist");
} else {
final googleAuth = await googleUser.authentication;
final credential = GoogleAuthProvider.credential(
idToken: googleAuth.idToken,
accessToken: googleAuth.accessToken,
);
await auth.signInWithCredential(credential).then((values) async {
await userAuth(credential).then((value) =>
value.addAll(output));
});
}
return output;
}
Future<Map<String, dynamic> userAuth (OAuthCredential credential) async {
Map<String, dynamic> output = {};
await auth.currentUser!.reauthenticateWithCredential(credential);
await auth.currentUser!.reload();
await auth.currentUser!.getIdTokenResult().then((result) => {
if(result.claims!.isNotEmpty){
//check your claim here
} else {
//assign log here
}
});
return output;
}
I'm learning React (with hooks) and I encountered a weird issue. Im currently working on Notes Application (from FullStackOpen learn react). My database only accepts notes which content length is greater than 4 characters. In case of invalid note my server catches a ValidationError and returns an error message with status code 401 instead of new note. My goal is to catch this error in frontend and display an error message.
Backend code:
try{
const savedNote = await note.save()
user.notes = user.notes.concat(savedNote._id)
await user.save()
response.json(savedNote.toJSON())
} catch(e) {
//console.log(e.name)
const msg = {error: 'too short!!!'}
//console.log(msg)
return response.status(401).json(msg)
}
Problem appears when I try to receive data at the front side of application. My development console displays Error: Request failed with status code 401 no matter what I do. I can't find a way to enter catch block at front.
Frontend code for communication with server:
const create = async newObject => {
const config = { headers: { Authorization: token } }
const response = await axios.post(baseUrl, newObject, config)
console.log(response.data)
return response.data
}
(...)
const addNote = (event) => {
event.preventDefault()
try{
const noteObject = {
content: newNote,
date: new Date().toISOString(),
important: Math.random() > 0.5
}
noteService
.create(noteObject)
.then(returnedNote => {
setNotes(notes.concat(returnedNote))
setNewNote('')
setErrorMsg('')
setUserNotes(userNotes.concat(returnedNote))
})
} catch (e) {///<----how to get there
setErrorMsg('note too short! minimum 5 characters')
setNewNote('')
setTimeout(() => {
setErrorMsg(null)
}, 5000)
}
}
Some advices would be appreciated.
Solution:
Chaining promises - .catch()
const addNote = (event) => {
event.preventDefault()
const noteObject = {
content: newNote,
date: new Date().toISOString(),
important: Math.random() > 0.5
}
noteService
.create(noteObject)
.then(returnedNote => {
setNotes(notes.concat(returnedNote))
setNewNote('')
setErrorMsg('')
setUserNotes(userNotes.concat(returnedNote))
})
.catch(e => {
setErrorMsg('note too short! minimum 5 characters')
setNewNote('')
setTimeout(() => {
setErrorMsg(null)
}, 5000)
})
}
Put the try, catch block around your api call:
try {
const response = await axios.post(baseUrl, newObject, config)
} catch (e) {
// handle error
}
On another note, I don't recommend using 401 as the invalid status code as that has a reserved meaning of Unauthorized. Use 400 (Bad request) instead. The definitions of status codes: https://httpstatuses.com/
I am having a slightly odd issue, and due to the lack of errors, I am not exactly sure what I am doing wrong. What I am trying to do is on an onCreate event, make an API call, and then update a field on the database if the field is not set to null. Based on my console logs for cloud functions, I can see the API call getting a ok, and everything is working properly, but after about 2-5 minutes, it will update. A few times, it didnt update after 15 mins. What is causing such a slow update?
I have eliminated the gaxios call as the bottleneck simply from the functions logs, and local testing.
Some context: I am on the firebase blaze plan to allow for egress and my dataset isnt really big. I am using gaxios because it is already part of firebase-funcstions npm install.
The code is:
const functions = require('firebase-functions');
const { request } = require('gaxios');
const { parse } = require('url');
exports.getGithubReadme = functions.firestore.document('readmes/{name}').onCreate((snapshot, context) => {
const toolName = context.params.name;
console.log(toolName);
const { name, description, site } = snapshot.data();
console.log(name, description, site);
const parsedUrl = parse(site);
console.log(parsedUrl);
if (description) return;
if (parsedUrl.hostname === 'github.com') {
let githubUrl = `https://api.github.com/repos${parsedUrl.path}/readme`;
request({
method : 'GET',
url : githubUrl
})
.then((res) => {
let { content } = res.data;
return snapshot.ref.update({ description: content });
})
.catch((error) => {
console.log(error);
return null;
});
}
return null;
});
When you execute an asynchronous operation (i.e. request() in your case) in a background triggered Cloud Function, you must return a promise, in such a way the Cloud Function waits that this promise resolves in order to terminate.
This is very well explained in the official Firebase video series here (Learning Cloud Functions for Firebase (video series)). In particular watch the three videos titled "Learn JavaScript Promises" (Parts 2 & 3 especially focus on background triggered Cloud Functions, but it really worth watching Part 1 before).
So you should adapt your code as follows, returning the promise returned by request():
const functions = require('firebase-functions');
const { request } = require('gaxios');
const { parse } = require('url');
exports.getGithubReadme = functions.firestore.document('readmes/{name}').onCreate((snapshot, context) => {
const toolName = context.params.name;
console.log(toolName);
const { name, description, site } = snapshot.data();
console.log(name, description, site);
const parsedUrl = parse(site);
console.log(parsedUrl);
if (description) return null;
if (parsedUrl.hostname === 'github.com') {
let githubUrl = `https://api.github.com/repos${parsedUrl.path}/readme`;
return request({
method: 'GET',
url: githubUrl
})
.then((res) => {
let { content } = res.data;
return snapshot.ref.update({ description: content });
})
.catch((error) => {
console.log(error);
return null;
});
} else {
return null;
}
});
Context
I am using telegraf.js for more than 3 bots which run very well in plenty of groups.
Currently one of the bots needs to request for Display Picture of the user who does not have a display picture.
It works very well as expected but unfortunately the bot throws an error and the server goes down
Current Code
// Request for display picture
const requestDP = async (ctx, next) => {
const { from, chat } = ctx.message;
const { can_delete_messages:canDelete } = await deletePermision(ctx);
let totalDPs = 1;
totalDPs = await ctx.telegram.getUserProfilePhotos(ctx.message.from.id)
.then((result) => result.total_count)
.catch((err) => {
console.log(err);
});
if (totalDPs != 0) return next();
if ((chat.id === -1001341734527 || chat.id === -1001083711103 ) && canDelete) {
await ctx.deleteMessage().then((response) => response, ({ response }) => response.ok);
await ctx.replyWithMarkdown(`[${from.first_name||''} ${from.last_name||''}](tg://user?id=${from.id}), പ്രൊഫൈൽ ഫോട്ടോ ഇല്ലാത്തവർക്ക് ഗ്രൂപിൽ മെസേജ് അയക്കാൻ സാധ്യമല്ല`)
.then(({ message_id }) => setTimeout(() => ctx.deleteMessage(message_id), 5 * 60 * 1000))
.catch((err) => console.log("Error in prevencontacts: " + err));
}
}
module.exports = requestDP;
Failure Information (for bugs)
let totalDPs = 1;
totalDPs = await ctx.telegram.getUserProfilePhotos(ctx.message.from.id)
.then((result) => result.total_count)
.catch((err) => {
console.log(err);
});
The functions seem to be working well. But unfortunately sometimes they get an error the and server goes down.
Error message 👇
Error: 400: Bad Request: request for new profile photos has already been sent
It is really hard to refresh the server occasionally :-(
Is there any solution to manage this error ?
I have a function that triggers on firebase database onWrite. The function body use two google cloud apis (DNS and Storage).
While the function is running and working as expected (mostly), the issue is that the Socket hang up more often than I'd like. (50%~ of times)
My questions are:
Is it similar to what the rest of the testers have experienced? Is it a well known issue that is outstanding or expected behavior?
the example code is as follows:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const {credentials} = functions.config().auth;
credentials.private_key = credentials.private_key.replace(/\\n/g, '\n');
const config = Object.assign({}, functions.config().firebase, {credentials});
admin.initializeApp(config);
const gcs = require('#google-cloud/storage')({credentials});
const dns = require('#google-cloud/dns')({credentials});
const zoneName = 'applambda';
const zone = dns.zone(zoneName);
exports.createDeleteDNSAndStorage = functions.database.ref('/apps/{uid}/{appid}/name')
.onWrite(event => {
// Only edit data when it is first created.
const {uid, appid} = event.params;
const name = event.data.val();
const dbRef = admin.database().ref(`/apps/${uid}/${appid}`);
if (event.data.previous.exists()) {
console.log(`already exists ${uid}/${appid}`);
return;
}
// Exit when the data is deleted.
if (!event.data.exists()) {
console.log(`data is being deleted ${uid}/${appid}`);
return;
}
const url = `${name}.${zoneName}.com`;
console.log(`data: ${uid}/${appid}/${name}\nsetting up: ${url}`);
setupDNS({url, dbRef});
setupStorage({url, dbRef});
return;
});
function setupDNS({url, dbRef}) {
// Create an NS record.
let cnameRecord = zone.record('cname', {
name: `${url}.`,
data: 'c.storage.googleapis.com.',
ttl: 3000
});
zone.addRecords(cnameRecord).then(function() {
console.log(`done setting up zonerecord for ${url}`);
dbRef.update({dns: url}).then(res => console.log(res)).catch(err => console.log(err));
}).catch(function(err) {
console.error(`error setting up zonerecord for ${url}`);
console.error(err);
});
}
function setupStorage({url, dbRef}) {
console.log(`setting up storage bucket for ${url}`);
gcs.createBucket(url, {
website: {
mainPageSuffix: `https://${url}`,
notFoundPage: `https://${url}/404.html`
}
}).then(function(res) {
let bucket = res[0];
console.log(`created bucket ${url}, setting it as public`);
dbRef.update({storage: url}).then(function() {
console.log(`done setting up bucket for ${url}`);
}).catch(function(err) {
console.error(`db update for storage failed ${url}`);
console.error(err);
});
bucket.makePublic().then(function() {
console.log(`bucket set as public for ${url}`);
}).catch(function(err) {
console.error(`setting public for storage failed ${url}`);
console.error(err);
});
}).catch(function(err) {
console.error(`creating bucket failed ${url}`);
console.error(err);
});
}
I'm thinking your function needs to return a promise so that all the other async work has time to complete before the function shuts down. As it's shown now, your functions simply returns immediately without waiting for the work to complete.
I don't know the cloud APIs you're using very well, but I'd guess that you should make your setupDns() and setupStorage() return the promises from the async work that they're doing, then return Promise.all() passing those two promises to let Cloud Functions know it should wait until all that work is complete before cleaning up the container that's running the function.