Set up Serverless Store: Part 1 (Auth, Storage, Event Streaming, and Third-Party APIs)

Ratros Y.
6 min readJan 24, 2019

--

This document is a part of the Serverless on Google Cloud Platform: an Introduction with Serverless Store Demo How-to Guide. It discusses the authentication, storage, event streaming solutions, and third-party APIs Serverless Store uses.

Before you begin

Storage

Serverless Store uses two Google Cloud Platform solutions, Google Cloud Storage and Google Cloud Firestore, for storage.

Cloud Storage

Google Cloud Storage is a unified storage for objects with global caching; in Serverless Store you will use it to store product images. The API is enabled by default when you create the Google Cloud Platform; follow the steps below to upload an image to Cloud Storage, which we will use in later steps:

  • Open Cloud Storage Browser in Google Cloud Console.
  • Click Create Bucket.
  • Type in the name of the bucket. Write down this name; it uniquely identifies the bucket in Google Cloud.
  • Click Create.
  • Click Upload files.
  • Pick the PNG image extras/sample_data/record_player.png. It will be uploaded to the bucket.
  • Click the name of the image. It will open in a new browser window.

Additionally, you will need to enable public access to the bucket:

  • Click Permissions.
  • Click Add members.
  • Type in allUsers as the member and assign it the role Storage > Storage Object Viewer.
  • Click Add.

Understanding the code

When users create a new product, the Filepond script reads an image from their local drives (see app/static/enableFilepond.js for configuration), send it to a Cloud Function upload_image. The function processes the data with ImageMagick, then saves it to Cloud Storage:

See functions/upload_image/main.py for the full source code.

Cloud Firestore

Cloud Firestore is a NoSQL database. If you are not familiar with the concept, think of Cloud Firestore as a large-scale dictionary where data is stored in key-value pairs. The solution provides cheap, blazing fast storage for structured data, though it lacks the flexibility of traditional SQL databases. In Serverless Store you will use it to store structured data, such as product details and order information.

To set up Firestore:

  • Open the Firestore page in Google Cloud Console.
  • In the Welcome page, Select Cloud Firestore in Native Mode.
  • Select a location, such as us-central1.
  • Click Create Database.

Document is the unit of data storage in Firestore, which can be grouped into collections. It is schemaless, which means that you do not have to specify the structure of data beforehand. The steps below create a document in the Products collection, which we will use later:

  • Open the Firestore Data page in Google Cloud Console.
  • Click Start Collection.
  • Type in products as the collection ID.
  • Leave the Document ID field empty. Cloud Firestore will automatically generate one for your document. The ID is the unique identifier of your document in the collection.
  • Specify the document:
  • Click Save.

Additionally, set up a few indexes to help with the query performance:

  • Go to the Firestore Indexes page in Google Cloud Console.
  • Click Create Index.
  • Create the following three indexes:
Collection ID: carts
Fields to index:
- Field path: uid
Index options: Ascending
- Field path: item_id
Index options: Ascending
Collection ID: carts
Fields to index:
- Field path: uid
Index options: Ascending
- Field path: modify_time
Index options: Descending
Collection ID: promos
Fields to index:
- Field path: label
Index options: Ascending
- Field path: score
Index options: Ascending

Understanding the code

Cloud Firestore is essentially the database backend of Serverless Store. It is used throughout the code; the app/helpers/product_catalog/helpers.py file, for example, includes a collection of helper methods for product related operations, such as getting a product from Cloud Firestore and listing all products from Cloud Firestore:

See app/helpers/product_catalog/helpers.py for the full source code.

Authentication

Serverless Store uses Firebase Authentication. Firebase is a Google developed mobile/web app development platform that solves common app development challenges, such as authentication, analytics, storage, etc. In the Serverless Store demo app you will only use its authentication solution, more specifically, its Sign-in With Google support.

The Firebase Authentication integration has the following workflow:

The system returns with a token (JSON Web Token, JWT) if authentication completes successfully. The token is saved in the browser cookie and passed to Serverless Store in every request; it is a secure proof of identity that can be verified easily with Firebase Admin SDK. Firebase keeps profiles of authenticated users in the database for your future reference.

To set up Firebase Authentication:

  • Open Firebase Console and sign in with your Google account.
  • Click Add project. In the Project Name drop-down menu, select your Google Cloud Platform project. This adds Firebase to your Google Cloud Platform project.
  • Read the terms, and click Add Firebase.
  • Click Add app. Pick Web Platform (</>). The configuration for your Firebase project will show up in a pop-up window.
  • Open the project and find app/static/initFirebase.js. Replace YOUR-API-KEY, YOUR-AUTH-DOMAIN, YOUR-DATABASE-URL, YOUR-PROJECT-ID, YOUR-STORAGE-BUCKET, and YOUR-MESSAGING-SENDER-ID with values of your Firebase configuration. This is the Firebase configuration for the HTML javascripts.
  • Find app/firebase_config.json. Similarly, replace the placeholders with values of your Firebase configuration. This is the Firebase configuration for Firebase Admin SDK.

Understanding the code

When users open the /signin page, the app/static/signInOutWithGoogle.js script handles all the authorization and authentication workload. It redirects users to Google and collects the data and writes the token to the browser cookie when users successfully sign in:

See app/static/signInOutWithGoogle.js for the full source code.

For verification, the flask app uses Firebase Admin SDK. app/middlewares/auth.py includes two wrappers, auth_required and auth_optional; they are responsible for decoding the token, passing the authentication context (user ID, username, and email) to the app, and redirecting customers without valid tokens back to the homepage (if applicable).

See app/middlewares/auth.py for the full source code.

Event Streaming

Serverless Store streams events via Google Cloud Pub/Sub. Cloud Pub/Sub takes events (or any type of data) from an arbitrary number of sources (publishers) and delivers them to an arbitrary number of destinations (subscribers). It scales automatically, requires little configuration, and promises at-least-once delivery.

To set up Cloud Pub/Sub:

In Cloud Pub/Sub, events are published to a Pub/Sub topic. The following steps specifies how to create a topic, publish some data to it, then retrieve the data back.

  • Open the Pub/Sub Topics page in Google Cloud Console.
  • Click Create a topic.
  • Type in sample-topic as the name.
  • Click Create.

Now you can try Cloud Pub/Sub out:

  • Open a terminal on your local machine.
  • Create a subscription to the topic:
gcloud pubsub subscriptions create — topic sample-topic sample-sub
  • Publish a message:
gcloud pubsub topics publish sample-topic — message "Hello World!"
  • Retrieve the message:
gcloud pubsub subscriptions pull --auto-ack sample-sub

You should see an output, Hello World!, in the terminal.

Create the following topics, which Serverless Store uses:

  • new-product
  • payment-process
  • payment-completion

Understanding the code

In the flask app, the stream_event method in app/helpers/eventing/helpers.py is responsible for publishing events:

See app/helpers/eventing/helpers.py for the full source code.

Many Cloud Functions subscribe to these events, which you will set up in the later parts.

Third-Party APIs

Serverless Store uses Stripe and SendGrid for payment processing and emailing respectively (you can set up Google Pay for payment as well). To use these third-party APIs:

  • Stripe
  1. Create a Stripe account.
  2. In the Stripe dashboard, click Get your API keys.
  3. Replace YOUR-API-KEY in app/static/stripe.js with the value of your publishable key.
  4. Write down your secret key, which you will use later.
  • SendGrid
  1. Create a SendGrid account.
  2. In the SendGrid dashboard, open the Settings drop-down menu and click API Keys.
  3. Click Create API Key and follow the prompts on screen.
  4. Write down your API key, which you will use later.

Understanding the code

Payment is an asynchronous operation in Serverless Store: when the app receives a request, it publishes an order_created event via the stream_events method above, in the payment-process topic (app/blueprints/charge/blueprint.py):

See app/blueprints/charge/blueprint.py for the full source code.

The pay_with_stripe Cloud Function subscribes to the topic, listens to the events, and call the Stripe API to process the payment:

See functions/pay_with_stripe/main.py for the full source code.

The asynchronous nature allows the demo app to process payments as fast as possible, even in the busiest holiday seasons. When the payment is processed, pay_with_stripe function will publish a payment_processed (or payment_failed) event to the payment-completion topic. Cloud Function sendOrderConfirmation (functions/sendOrderConfirmation/index.js) subscribes to the topic, listens to the events, and call the SendGrid API to send notification emails:

See functions/sendOrderConfirmation/index.js for the full source code.

sendOrderConfirmation prepares order confirmation emails using pug templates from Cloud Firestore. Create an emails collection in Cloud Firestore and add the following documents:

Document ID: cart_item_reminder
Fields:
- from (String): no-reply@serverlessstore.com
- pug_source (String): You have some items left in the cart.
- subject (String): Long time no see
Document ID: payment_failed
Fields:
- from (String): no-reply@serverlessstore.com
- pug_source (String): Many apologies; we cannot process your order right now due to a payment problem.
- subject (String): We cannot process your order
Document ID: payment_processed
Fields:
- from (String): no-reply@serverlessstore.com
- pug_source (String): Thanks for your order. We have processed your payment.
- subject (String): Thank you for your order

What’s next

Continue the setup in Set up Serverless Store: Part 2.

--

--