Serverless Payment Processing with Firebase (Cloud Next '19)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[MUSIC PLAYING] JENNIFER PERSON: So why are we talking about managing payments today? Well, a lot of apps require you to be able to exchange money, especially because that's probably the primary way that you are making profit off of an app. It would be nice if we could just do it out of the goodness of our hearts. But it is important to be able to break even or make a profit. So a lot of different applications require that ability. So for instance, mobile commerce apps-- there are all sorts of stores, seem to have their own applications right now. And there's a rich on-demand economy. You can get anything delivered to your door within 24 hours, or ridesharing, et cetera. And there's also software as a service, like subscription for billing software, Cloud services, et cetera. We are most focused on these first two bullets because if you're familiar with how apps work in the App Store, when it comes to goods that are digital, that is managed differently. So in this case, we're talking about tangible goods. Specifically, we're talking about a hypothetical online flower store that Susan and I are going to open. And it is going to be called Mobile Florist. And Susan's going to tell you a little bit more about our app. SUSAN GOLDBLATT: Thanks, Jen. Yeah, so we've been building all this great flower application. I'm very excited about it. The way that this will work-- it's a four-step process, like many things in our talk today. And you'll order flowers via the app. So figure out which flowers you want and select them. And then, step 2 will be scheduling a delivery. So when will our person come and deliver these flowers to you? Then, the third step is making a payment via the app-- so actually using your credit card to charge the customer, that that'll be most of what we talk about during this talk. And then, step 4 will be getting your flowers delivered. So how do you actually get the services? So that's how we'll build out the business model. And with that in mind, I'll go into talking a little bit about how we'll be building the application. So there's four steps to this process. And we'll do an authentication process. So how does a user log in and access their information? How do we create them in Firebase? How do we schedule things? So store the information. And then finally, how are we going to manage those customer payments? And then, we'll follow up with how might we handle a refund in the application-- so just a little bit more of a use case for refunds. So we know that managing payments can be kind of intimidating. This is the part where you actually charge your customers. And so if you do it wrong, you can do it really wrong. And no one wants that. It erodes user trust. So we're going to talk about how you can handle payments in a way that's safe and seamless for your customers. And we'll use two technologies, Stripe and Firebase. So I'm going to talk a little bit about why we're using Stripe. First, I'll explain what Stripe is in case we don't know. It's a payment processor. And so that means that it handles charging the credit cards. And this can be really helpful because we don't want to be in the business of handling credit card information in our app. We want to focus on flower delivery because that's what we care about. And so we want to take the process of actually making payments, and handling credit card information, and all of the security concerns-- like what if someone is trying to use an old card? How do we handle that? And Stripe and other payment processors do a really good job at this. So for us, it makes the most sense to use a payment processor to handle that type of information, and security, and convenience. So we're going to use Stripe here. But you definitely don't have to use Stripe. We really only picked it because we know the Stripe API, and we're familiar with it. But you can use any payment processor that you want. So that's why we're going to use Stripe. And I'll pass it off to Jenn to explain a little bit about why we're using Firebase. JENNIFER PERSON: Thank you. So there are actually several reasons that we're going to be using Firebase because we are using different products along different steps. So I'm going to break it down by each step that we're taking. Here are the Firebase technologies that we're going to be using today-- Firebase Authentication, Cloud Firestore, and Cloud Functions for Firebase. Going back to our four steps-- yes, this is going to come up quite a bit-- our first step is going to be authentication, in order for us to know who is going to be paying, where we're sending the flowers, storing that information. So when the user comes back to the application, they still have all that. We need a way to verify who our users are. But we know that auth is very complex, though it is essential. If you've ever rolled your own auth, you already know this. One option that people use a lot is federated identity providers, like Google, or Facebook, or Twitter. And these are really great options. They definitely eliminate some of the difficult work of setting up auth. But at the same time, there are still some challenges. So for instance, what if your customers don't want to use that account to sign into your app, or they just don't have one. Or if you want to give them more than one option, how are you going to make sure that a user who signs in with Google, and a user who signs in with Facebook still have the same type of user, the same type of information? So another problem is, what if someone accidentally logs in with one provider one day and another the next? How are you going to handle those situations? Fortunately, there's Firebase Auth. So Firebase Auth supports all these methods of authentication and more-- so email and password, Google, Facebook, Twitter, GitHub, Anonymous, which is very useful. So for instance, when a user first goes into our application, it's not the best experience to right out of the box make them need to sign in. They aren't invested yet, and that can really ruin the experience. So allowing them to explore the app and then log in once they're ready to schedule can give you a much better experience. At the same time, you still want to protect your information with security rules and be able to identify who your users are. Anonymous Auth allows you to do that. When a user first comes into the app, you can log them in anonymously. And then every time they return to the application, it is still the same user with the same user ID. And even better, when it is time for that user then to schedule something, and they choose the way that they're going to log in, it actually links automatically that anonymous user with the email and password or federated identity provider that they sign in with-- so at least, for a very seamless experience. And if you're interested in a UI that looks a little like this one-- you'll actually see another example of it further in the talk-- this is an example of Firebase UI, which is an open source project on GitHub that allows you to build some UI out of the box for different Firebase products, including Auth. And it really is as easy to add a provider as it is to add a single line of code. And I know that gets thrown around a lot. But in this case, it really is that simple. So yeah, that's why we're using Firebase Auth for authentication. Our next step is going to be scheduling. And we need to store that scheduling information somewhere, so that our customers can see their scheduling information. We need to be able to see all of it, so we can figure out where to send the flowers. So in this case, we are going to use Cloud Firestore to store all of our data. So Cloud Firestore is a database in the Cloud that is built as part of the Firebase service. It is divided into documents. So if you are familiar with a NoSQL model-- maybe you've used the real-time time database before-- this is similar but has some benefits. So a document has inside of it key value pairs that we're calling fields. Keys are strings, and values can be all sorts of different things-- strings, numbers, binary values. They could be Booleans, and even these objecty-looking things. So you have all sorts of things that you can put inside of a document. Documents are stored in collections, which are, of course, collections of documents. And these documents can point to other collections of documents. You cannot have a document inside of a document, but you can have a sub-collection. So what you end up with is a structure somewhat like this. So what is the advantage of storing your data like this, as opposed to just a full Jason blob like you might get in the real-time database? What this allows you to do is make shallow queries for one thing. So let's say, I just want the information that's in that highlighted box. In a NoSQL model sometimes, if you want to query that, you're going to get all of the information underneath it. So you really have to design your database structure, such that you keep it as shallow as possible. And that means that it doesn't necessarily match with your application. This allows you to make a data model that really mirrors your application and makes it a lot easier to understand. So on the back-end, Cloud Firebase Store supports security rules. So along with Firebase Auth, they can help you make sure that users only access the data that you want them to access. So this is where Auth and Cloud Firestore work nicely together. Since we can identify our users by their user ID, we can make sure that securely, they can only check their own data, and we are able to look at any scheduling data. So the final technology when we want to talk about is in terms of managing customer payments. And this is the bulk of what you're going to see us working on today. We are going to use Cloud Functions for Firebase, which are event-driven-- meaning they react to events that happen in your app. This could be when a user first slides into Firebase Auth, or writes to a particular document in Cloud Firestore, writes to a field in the real-time database, maybe triggers a conversion analytics event in Google Analytics. There are all sorts of things that can trigger this. You could even have an HTTP triggered function, so that you can trigger it whatever you want to. Then, wherever these events occur, the Cloud Function starts to run. And whatever code that you have put in it, whatever actions you want to occur are going to happen. Cloud Functions are written in TypeScript or JavaScript on top of No.js, which means you have the option to incorporate all sorts of NPM packages. We're looking at 350,000 different packages at your disposal. So you can definitely customize it. This is not just for Google products. You can incorporate all of the different APIs that you need, which we'll see today in terms of using the Stripe API. So Cloud Functions work inside a privileged Google environment, which means that unlike the client code, they aren't going to be subject to security rules. This is really beneficial for when you want to make actions that you don't want to be accessible to the client. You can send things here and do checks before writing to places in the database, for instance, that you wouldn't want your client to be able to do so. And if you are using any sort of Google Cloud Services, usually setup is a snap. And you don't even necessarily need to include some of those configuration steps that you're used to setting up. So now that you know about why we're using these technologies, let's dig into the good stuff, the payments. SUSAN GOLDBLATT: Cool. So we are going to do another four-step process to manage our customer payments. The first step in there is creating a Stripe customer. So we know through Firebase Auth that we have a customer. But we need to let Stripe know because that way, we can actually do things like add cards, and also charge payments, and make refunds. So that's step 1. Step 2 is then creating a payment method. So sometimes, we say payment method. Sometimes, we say add a card. And sometimes, we say source. It's just a way of paying for the service. So we'll do that. And then next, we make the payment, so processing the credit card. Then finally, we'll handle the refund. So let's go into the first step of creating a Stripe customer. The way that this will work is the user will log in and create a Firebase Auth user. From there, we'll go ahead and trigger a Cloud Function based on the creation of that user. Then, we'll talk to the Stripe SDK and wait for the data to come back in the Cloud Function. Then, with the data back, we'll write that to Cloud Firestore, so that we can use it later. Let's look at what this is going to look like in code. So let me walk through some of this. It's a lot of code on the screen. So here we have a function called Create Stripe Customer. The function is triggered off of an auth. So you can see the functions that auth that user. And then, on Create-- so that means that when a user is created, we'll run this function. Then, we get the user object here. So that contains information that we'll use like the email address or other things that we might need. So what we do is just talk to the Stripe API here. So Stripe.customers.create. So we're saying, hey, Stripe, make a customer. Here's their email address. Super easy, and then we just wait for that data to come back. And we use a wait here because it's TypeScript JavaScript. And if we don't use a wait, it'll just fall right through, and we won't get the data back. So we have to wait. And we wait for the customer. And then, with that customer, we store it back to Cloud Firestore. So we do that by saying admin.firestore.collection. And then, we have a collection called Stripe Customers. And that collection is made up of all of our users with the user.uid. So we'll see in Firestore this collection and then a bunch of documents. And each of those documents will have data that's related to their Stripe ID. And then, we'll also add other information there. So let's look at what this will look like in our actual application. So here you can see, we go and click the Login button. And this will pop up some really nice UI from Firebase. And this is all part of authentication. So we'll go into the actual Google account to log in. We pick our login account that we want to use. And we can see here, we've logged in successfully. If we look at our Data Viewer, the Stripe customer is added there. And when we click into it, we have the customer ID that we got back from Stripe. Cool, so I'll pass it off to Jen to talk about how we're going to create a Stripe payment method. JENNIFER PERSON: So now that we have a Stripe customer associated with a Firebase user, we want to be able to add a method for them to pay for our services. This involves the Client Stripe SDK, creating what is called a token. A token is a single-use payment method. So you give, say, a credit card or some other source of information to the Stripe Client SDK, and they give you back this token that they identify as the credit card. So it doesn't actually have specific information about the credit card in it-- which is nice because then, we can write it to Cloud Firestore without actually storing any of that very sensitive data. At every point in this, you will see that we don't store anything that is identifiable in terms of someone being able to take the credit card information from a user. So we want to store stuff that even if it leaked wouldn't have much of an impact. So in this case, we're just going to write that one-time token, which is naturally going to trigger a Cloud Function. At this point, we're going to speak to the Stripe Server SDK, and take that token and our customer ID, and link them together, which gives us what's called a Source. a Source and a token are very similar, but a source is something that you can use over and over because we think that once someone orders flowers through Mobile Florist, they're definitely going to want to do so again. Finally, we're going to write information about the Source into Cloud Firestore, which enables the client to be able to see that the card was added successfully and also see some information about their card. So here's what that Cloud Function looks like in code. Our function is called Add Payment Source. And in terms of its form, we have functions again dot Firestore instead of in the previous case, you saw off. Here we have a document which is Stripe customer's user ID, tokens, auto ID. This is where that token is being written. You'll see that a couple of these fields are in brackets, which means that they are wild cards. So whatever it happens to be in that place will still trigger this function. It doesn't need to actually say user ID. In this case, it's actually going to be the Firebase user's UID. This isn't on write function, which means it is triggered whenever there is a write to that specific location. So that could be when it is first created, when a change is made, when something is deleted-- all of that is going to trigger this function, which could be beneficial and works for this particular situation. But you'll see that there are some cases where you don't want that. So to get the data from Firestore, we're going to call change.after.data. And this is going to give us what was just changed in Cloud Firestore. If there is no data because it was just a delete, we're just going to return out of this function. We don't need to proceed. Otherwise, we're going to get the token from that data. And then, we are going to get the Stripe customer ID from Cloud Firestore. So this is what we stored in the first function that you saw. And this is going to come up a lot, where we're going to need to get that customer ID based on the Firebase user. So we're just going to put that in its own function, and you'll see get customer ID. And that means we're going to get the customer ID for this particular customer, which enables us to do something like this. CallStripe.customers create source, pass the customer, end of the token. And then, we're going to write that information back to the database. Notice, we also have something that instead of just a random ID for the document, we're using something called Response. In the Response, we have fingerprint, which is a unique identifier of that source. And that actually just makes it easy to query this later. We also call merge true, so that rather than overriding all the information in the document, it just merges the fields together. So let's see what this looks like in action. Here, you'll see adding a credit card. Feel free to try to use this. It's just a Stripe test card. It's really not going to do anything. Also, it's expired. So it's really not good. Good luck. So the card has been saved. You'll see it says Success. And after a moment, the UI updates to show the new card. So here, I can show a little information about it. And then, in Cloud Firestore, you can see the kind of information that comes back. A lot of these are No. But if you wanted to provide that information as well, you could. OK, so we have our Stripe customer. We have their payment method all cued up. Let's move on to actually making a payment because that's the part I'm excited about is making some money. SUSAN GOLDBLATT: Awesome. Same, same. So the way that this will work is a client will write to Cloud Firestore the charge that they're going to make. So that'll come from the app, and we'll see that in our video later. But we'll write to Cloud Firestore. Then after that, we'll trigger a Cloud Function. So hopefully, this is starting to sound a little familiar. Then, our Cloud Function will talk to the Stripe SDK. And we'll wait for that data to come back. Then, with that information, we'll return the result to Cloud Firestore. So before I go into the code for this, I want to talk a little bit about Cloud Functions for Firebase Retries. So Cloud Functions for Firebase are guaranteed to run at least once, but that means that they could run more than once. And we need our function to be able to support that. This is really important when you're making payments because if you run a function that charges a customer more than once, it could charge them more than once-- which would be very bad. And users would be writing in. They wouldn't be using our app. So we really want to make sure that we handle this correctly. So the way that we're going to handle this is called Idempotency. It's a concept that if you run something more than once with the same arguments, only one side effect of it will run. So in this case, we're going to talk to the Stripe API. And if the Cloud Function retries, the Stripe API knows with our Idempotency key that we only want to charge one time. So we give them the same Idempotency key, and they won't recharge the customer every time. So we'll see this in the code a little bit later. But just wanted to set the stage for that. So let's look at the code. This function is called Create Stripe Customer. So it's run off of functions.Firestore.document. And that's when this is created, so whenever a document is created in this location. So we're in the collections write customers. We have our user ID, so whatever user we're in. And then, we have a sub-collection charges. And then, the charge will get an auto ID that is randomly generated but unique by Firestore. And we get the snap and context. So we can get information from that as well. So first thing that we do is get the customer ID since we need that to talk to Stripe. We'll use our Get Customer ID function here and pass in the context.params.userID. Next, we get the amount that they're being charged. So snap.data.amount will have that information. And then, we create a charge object, which is just the amount, and the currency, and the customer. Next, we need to set the source. So what credit card are they going to be using? Do they want to use a default card? Or are they using one that they've put in for the first time? Maybe this is a corporate account for some reason, and they have a different credit card. So after that, we need to get our Idempotency key. So what are we going to use for that here? Well, it needs to be unique, and it needs to be not changing, even though if we run this more than once. So a good example here would be the auto ID of our document. So even if this function runs more than once, the auto ID won't change. So it makes a really good Idempotency key, and so we'll just grab that from the context.params. Then, we'll talk to Stripe and pass in our charge that we created earlier with our currency, and amount, and customer, and also give it the Idempotency key. Then, we wait for that data to come back. And then, store it in Cloud Firestore. You'll notice here that we wrap this in a try catch. And that's because this logic is really important. And we want to make sure any errors are serviced to the user. So we have a function that says User Facing Message. And then, we put the error in there, so the user can understand what's going on with their application. So let's look at what this will look like in our application. JENNIFER PERSON: Now, I'd also just like to note very briefly that there is the risk of the client pressing the button more than once. Maybe they're just really eager to pay you. And resolving that is actually a lot easier than dealing with Idempotency, which is the button in this case is no longer active until a response comes back from the Cloud Functions. SUSAN GOLDBLATT: So here we are write who the flowers are for, click Pay, Payment Was Successful. We can wait for that data to come back, and we see the charge to Puf here. We go and look into our charges. We can see all of this information back from Stripe here. So we were able to successfully charge our credit card from Stripe. And we get all this information back that can be helpful. Now, I'll pass it off to Jen to talk a little bit about handling refunds because sometimes, the flowers aren't always the freshest. JENNIFER PERSON: Right, so we would like to think that we will never have to refund our customers because their product is just that great. But quite frankly, it is going to come up from time to time. So in our case, we want to set up a system where users can request a refund if they think that one is deserved. But we want to be able to have the final say, and what we are actually going to refund to people because there are certainly cases where a refund would be a good idea. Maybe they ended up with black roses instead of red roses. But there are some cases where it's really not on us. So if they send flowers to someone, but that person doesn't actually want them. So we want to be able to pick and choose which refunds we want to approve. So in order to see how we're going to pick and choose that, let's look at how we are going to approve refunds. Starting to look familiar? The client is going to write a refund request to Cloud Firestore, which is going to end up in a queue that we can see. If we decide that it is a reasonable request, we will approve that refund. This approval is going to trigger a Cloud Function, which is actually going to do the refunding. So we need a way to distinguish between moderators-- which right now is just us, but as our company grows, there could be more of them-- and regular customers, so that users can't just approve their own refunds. The way that we're going to do that is through a concept called Custom Claims. In Firebase Auth, when you sign in, a user gives you a whole lot of different information, including the user ID, their email, what providers they've signed in with, maybe an image URL, which could have come from their provider or could be provided by them. And then, they can upload one, and then you could update the user. There's all sorts of information that's in there. There's also this little bit of information on their Auth token, which are Custom Claims. And these can be any kind of key value pairs that you want. But do note that they have a very low limit in size. I think it's like 1,000 bytes, maybe. It's really not meant for those cases where you're like, hey, it would be great if I could put it in their whole home address into the user or the list of their friends. It's just for little pieces of information that can distinguish one kind of user from another. So in this case, we're going to add to our token a claim called moderator, and we're going to set it to true. So this is how we're going to see, does this claim exist on a user. Then they have the right to make changes such as giving refunds. This also enables us to make a different UI where we can see more information. This allows us to distinguish between us being able to see every scheduled delivery and clients just being able to see their deliveries. So how do we make sure that only authorized folks can actually become moderators? We don't want someone to just be able to say, I'm a moderator. Give me that claim. So what we're going to do is make it so that only existing moderators can give that privilege. And in this case, you can get more hierarchical if you want. Maybe you could have an owner property and only that person gets to grant privileges to other people. For simplicity's sake, we are just checking for a single claim, but remember that you can do sort of a combination of them. So this is what the function looks like to give that permission. We are using an HTTP function, but this one is a little different. It is an onCall function, which means this call can only be made from a Firebase client, your Android app or your iOS app, rather than just being able to make it from anywhere. In this case, passes data and context. We check the context because it also passes information about the user who has made the request. We check their Auth token and see if they are already a moderator. If they are not, we let them know that they don't have permission to make this change. This format might look a little strange if you're used to doing HTTP calls. But this is just how it's done. So you can return your fields instead of doing a response.send. If they are a moderator, we're going to get the email of the user that they want to promote. So in this case, if I'm a moderator and I want to promote someone else-- I want to promote Susan-- I would pass her email. If there's no email, I'm just going to let them know, just keeping all my checks in there. Then we have a function called getUserByEmail, which enables us to get all the information about the user based on just their email. If there doesn't happen to be a user with that email, maybe Susan hasn't signed up yet, again, we're just going to have another check. Otherwise, we're going to get the user's UID, which is what is required to add these claims. So then we set custom user claims using their user ID and then passing whatever claims we want. In this case, we're just doing moderator true. You could do several claims at once if you want. You can do them over time, and they'll still all be there. And then we're going to return a response that user is a moderator. So this is how we're making sure that only we can approve moderators and only people with the moderator claim are going to be able to make refunds. So once a moderator approves the refund, it's still going to need to be processed by Stripe. So Susan is going to show you how to do that. SUSAN GOLDBLATT: Awesome. Cool. So we have this refund request that the user is written into. And I just wanted to give you all a little insight into what this might look like. So we have the amount, the approvedAt, which is what our moderator would say yes or no to, an ID, closedAt, all this type of information. I'm just trying to add more dates to these so that we can have an insight if something goes wrong with the customer to look back and be like, oh, it was closed at this time. It was approved at this time. So this is just a little insight into how we're structuring some of our data. So let's go back to our example of how the approvals process for refunds get processed. So we write to Cloud Firestore to request the approval, and then a moderator will come in and approve it or not. Then that moderator coming in to approve will trigger a Cloud Function. And then our Cloud Function will talk to the Stripe SDK, and then we will write that data back to Cloud Firestore after that. So that's kind of the process. And so now we have our moderators, so we have a way to create moderators, and we need to look at the code to actually talk to Stripe. So let's look at that. Here we have a function called refundCharge, and so this is based off a function, that firestore.document-- so a refund request-- and then on the ID. And you can see this is onUpdate function, so this will run when there's an update. And we'll get the change in the context here too for this function. So the first thing that we want to do is make sure that the user is a moderator. And if they're not a moderator, we want to just return an error. And I've included an attemptedAt here to be like, hey, someone tried to refund this, and they weren't a moderator. So maybe pay attention to that if you're looking through it. After that, we want to do a little bit more error checking here too. So we get our refund that we're trying to issue, and then we also want to get a refund object before. So we get our refund that we're trying to issue by saying, change.after.data. So that would be the data after the change has been applied. And we can get the data before the change has been applied by saying, change.before.data. So we want to make sure two things here. One, that the refund hasn't already been approved and two, that the previous refund hasn't been approved. So we want to make sure you're not trying to re-refund something that's already been approved. And then the second one is that there is an approval on it. So make sure that it actually gets approved by someone. If either of those are fall through, so if no one if it's already been approved or if no one approved it, also set an attemptedAt and return. So don't process this refund. So now with all of that error checking aside, we're going to go ahead and talk to Stripe to process the refund. So we call stripe.refunds.create with our charge and the refund ID. And we wait for that data to come back. Here, the response can succeed, and so if it's succeeded, we'll say, great, refund it at this time and return that back. And we'll let the user know. But if the refund doesn't succeed, we also need to make sure that we set that data as well. So we'll say, it was attempted at this time and send the data back to the customer and to the moderator so they can look through it. Finally, we wrapped all of this in a try catch. So just in case there was an error talking to Stripe for some reason that wasn't a successful response or an unsuccessful response, we also want to keep track of that. So we'll say, hey, you attempted this at this time, and it didn't work. And then report the error. So we keep track of all of that in order to just help understand the process for the refunds and understand where our users are in the process. So let's look at this in our application. So here, we have our list of approvals over there, and we can see approvedAt. So it was approved by our moderator, and then this all has the data about when it was refunded, the response that we got back, stuff like that. So you can see that process of going through and approving things. So the next step two, we just covered a bunch of data protection or these if cases, stuff like that. We also want to make sure, on top of our moderator, that we want to protect this data. And so as we mentioned earlier, Cloud Firestore has rules when it's talking with the client to keep things secure. So let's write some rules specifically for refunds that can cover some of our security concerns. So if you're not familiar with rules, it's a match-based statement. So here we have at the top, our databases and the database and the documents that we're trying to match. And then each path in the database gets kind of-- we can give it its own rules. So this particular statement is for the refund request collection. And the refund ID there is a wildcard, so it matches to any of the refund IDs that you pass in. So these are all ordered together, and so you'll have more complex rules as you build out your Firestore database. But this is just, as I said, the refund request ones. So what we're allowing here is, allow read and create. So if the user is logged in and they're the one trying to create the refund and they're not including approved that-- so approve that is not in the request.resource.data, they can read and create. So they can't approve themselves. So this rule prevents that. Then the next rule, allow read and write, is so that moderators-- so you can actually access that custom claim token here. So if request.auth.token.moderator is true-- sorry, that was a lot of words. But if that's true, you can read and write. So that allows our moderators to go in and update the request. So with that, I'll pass it off to Jenn to talk a little bit about our fifth topic. JENNIFER PERSON: Yeah. So the first time we were going to deliver this talk, we actually had a 25 minute window. So I'm super excited that we have a little more room because we're able to cover some topics that I think are very important and exciting. And in this case, we're going to be talking about webhooks. So most payment processors are going to offer you some kind of webhook, an ability to trigger an endpoint when something happens within the payment processor. So in terms of Stripe, this could be pretty much anything. This could be when a payment goes through, when a payment is declined, when a refund happens, when a new customer is created, when a new card is created. They have a whole list of things that you can trigger endpoints from. So again, expired credit cards, failed charges, and stuff. So in terms of making sure that it's just not some malicious person triggering that endpoint, Stripe offers you a signature header that you can use to verify that this webhook actually came from Stripe and not somewhere else. So let's take a look at one example of an endpoint. In this case, we want to do this whenever a customer makes an update to their charge. So in this case, if it seems to be approved upfront, but then later it actually fails, we want to be able to keep data in sync in Cloud Firestore to reflect that change. So this is a regular HTTPS request, as opposed to the ones that are only called from a Firebase client app. So we're going to get the data. This is provided by Stripe. They're going to tell us some information about what has happened. We're also going to get the customer ID because that's provided by Stripe. And then we're going to get an ID, which is the ID of the charge where that change happened. Now we're going to get the Firebase user associated with the Stripe customer ID. So you've seen examples of where we start with a Firebase user and then we get the Stripe customer by looking in the Cloud Firestore. We can do the reverse as well. So in this case, we're going to do it using a query of Firestore Stripe customers where the customer ID field of that document is equal to the customer ID field that just came to us from Stripe. This does return an array of documents even if you set the limit to one. So in this case, I get the first document which is going to be our Firebase user who has that customer ID. And then we're going to get the reference to that path to their customer path. Similarly, we want to know which of their charges something happened to. So now that we know which user it is, we can go into their charges and get the specific document where the ID of the charge is equal to the ID that was just provided from Stripe. Now, we are going to add the information that changed in that charge to Cloud Firestore. So in this case, in that path, I'll set all of the data that just came from Stripe and again merge true. So we have the previous information about the charge and then any updates like the fact that maybe it just failed. We also send a response back to Stripe because they are expecting to know that something was successful. So you can imagine that this could be very useful. You could have a specific endpoint for all sorts of events that happen. So today, we talked to you about a whole lot. We threw a whole lot at you at once, including how to create a Stripe customer and link it to a Firebase user, how to store information about a straight payment method in Cloud Firestore without storing the specific information that makes that card identifiable, how to pay for things by writing the Cloud Firestore and handling the payments from the Stripe server API. Now certainly, you can pay from the client, but the benefit of doing it this way is that you are then a lot-- it makes it much easier to function and update Cloud Firestore. [MUSIC PLAYING]
Info
Channel: Google Cloud Tech
Views: 17,024
Rating: undefined out of 5
Keywords: type: Conference Talk (Full production);, pr_pr: Google Cloud Next, purpose: Educate
Id: BrLTF4QdRrM
Channel Id: undefined
Length: 42min 2sec (2522 seconds)
Published: Thu Apr 11 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.