I am running this node.js code to create customer on stripe account function deploy successful but failed to create customer on stripe I am not getting what I am missing.
Fire base functions folder is also not showing the function there.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const stripe = require('stripe')("secret key here");
var customer;
stripe.customers.create(
{
email: 'customer#example.com',
},
{
maxNetworkRetries: 2,
}
);
When you use APIs to services (viz. stripe.com and firebase) outside your complete control, you must check for errors. If you're using a service incorrectly the error will explain, or at least hint, what you're doing wrong.
The stripe-node API documentation suggests you invoke stripe.customer.create() as an awaited function, like this:
const customer = await stripe.customers.create({
email: 'customer#example.com',
});
This is easy if you call it from an async function. You should use this sort of code in your async function to check for errors back from stripe.com.
try {
const customer = await stripe.customers.create({
email: 'customer#example.com',
});
/* here's your customer object */
}
catch (error) {
console.error ('stripe', error);
}
If you do not call it from an async function, you can wait for results using the Promises scheme.
stripe.customers.create({
email: 'customer#example.com',
})
.then ( function (customer) {
/* here's your customer object */
})
.catch ( function (error) {
console.error ('stripe', error);
});
If you haven't yet figured out how async/await or Promises work, the time has come for you do to that.
Related
I have a async function like this:
exports.myFunction = async (req, res, next) => {
if (some condition) {
next()
}
try {
const results = await axios.get(`https://a-domain.com/url/path`);
const info = results.data;
const docRef = await addDoc(collection(db, "name_of_collec"), info);
console.log("Document written with ID: ", docRef.id);
} catch (e) {
console.error("Error adding document: ", e);
}
next();
};
Here, response from the first request is required in the second request. But according to my knowledge since I am making asynchronous requests, the two requests should be made at the same time.
What I cannot understand:
So, how it is possible that there is no error occurring?
How is it that, sometimes the no document is added to Firestore? Like it is skipped somehow...
What modification can be done so that await addDoc(collection(db, "name_of_collec") executes compulsorily?
Context info:
I am using Express.js and Node.js to make a backend
I am using Axios to make the first request and the second one is adding a document to Firestore.
Firestore is a NoSQL database inside Google's Firebase.
But according to my knowledge since I am making asynchronous requests,
the two requests should be made at the same time.
asynchronous doesn't mean that the requests are made at the same time. It means the code won't wait for the responses from these requests. Requests are made in the manner you add them in the code and responses will be asynchronous i.e the response will be received at some point in future time.
And there is no guarantee in what manner they will be received.
However, when you sue async/await, the code execution waits at await keyword for the response based on its success or failure it calls the next flow. It is nothing but syntactic sugar on promises. Under the hood, this is how your code will be executed:
exports.myFunction = async (req, res, next) => {
if (some condition) {
next()l
}
axios.get(`https://a-domain.com/url/path`).then(result => result).then(data => {
const info = data;
addDoc(collection(db, "name_of_collec"), info).then(response => {
console.log("Document written with ID: ", docRef.id);
}).catch(e => {
console.error(e);
})
}).catch(e => {
console.error(e);
})
next();
};
So, how it is possible that there is no error occurring?
It is not necessary that the error occurs when you request. If that is the case catch handler should be activated.
How is it that, sometimes the no document is added to Firestore? Like
it is skipped somehow...
The reason might be info is an empty object and firestore automatically removes the empty document.
There is no issue, but there is not data info that is empty sometimes that skips the addition(it does request firestore, but firestore removes the empty docs)
exports.myFunction = async (req, res, next) => {
if (some condition) {
next()
}
try {
const results = await axios.get(`https://a-domain.com/url/path`);
const info = results.data;
const is_Info_Data = Array.isArray(info) ? info?.length >= 1: Object.keys(info) !== 0
if (is_Info_Data) {
const docRef = await addDoc(collection(db, "name_of_collec"), info);
console.log("Document written with ID: ", docRef.id);
} else {
console.log(`Info is empty ${info} no addition to DB`);
}
next();
} catch (e) {
console.error("Error adding document: ", e);
next(e);
}
};
I have a callable initiatePayment function below that process the payment of a user when they pay from client side. This records a new document to my firestore database if the payment is success (addNewRecord) then finally returns payment data from the response of the request.
export const initiatePayment = functions.https.onCall(async (data, context) => {
// destructure data argument
const { userId } = data;
try {
// 1. Process payment via external API request
const payment = await paymentExternalRequest();
const { paymentData, status } = payment.response;
// 2. If payment processing was a success, record new payment data
if (status === "succeeded") {
addNewRecord(userId, paymentData);
}
// 3. Return paymentData to client
return paymentData;
} catch (error) {
throw new functions.https.HttpsError("cancelled", "Cancelled", error);
}
});
addNewRecord function:
const addNewRecord = async (userId, paymentData) => {
const newRecordToAdd = { userId, paymentData };
const docRef = admin
.firestore()
.collection("transactions")
.doc(paymentData.id);
try {
const newRecord = await docRef.set({ userId, transaction: newRecordToAdd });
return newRecord;
} catch (error) {
console.log(error);
}
};
My question is what if addNewRecord fails, how do you handle its error and retry the function again to ensure its success?
You should not have problems with the addNewRecord failing, considering your code. Due to the fact that the function will only be called, based in specific and controlled scenarios, in which you will have the parameters needed for the function to be called correctly, you should be fine.
Anyway, it's very probably that if it failed once, it will fail again, so, you can try to work with a queue system instead of just trying to repeat the execution. This way, you will maintain that data in a queue and run again after checking and handling of the error, to ensure that the addition of the record will occur.
I would recommend you to take a look at the following documents, on queuing with Javascript, that I believe might help you.
Implementation of Queue in Javascript
How would I design a client-side Queue system?
Let me know if the information helped you!
I'm making an authenticate function. It actually works with hardcoded users, but when I start getting users from Firebase, things start getting asynchronous and issues with timing start happening.
I've got a kind of long-winded Javascript function here that I believe returns a promise.
function authenticate({ username, password }) {
return users.then((querySnapshot) => {
return querySnapshot.forEach(doc => {
let user = doc.data();
if (user.username.toUpperCase() == username.toUpperCase())
return bcrypt.compare(password, user.password).then(function (result) {
console.log(password);
console.log(user.password);
console.log(result);
if (result) {
const token = jwt.sign({ sub: user.id }, config.secret);
const { password, ...userWithoutPassword } = user;
return {
...userWithoutPassword,
token
};
}
})
})
})
}
Console logging seems to confirm that this is a promise. I'll be honest, I copy-pasted a lot of the code inside, so I'm still not entirely sure how it works, but the promise syntax is at least something I'm confident in. After I go through a list of users pulled from Firebase and check that both username and password match, the guts of if (result) should run. result does come back as true, which is correct for what I'm trying to log in with, but my password form rejects me because it continues processing before the authenticate method is finished.
In another Javascript file, I have the method that calls this one.
function authenticate(req, res, next) {
console.log(req.body);
userService.authenticate(req.body)
.then(user => console.log(user))
//.then(user => user ? res.json(user) : res.status(400).json({ message: 'Username or password is incorrect' }))
.catch(err => next(err));
}
I'm learning a lot about asynchronous programming recently but this is defying my expectations a bit. Surely doing .then() on authenticate() should run authenticate(), get a promise, even if it's unresolved, then wait for it to resolve before executing the rest of the statements? The current issue is that the method goes ahead, finds no value for user, then throws a 400, which I think is an issue with asynchronicity. Can anyone explain why the outer authenticate function isn't waiting and how I could make it do that?
There are two possible issues:
Result of forEach
The forEach function returns undefined, see Array.prototype.forEach(). If you need the result of the iteration, you can use Array.prototype.map()
Waiting for the Promise
The following statement sounds like the code does not await the result properly:
my password form rejects me because it continues processing before the authenticate method is finished.
If you have a javascript promise, you can use the await keyword in order to continue the function execution only if the promise is either resolved or rejected. Have a look at the examples here: https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Operators/await
In your example, the authenticate function would look like this:
async function authenticate(req, res, next) {
console.log(req.body);
await userService.authenticate(req.body)
.then(...)
.catch(...);
}
Note the async and await keywords. That way it only returns after the userService.authenticate(..) call is fully processed.
Firebase QuerySnapshot has a docs property of type Array<QueryDocumentSnapshot<T>>. You can use that and the Array.find to search for the user. You should also await for bcrypt.compare while you search for user.
function authenticate({ username, password }) {
return users.then(async (querySnapshot) => {
const { usersDocs: docs } = querySnapshot;
const userDoc = usersDocs.find(doc => {
return doc.data().username === username;
});
if (userDoc) {
let user = doc.data();
const pwdCompareResult = await bcrypt.compare(password, user.password);
console.log(password);
console.log(user.password);
console.log(pwdCompareResult );
if (pwdCompareResult ) {
const token = jwt.sign({ sub: user.id }, config.secret);
const { password, ...userWithoutPassword } = user;
return {
...userWithoutPassword,
token
}
}
}
})
}
Please consider using Firebase Authentication instead
Your auth implementation is not reliable and it transfers sensitive data to every users device, like usersname and password hashes. Firebase has a very solid authentication system that you should be using.
I'm using a Firebase function that detects when a Stripe Token is added to a user collection, which then creates a Stripe User and creates a Subscription for that user.
The problem I'm having is that the below code has an error in it, and whilst I need to figure out what that error is, the Promise Chain doesn't seem to catch the actual error.
All that logs out is Function execution took 4375 ms, finished with status: 'connection error'
Does anyone know why this is happening. The only way I can get it to log catch the error is to nest the Promises.
exports.createStripeUser = functions.firestore
// A Stripe Token is created in a user, therefore they have agreed to pay
// Create a User in Stripe, and then attach the subscription to the Stripe customer
.document('users/{userId}/stripe/{stripeCollectionId}')
.onCreate((snap, context) => {
const stripeToken = snap.data().stripeToken;
let customer;
return admin.auth().getUser(`${context.params.userId}`)
.then(userObj => {
const user = userObj.toJSON();
return stripe.customers.create({
email: user.email,
source: stripeToken
})
})
.then(cust => {
customer = cust;
return db.collection('users').doc(context.params.userId).collection('plan').doc(context.params.userId).get()
})
.then(plan => {
return stripe.subscriptions.create({
customer: customer.id,
items: [{plan: plan.data().plan}]
})
})
.catch(e => {
console.log("ERRR", e)
throw new functions.https.HttpsError('unknown', e.message, e);
})
})
Wrap your block in a
try {
}
catch (e) {
// e holds the nested error message
}
block and pick up the error there.
I currently have a project which makes use of native Promises. I am looking to migrate these Promises over to Async/Await. I am having troubles migrating them over; I am trying to follow this article. Below is the current code with the Promises which need changing to Async/Await.
routes.js
// Importing user information
import user from '../server-controllers/user';
// User Information Route
router.get('/about', (req, res) => {
user.profile().then((data) => {
return res.render('user', {
title: data,
});
}).catch((e) => {
res.status(500, {
error: e,
});
});
});
user.js
/*
This file contains any server side modules needed.
*/
module.exports = {
// Returns information about a user
profile: () => {
return new Promise((resolve, reject) => {
const user = "John Doe";
resolve(user);
});
},
};
If there is any help in what I would need to do to convert these that would be helpful. I don't know if the code needs changing on either the routes or user file (or both).
The error which I am getting in my terminal is [object Error] { ... }
The key thing to remember about async and await is that an async function is really just a function that returns a Promise, and lets you use await to resolve Promises. So when a Promise rejects, if it is awaited then you will get an error thrown in the context of wherever the await is.
So technically, if you want to use async/await syntax, you don't need to change user.js. You could just change routes.js to:
// Importing user information
import user from '../server-controllers/user'
// User Information Route
router.get('/about', async (req, res) => {
try {
const data = await user.profile()
return res.render('user', {
title: data
})
} catch (error) {
// Runs if user.profile() rejects
return res.status(500, {error})
}
})
But user.js is made more succinct when you use an async function:
module.exports = {
// Returns information about a user
// This returns a Promise that resolves to 'John Doe'
profile: async () => 'John Doe'
}