Reputation: 53
I have a problem with a callable firebase cloud function (exports.listAllUsers).
Backend: Nodejs & Firebase-Cloud_functions to use admin.auth().listUsers
Problem: Result (usersList; an array with the uid of the users) is OK in cloud-functions-emulator (log) but NOT in the client (console.log(usersList) in browser is null)
Maybe a problem related with...: bad understanding of promises. A second code example is working with async/await but not working with .then().
The code of the function listAllUsers is basically copy&paste from docs (original code snipet: https://firebase.google.com/docs/auth/admin/manage-users#list_all_users). My code modifications are 5 (comments in the code), to get a list of users uid:
exports.listAllUsers = functions.https.onCall(() => { // -1) callable function
const usersList = ['12323211'] // ----------------------2) first user uid, just a sample
function listAllUsers (nextPageToken) {
// List batch of users, 1000 at a time.
admin.auth().listUsers(1000, nextPageToken)
.then((listUsersResult) => {
listUsersResult.users.forEach((userRecord) => {
usersList.push(userRecord.uid) // --------------3) get users uids
})
if (listUsersResult.pageToken) {
// List next batch of users.
listAllUsers(listUsersResult.pageToken)
}
console.log(usersList) //-------------------------4) list users uid (cloud functions console)
return usersList //-------------------------------5) return to the client the same as showed at the console
})
.catch((error) => {
console.log('Error listing users:', error)
return null
})
}
// Start listing users from the beginning, 1000 at a time.
listAllUsers()
})
The method in the client is...
getUsersList: async function (userType) {
const usersList = await this.$fb.functions().httpsCallable('listAllUsers')()
console.log('usersList: ', usersList)
}
I am using firebase emulators. Cloud functions log is OK, you can see the sample uid and the other uids:
cloud function emulator console output
But I don't get the same in the client:
I think I am doing something wrong related with promises... because a simplification of the code is working with async/await:
exports.listAllUsers = functions.https.onCall(async () => {
try {
listUsersResult = await admin.auth().listUsers()
return listUsersResult
} catch (error) {
console.log('Error listing users:', error)
return null
}
})
Browser console output (reduced code with async/await)
But the same is not working with then()...
exports.listAllUsers = functions.https.onCall(() => {
admin.auth().listUsers()
.then((listUsersResult) => {
return listUsersResult
})
.catch((error) => {
console.log('Error listing users:', error)
return null
})
})
Browser console output (reduced code with .then())
I can refactor the initial snipet of code with async/await, but I am interested in the solution with the original code (.then() flavor; I always use async/await because I am quite new at js)... Anyone can help me? Thanks!
Upvotes: 0
Views: 267
Reputation: 53
Finally I decided to code an async/await
version for my cloud function. The then
version in the first code snipet requires more than just adding the return
to the entire promises chain (it initially complains because of the recursivity, maybe, asking me to add async
to the wrapper function listAllUsers
... I'd like the then
version to just copy&paste from the firebase docs, but it wanted more).
I'd like to share this homemade (but initially tested) version as a sample with async/await without recursivity to list users with admin.auth().listUsers(maxResults?, pageToken?)
:
// get list of users
exports.listAllUsers = functions.https.onCall(async () => {
const usersList = []
try {
let listUsersResult
let nextPageToken
do {
if (listUsersResult) {
nextPageToken = listUsersResult.pageToken
}
// eslint-disable-next-line no-await-in-loop
listUsersResult = await admin.auth().listUsers(1000, nextPageToken)
listUsersResult.users.forEach((userRecord) => {
usersList.push(userRecord.uid)
})
} while (listUsersResult.pageToken)
return usersList
} catch (error) {
console.log('Error listing users:', error)
return null
}
})
Upvotes: 1
Reputation: 83191
This is because with the async/await
version you correctly return listUsersResult
by doing
listUsersResult = await admin.auth().listUsers()
return listUsersResult
but, with the then
version, you don't. You should return the entire promises chain, as follows:
exports.listAllUsers = functions.https.onCall(() => {
return admin.auth().listUsers() // !!! Note the return here !!!
.then((listUsersResult) => {
return listUsersResult
})
.catch((error) => {
console.log('Error listing users:', error)
return null
})
})
Upvotes: 1