"Cannot read property 'uid' of undefined" error - Plaid link token - swift

I'm getting a "Cannot read property 'uid' of undefined" when trying to create a plaid token....I have spent like 3 days trying to make it work.
does anybody knows how to fix it?
Cloud function to get Plaid token
//PLAID - create link Token plaid Nat
const plaid = require("plaid");
exports.createPlaidLinkToken = functions.https.onCall(async (data, context) => {
const customerId = context.auth.uid;
const plaidClient = new plaid.Client({
clientID: functions.config().plaid.client_id,
secret: functions.config().plaid.secret,
env: plaid.environments.development,
options: {
version: "2019-05-29",
},
});
return plaidClient.createLinkToken({
user: {
client_user_id: customerId,
},
client_name: "Reny",
products: ["auth"],
country_codes: ["US"],
language: "en",
})
.then((apiResponse) => {
const linkToken = apiResponse.link_token;
return linkToken;
})
.catch((err) => {
console.log(err);
throw new functions.https.HttpsError(
"internal",
" Unable to create plaid link token: " + err
);
});
});
swift function
class func createLinkToken(completion: #escaping (String?) -> ()){
//this is the firebase function
Functions.functions().httpsCallable("createPlaidLinkToken").call { (result, error) in
if let error = error {
debugPrint(error.localizedDescription)
return completion(nil)
}
guard let linkToken = result?.data as? String else {
return completion(nil)
}
completion(linkToken)
}
}

The only .uid in your code is in this line:
const customerId = context.auth.uid;
So it seems like context.auth is undefined. In the Cloud Functions code you can handle this with:
exports.createPlaidLinkToken = functions.https.onCall(async (data, context) => {
// Checking that the user is authenticated.
if (!context.auth) {
// Throwing an HttpsError so that the client gets the error details.
throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' +
'while authenticated.');
}
const customerId = context.auth.uid;
...
The new code here comes from the Firebase documentation on handling errors in callable Cloud Functions.
You'll also want to check if the user is signed in in your Swift code.

Related

Firebase Callable Function returning nill data

I'm doing firebase auth on the backend and it's working. It's correctly creating the user and I get the UUID in the console log, however when I try to send back the user's UUID I get a nill response. I've already tried all the solutions on other stackoverflow responses and none have worked for me.
This is my firebase callable function.
exports.create_user_auth = functions.https.onCall((data, context)=> {
const email = data.email;
const password = data.password;
return admin.auth().createUser({
email: email,
emailVerified: false,
password: password,
})
.then((userRecord) => {
// response.status(200).send("Successfully created new user: " +userRecord.uid);
console.log(`UserRecord ${userRecord}`)
console.log(`UserRecord ${userRecord.uid}`)
return userRecord.uid
})
.catch((error) => {
// response.status(400).send("Failed to create user: " + error);
return error
});
});
This is my swift code
Functions.functions().httpsCallable("create_user_auth").call(data) { (result, error) in
if result != nil {
print("Result: \(result)")
print("data", result?.data)
let userId = result!.data as? String
print("UserId: \(userId)")
// onSuccess(offerId!)
}
if error != nil {
print("Error: \(error)")
}
}
This is the new working code
exports.create_user_auth = functions.https.onCall(async (data, context)=> {
const email = data.email;
const password = data.password;
var uuid = ""
await admin.auth().createUser({
email: email,
emailVerified: false,
password: password,
})
.then(async (userRecord) => {
// response.status(200).send("Successfully created new user: " +userRecord.uid);
console.log(`NEW UPDATE`)
console.log(`UserRecord ${userRecord}`)
console.log(`UserRecord ${userRecord.uid}`)
uuid = userRecord.uid
// return userRecord.uid
})
.catch((error) => {
// response.status(400).send("Failed to create user: " + error);
return error
});
console.log(`UUID OUTSIDE: ${uuid}`)
return uuid
});

Firebase Cloud Functions Array Parameter Undefined

When I try to put an array as a parameter for cloud functions. In my code, the array shows up correct, but in the logs for the cloud function it shows up as undefined.
Array Result:
["user1", "user2"]
Cloud Function:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
exports.chatNotifications = functions.https.onCall((data, context) => {
const title = data.title;
const payloadMsg = data.message;
const memberList = data.membersList;
functions.logger.log("Member List:", memberList);
for (let i = 0; i < memberList.count; i++) {
const memberName = memberList[i];
const message = {
notification: {
title: title,
body: payloadMsg,
},
topic: memberName,
apns: {
payload: {
aps: {
badge: "1",
},
},
},
};
admin.messaging().send(message)
.then((response) => {
// Response is a message ID string.
console.log("Successfully sent message:", response);
})
.catch((error) => {
console.log("Error sending message:", error);
});
}
});
Code:
functions.httpsCallable("chatNotifications").call(["title": chatName, "message": name + " has been added to the group", "memberList": memberList]) { (result, error) in
if let error = error as NSError? {
if error.domain == FunctionsErrorDomain {
let message = error.localizedDescription
print(message)
}
}
if let text = result?.data as? String {
print("Result: ", text)
}
}
I can see that in your code you are sending this:
"memberList": memberList
But in the cloud function you have this:
data.membersList
The name of the data is different, also use
memberList.length
instead of
memberList.count

Pushserver isn't waiting for promise answer

I have this push server which sends push notifications to devices and logs the response to a json. The code goes:
push.js
module.exports.sendPushSubscription = async (post, recipient, p256, auth) => {
console.log("Mandando PUSHES");
const subscription = {
endpoint: `https://fcm.googleapis.com/fcm/send/${recipient}`,
expirationTime: null,
keys: {
p256dh: `${p256}`,
auth: `${auth}`
}
}
console.log(subscription);
error = webpush.sendNotification(subscription, JSON.stringify(post))
.then(() => {
console.log("Notificación enviada");
return "Sent!";
})
.catch(err => {
return err;
});
await Promise.all(error);
return error;
};
routes.js
recipients = recipients.split(',');
p256 = p256.split(',');
auth = auth.split(',');
let err = "";
for(var i=0;i<recipients.length;i++) {
err = "Trying";
err = push.sendPushSubscription(post, recipients[i], p256[i], auth[i]);
post.recipients.push({
recipient: recipients[i],
error: err
})
}
rsp.json(post);
However, despite the code might suggest the sendPushSubscription function should wait for the promises to end (it's usually only one) and return either Sent! or the error itself, the json always adds the recipient and an empty error. No matter if it succeeds or fails, the answer is:
"recipients": [
{
"recipient": "d96UkANUtAo:APA91bF1-...",
"error": {}
}
Any ideas? Thanks in advance.
Best regards,
Emiliano

Uncaught (in promise) TypeError: Cannot use 'in' operator to search for 'validateStatus' in

I am getting ** Uncaught (in promise) TypeError: Cannot use 'in' operator to search for 'validateStatus' in 5f8425a33a14f026f80133ed** where 5f8425a33a14f026f80133ed is the id passed to the axios url
I want to display the services based on the user id. My url works perfectly in postman but when i access it from the veux store it gives an error.
services.js (store)
import axios from 'axios';
const state = {
services : {},
status: '',
error: null
};
const getters = {
services : state => { return state.services }
};
const actions = {
async fetchServices({commit}, userId) {
let res = await axios.get('http://localhost:5000/api/services/displayUser' , userId)
commit('setProducts', res.data)
return res;
}
};
const mutations = {
setProducts (state, items) {
state.services= items
},
};
export default {
state,
actions,
mutations,
getters
};
This is how I am calling the action :
computed: {
...mapGetters(["services"]),
},
methods: {
...mapActions(["fetchServices"]),
getData(){
this.fetchServices(this.user._id)
},
},
async created() {
await this.getProfile();
await this.getData();
}
The axios route is defined as
router.get('/displayUser', (req,res) => {
const query = user = req.body ;
Services.find(query)
.exec((err, services) => res.json(services))
})
the error screenshot :
Error screenshot
GET request should not have a body. Either use query params, indicate an id in a path, or use POST request.
In case of query params this may look like this:
let res = await axios.get('http://localhost:5000/api/services/displayUser' , { params: { userId })
router.get('/displayUser', (req,res) => {
const query = user = req.query;
Services.find(query)
.exec((err, services) => res.json(services))
})
This worked for me too:
In front end: Vue Js
let res = axios.get("http://localhost:3000/api/v1/role/getRoleByName",
{ params: { roleName: "name of role you want to send as params" },
});
In back end: Node Js
router.get('/getRoleByName', (req,res)=>{
let roleName = req.query.roleName;
roleModule.getRoleByName(roleName).then(data =>{
response.json(res,data)
}
).catch(err=> {
response.badRequest(res, err);
})
});
it's a silly mistake axios.post req.
async addTodo({ commit }, title) {
try {
const res = await axios.post(BASE_URL, { title, complete: false });
commit("newTodo", res.data);
} catch (err) {
console.log(err.message);
}
},

Unable to return an array of json from Cloud Firestore via Cloud Functions (onCall) to Swift

I have a problem getting the result from a Cloud Function.
This is my Cloud Function:
exports.retrieveTrips = functions.https.onCall((data, context) => {
const uidNumber = context.auth.uid;
var arrayOfResults = new Array();
var idOfFoundDoc;
var query = admin.firestore().collection('Users').where('UID','==', uidNumber);
query.get().then(snapshot =>
{
snapshot.forEach(documentSnapshot =>
{
idOfFoundDoc = documentSnapshot.id;
});
var queryDoc = admin.firestore().collection('Users').doc(idOfFoundDoc).collection('Trips');
queryDoc.get().then(snapshot =>
{
snapshot.forEach(documentSnapshot =>
{
arrayOfResults.push(documentSnapshot.data());
});
console.log('ARRAY: ' , arrayOfResults);
return arrayOfResults;
})
.catch (err =>
{
console.log ('Error adding document: ', err);
});
})
.catch (err => {
//response.send('Error getting documents', err);
console.log ('Error getting documents', err);
});
And this is the code that I have in my application.
#IBAction func RetrieveTripsButton(_ sender: Any)
{
self.functions.httpsCallable("retrieveTrips").call() {(result, error) in
if let error = error as NSError? {
if error.domain == FunctionsErrorDomain
{
let message = error.localizedDescription
print ("Message: " + message)
}
return
}
print ("Result: -> \(type(of: result))")
print("Result.data type: \(type(of: result?.data))");
print ("Result.data -> \(result?.data)")
}
}
And this is the printed result.
Result: -> Optional<FIRHTTPSCallableResult>
Result.data type: Optional<Any>
Result.data -> Optional(<null>)
The console log is able to print arrayOfResults correctly. Furthermore, when I change this functions to onRequest and feed it the relevant information, the res.status(200).send(arrayOfResults) is able to display the array of JSON in the page.
If I placed the return arrayOfResults; outside of the .then function, I would get a result along with an empty array. My issue is similar to this problem here but I'm unable to receive even that when I return { text: "some_data" }; .
Any help would be great, thank you!
You have to chain the different promises and return the result of the promises chain, as follows.
Note that it is actually what the OP explains in his answer to the SO post you mention "The issue was that I forgot to return the actual promise from the cloud function".
exports.retrieveTrips = functions.https.onCall((data, context) => {
const uidNumber = context.auth.uid;
const arrayOfResults = new Array();
let idOfFoundDoc;
const query = admin.firestore().collection('Users').where('UID','==', uidNumber);
return query.get().then(snapshot => { // here add return
snapshot.forEach(documentSnapshot =>
{
idOfFoundDoc = documentSnapshot.id;
});
const queryDoc = admin.firestore().collection('Users').doc(idOfFoundDoc).collection('Trips');
return queryDoc.get(); // here add return and chain with then()
})
.then(snapshot => {
snapshot.forEach(documentSnapshot => {
arrayOfResults.push(documentSnapshot.data());
});
console.log('ARRAY: ' , arrayOfResults);
return { arrayOfResults : arrayOfResults }; //return an object
})
.catch (err => {
console.log ('Error getting documents', err);
//Here you may return an error as per the documentation https://firebase.google.com/docs/functions/callable#handle_errors, i.e. by throwing an instance of functions.https.HttpsError
});
});
I would also suggest that you look at these two videos from the Firebase team, about Cloud Functions and promises: https://www.youtube.com/watch?v=7IkUgCLr5oA and https://www.youtube.com/watch?v=652XeeKNHSk.