Managing payments in your app: setting up the website — the code

Jen Person
Google Cloud - Community
8 min readAug 24, 2020

Let’s hurry up already and make this website!

If you’re still on this coding journey with me, then I know that you’re passionate about payments! Source

Are you new to this series? Check out the first blog for an introduction and a table of contents!

So far, the code we’ve written for American Sock Market has been for the backend. In this post, we’re finally tackling the front end!

In my last blog post, I described the components of the storefront. In this post, I walk through the implementation. Go to the part-3-set-up-shop-website folder so we can check out the code!

Inside the folder, you’ll find another folder and some files:

  • public/
  • firebase.json
  • firestore.rules
  • package.json
  • README.md

There are a couple files here that you may not be familiar with: firebase.json and firestore.rules. I will explain these in a bit. For now, let’s pretend they don’t matter even though they actually do matter a lot.

Opening the public/ folder, we find the main code that we’re going to explore:

  • img/
  • 404.html
  • canceled.html
  • completed.html
  • global.css
  • normalize.css
  • index.html
  • index.js

I suggest opening all of the files and taking a gander, just to get an idea of how the app works. Open index.html in a Chrome window. Finally, an actual website to look at!

But of course, this site isn’t up and running yet. This is just the HTML. So if you click the dropdown menu, you’ll just see this lonely placeholder sock.

This sock must be sad because it’s alone. Maybe that’s why it’s so blue.

Inspecting the HTML also doesn’t reveal too much excitement. The page is kept purposely simple so you can easily see how to customize it to fit your needs. Let’s focus on the bottom of the body where we find some script tags.

<script src="https://www.gstatic.com/firebasejs/7.15.0/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.15.0/firebase-firestore.js"></script>
<script src="/__/firebase/init.js"></script>

These scripts used to incorporate Firestore in the app. The version numbers I show in this blog are up to date at the time I published this, but they may have changed since then. Be sure to check the Firestore documentation to find the latest version numbers.

The first script is the core Firebase SDK. It’s required for all projects using Firebase. The second script adds the Firebase product we’re going to use: Firestore. The third initializes Firebase for use in this specific application. It always goes after any other Firebase-related scripts.

Why Firebase?

So it turns out that Cloud Firestore is a Cloud product and a Firebase product. You can find implementation steps in both the Google Cloud and Firebase docs and these directions are the same. To access Firestore client-side, you use the Firebase SDKs.

Additionally, the website is hosted on Firebase Hosting. The advantage of this over other hosting options is that the Firebase app’s configuration is automatically provided by the Hosting environment, meaning that you don’t have to provide configuration details. This makes it easy to use the same web app code across multiple Firebase projects.

So that’s about all the excitement in index.html. Again, feel free to peruse it to your liking. Just keep in mind that it’s intentionally basic. There are no frameworks or optimizations. The payment-related code can be found in index.js, so let’s spend some time to walk through it.

The Code

Alright, let’s check out index.js.

First, as usual, we have some initializers.

const stripe = Stripe('pk_test_ABCde');
const db = firebase.firestore();
const sockRef = db.collection('socks');
let selectedProduct;
let productList = '';

Notice that you will provide your Stripe public key here. Since this key is (as the name suggests) public, you don’t have to be concerned about the client having access to it. When you deploy your app, be sure to include your public key, which can be found in the Stripe dashboard.

Get the latest socks

Next up in our code, we get up-to-date information about our sock patterns from Cloud Firestore.

sockRef.get().then(querySnapshot => {
querySnapshot.forEach(doc => {
const data = doc.data();
let name = data.name;
// capitalize first letter for display purposes
let displayName = name.charAt(0).toUpperCase() + name.slice(1);
if (!selectedProduct) {
selectedProduct = name;
}
const amount = data.price;
const image = data.images[0];
productList = productList+`<option data-amount="${amount}" data-id="${name}" data-img="${image}">${displayName}</option>`
});
document.getElementById('select').innerHTML = productList;
});

Here are the basic steps taken in this code:

  • Get the documents in the socks collection
  • iterate through the documents
  • Get the data from each document
  • Use this to populate an HTML tag

Keep in mind that the way I’m populating the HTML is less than ideal. In your own app, you’re probably using some kind of JavaScript framework that will update your HTML in a more elegant fashion.

Checkout time

Once the customer has selected an item, it’s time to check out. This is where we initiate the Stripe Checkout session by making a call to our Cloud Run endpoint.

fetch(
'https://[your_cloud_run_url]/session?product='+selectedProduct
)
.then(function(response) {
return response.json();
})
.then(function(session) {
document.getElementById(“spinner”).classList.add(“hidden”);
document.getElementById(“label”).classList.remove(“hidden”);
stripe
.redirectToCheckout({
sessionId: session.id
})
//...
});

In the call to Cloud Run, we pass the selected product as a query parameter. The response data includes the Stripe Checkout session ID, which we need to complete checkout. Using the Stripe client SDK, we redirect to the Stripe Checkout page. From there, the payment is handled by Stripe, so there’s no additional coding on your part! And that’s about all there is to it to start a simple storefront.

Great…but you seemed to gloss over some stuff in that folder

You didn’t think I’d forget, did you? There were indeed a couple files in the project folder that I wanted to talk about before deploying:

  • firebase.json
  • firestore.rules

These small files play important roles in our project. Let’s examine each of them.

firebase.json

Open the firebase.json file. Inside, you’ll find the following code:

{
"firestore": {
"rules": "firestore.rules"
},
"hosting": {
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
}
}

This file contains the configuration for deploying your Firebase project via the Firebase CLI. If I run the command firebase deploy, then by default I’m deploying to both Firestore and Hosting in the configuration outlines in this file.

For Hosting, the configuration tells Firebase which folder is the public folder, and which files and folders to ignore.

For Firestore, the config tells me which files will be included in deployment. In this case, we’re using the CLI to configure the security rules for Firestore. This seems like a great segue into that firestore.rules file!

firestore.rules

Before I explain the security rules of this project, I want to emphasize that security is not optional and should be considered as you’re designing your database schema. Security rules are a meaty topic, and I implore you to read the documentation, test out examples, and be sure that you have a deep understanding of how Firestore security rules work. I’m not trying to lecture you but at the same time, I admit I’m lecturing you. I don’t care if you think I’m being a nag if it means you’ll actually take security seriously!

Phew! Alright, with that out of the way, let’s get back to the rules we use in American Sock Market. We can examine the Firestore security rules in the firestore.rules file:

rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /socks/{sock=**} {
allow read: if true;
}
}
}

If you’re unfamiliar with the format of security rules, then definitely spend some time in those docs. These rules allow public access to read the socks collection and all subcollections under it. Since the default security condition is false, unless otherwise specified, no client can read or write to any part of the database. Thus, customers cannot write to the `socks` collection and they cannot read or write any other part of the database.

This is a very rudimentary set of rules and it’s definitely not recommended for a production app. Even in testing, it’s a good idea to keep your database secure by including authentication as a requirement to interact with any part of the database. I set the socks collection to be able to be publicly read, when in reality I prefer to use at least anonymous authentication. So as you might suspect, we’ll be adding authentication in a future post! If it sounds like I’m getting preachy again, so be it. Did you check out the rules doc yet?

Deploy to Firebase Hosting

It’s the moment you’ve been waiting for: time to bring this app to life! Way back in the very first blog post of this series, I outlined the requirements to build the project. One of these was installing the Firebase CLI. If you don’t already have it installed, then you can follow the steps in the CLI reference docs to get it up and running.

Set the default project to the project you’re using.

firebase use PROJECT_ID

Now any commands we run will automatically use this project unless you add a --project flag and include another project.

Deploy the website to Hosting and the security rules to Firebase by running this command:

firebase deploy

Once deployed, follow the link to your hosted web page to give it a try!

It’s alive!

Well, maybe our storefront is not so much alive as it is live. Go ahead and click around to get a feel for the app. When you’re ready to try the checkout functionality, you can use Stripe’s dummy credit card number, 4242 4242 4242 4242.

You can verify that the payment was successful via the Stripe dashboard.

You can see the email you used under the list of customers
Click on the email and you’ll see a history of that customer’s payments

Done…ish

What we have now is a free-standing application that can make payments, so you could say that it’s done. But there are a lot of other things to consider, like verifying that payments were successful, account creation so customers can save their purchase history, refund management, and much more. You can bet this series is far from over! Stick with me for some payment processing fun!

In the meantime, continue to play with your project. You can fork the repo and make changes. If you think you’re on to something good, go ahead and make a pull request!

Also, be sure to:

--

--

Jen Person
Google Cloud - Community

Developer Relations Engineer for Google Cloud. Pun connoisseur.