Building a Serverless E-Commerce App with AWS Lambda, Stripe and React

Dragon’s Den (German version, “Die Höhle des Löwen” ), a television program featuring entrepreneurs pitching their business idea, offers an amazing opportunity to showcase your products and drive huge awareness to your startup. However, dealing with the enormous influx of traffic during the live broadcast is still a challenging task.

Limberly Trachten’s appearance on the GermanDragon’s Den version “Die Höhle des Löwen” and the immediate impact on site traffic.

In this post, we build a serverless e-commerce app using AWS Lambda, Stripe and React ensuring your website is ready for such traffic peaks. The accompanying code repository can be found on https://github.com/patrick-michelberger/serverless-shop.

Architecture

The bullet-proof, low-cost solution is based on a serverless architecture. Serverless is a hot topic today. A nice introduction by Martin Fowler can be found here. There are basically two types of definitions:

First it can be used to describe applications that significantly or fully depend on 3rd party services in the cloud. These types of services can be described as “Backend as a Service” (BaaS). We use Stripe as a BaaS provider for both inventory & order management and payments.

Second, it can also contain some amount of server-side logic but unlike traditional architectures the code is run as plain functions in “stateless compute containers that are event-triggered”. We use AWS Lambda as a ‘’Functions as a Service” (FaaS) provider to communicate securely with Stripe servers and provide a basic Shop API for a web-based Shop Frontend.

The proposed architecture consists of four components.

  1. Inventory & Order Management: Stripe allows to add and receive product and inventory data (product information, sizes, colors, etc.) right from its dashboard or Products API. https://stripe.com/docs/api#products
  2. Shop API: To communicate with the Stripe API a secure server environment is still needed. Therefore we use AWS Lambda to execute server functions in the cloud and expose a public Shop API for products and inventory data. AWS Lambda is extremely cheap and we pay only for the time our code runs, and not for hours we rented servers for.
  3. Payments: Processing credit cards manually is difficult and dangerous. We use Stripe Checkout as an embeddable payment plugin. Customers can pay instantly, without exposing sensible credit card information to our code. https://stripe.com/checkout
  4. Shop Frontend: Instead of building the site on-demand on the server, we entirely host our shop as a static site on a content delivery network (CDN). CDNs offer improved scalability and fast load times by distributing assets globally. The current proof-of-concept site is built with Facebook’s React library.

In September 2015, Stripe launched a new product Relay that allows retailers to sell goods directly in social networking and content apps. Currently, we solely use Relay’s inventory & order management features for our site. In addition to that, the architecture could leverage Relay’s built-in distribution capabilities and effortlessly add additional customer touch points such as social, voice or messenger bots. For more information take a look at the Stripe Relay documentation.

III. Implementation

Let’s start building. First, we setup the product inventory. Second, we build a Shop API to make our product inventory publicly available. Third, we build the Shop Frontend to showcase our product inventory. Fourth, we include a payment method. Lastly, we send an order from our site to Stripe.

Setup the product inventory & order management

  1. Signup for a Stripe account on https://stripe.com
Stripe dashboard: Products section

2. Click on “Create your first product” in the dashboard’s products section and fill in some product details (ID, Name, Description, Images)

Product details view

3. Add SKUs (Stock Keeping Units) to the created product. Each product can be linked to one or many variants taking into account any combination of attributes (such as color, sizes) and cost. Note: A customer buys a variant of a product (e.g. specific color and size combination), not the product.

Product variants / Stock Keeping Units (SKUs)

After this setup, Stripe exposes those products / variants via its Products API .

Build the Shop Frontend

We use Facebook’s Create React app template to setup an initial site with no build configuration.

yarn install -g create-react-app

create-react-app serverless-shop
cd serverless-shop
yarn start

The example site consists of a basic single product page with product details, a delivery address form, add to basket button and a payment form. The code can be found on github.

Proof-of-concept Shop Frontend built on React distributed via a CDN provider.

Please note: This is only a proof-of-concept site, more components such as multiple products, categories etc, can easily be added in the future.

Build the Shop API

To communicate with the Stripe API a secure server environment is still needed. The secret key can be found in the API section of the Stripe dashboard. We use AWS Lambda to execute server functions in the cloud and expose a public Shop API for products and inventory data.

To simplify the FaaS setup we use the Serverless framework.

  1. Setup the serverless environment
# Install serverless globally
$ npm install serverless -g
# Create a separate folder for your serverless code
$ mkdir serverless && cd serverless
# Create a serverless function for fetching the products
$ serverless create --template fetch-products

2. Respond with the fetched products from Stripe.

const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY); 
module.exports.handler = (event, context, callback) => {  
return stripe.products.list({limit: 10})
.then((products) => {
const response = {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
},
body: JSON.stringify({
data: products.data
}),
};
callback(null, response);
});

3. Deploy to AWS

# Deploy to cloud provider
$ serverless deploy
# Function deployed! Trigger with live url
http://xyz.amazonaws.com/fetch-products

The Shop Frontend should fetch the products from this endpoint.

4. Insert the displayed endpoint URL as productsUrl in config.json file

# Go to frontend folder
$ cd src
# Copy config.json.example
$ cp config.json.example config.json
# insert http://xyz.amazonaws.com/fetch-products as productsUrl into # config.json

Setup the Payment methods

Finally we use Stripe Checkout as an embeddable payment plugin.

1. Insert the Stripe Checkout Javascript library

$ cd public
# Insert <script src=”https://checkout.stripe.com/checkout.js"></script> into the index.html file

2. Initialize Stripe Checkout in the componentDidMount() method in the PayButton component.

componentDidMount() { 
this.handler = window.StripeCheckout.configure({
key: config.stripe.apiKey,
token: function (token) { self.onToken(token); }
});
}

3. Insert the Stripe API’s publishable key as apiKey in config.json.

Stripe Checkout payment plugin for credit card payments

After filling out the payment form, Stripe checks the credit card information and returns a token on success. We use the token to create and pay a order for a selected product variant.

Extend the Shop API with an order endpoint.

  1. Create a serverless checkout function
# Create a serverless function
$ serverless create — template create-charge

2. Create an order and pay for it with the received payment token

const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
module.exports.handler = (event, context, callback) => {  
const requestBody = JSON.parse(event.body);
  // Payment information (from Stripe Checkout)  
const token = requestBody.token.id;
const email = requestBody.token.email;
  // Order information  
const currency = requestBody.order.currency;
const items = requestBody.order.items;
const shipping = requestBody.order.shipping;
  // Create order  
return stripe.orders.create({
currency: currency,
items: items,
shipping: shipping,
email: email
}).then((order) => {
    // Pay order with received token (from Stripe Checkout)   
return stripe.orders.pay(order.id, {
source: token // obtained with Stripe.js
});

// Return success info to client (see full code on github)
});

3. Deploy to AWS

# Deploy to cloud provider
$ serverless deploy
# Function deployed! Trigger with live url
http://xyz.amazonaws.com/create-charge

The Shop Frontend should post the order to this endpoint.

4. Insert endpoint URL as checkoutUrl in config.json file

# Go to frontend folder
$ cd src
# insert http://xyz.amazonaws.com/create-charge as checkoutUrl into # config.json

Run the app & make a test order

Finally, the whole site should be working. You can either run the app locally or in production.

# Run the app locall
$ yarn start
# Deploy the app e.g. via Firebase
$ npm install -g firebase-tools
$ firebase login
$ firebase init
# You will need to agree with database.rules.json being created, choose build as the public directory, and also agree to Configure as a single-page app by replying with y.
# Create a production build
$ yarn run build
# Deploy the app
$ firebase deploy

Visit the running site. Choose a size, fill in the delivery form, insert a test credit card and click on the pay button.

Orders overview

After that you should get a success notification and the recent order should be displayed in the products -> orders section of the Stripe dashboard.

Order details view

Congratulations, you have finished all required streps to build a serverless e-commerce app. I hope you enjoyed the project.

Github repository: https://github.com/patrick-michelberger/serverless-shop
Demo site: http://patrick.michelberger.info/serverless-shop/

If you run into issues getting the application working, feel free to DM me.