diff --git a/docs/docs/ecommerce-tutorial/card-payments-modal.png b/docs/docs/ecommerce-tutorial/card-payments-modal.png
deleted file mode 100644
index 83a589177e358..0000000000000
Binary files a/docs/docs/ecommerce-tutorial/card-payments-modal.png and /dev/null differ
diff --git a/docs/docs/ecommerce-tutorial/index.md b/docs/docs/ecommerce-tutorial/index.md
index e0b6ff2197a78..ce9577668a7e7 100644
--- a/docs/docs/ecommerce-tutorial/index.md
+++ b/docs/docs/ecommerce-tutorial/index.md
@@ -7,29 +7,21 @@ title: "Gatsby E-Commerce Tutorial"
- [Table of Contents](#table-of-contents)
- [Why use Gatsby for an e-commerce site?](#why-use-gatsby-for-an-e-commerce-site)
- [Prerequisites](#prerequisites)
- - [How does Gatsby work with Stripe and AWS?](#how-does-gatsby-work-with-stripe-and-aws)
+ - [How does Gatsby work with Stripe?](#how-does-gatsby-work-with-stripe)
- [Setting up a Gatsby site](#setting-up-a-gatsby-site)
-- [Installing Stripe Checkout plugin](#installing-stripe-checkout-plugin)
+- [Installing the StripeJS plugin](#installing-the-stripejs-plugin)
- [See your site hot reload in the browser!](#see-your-site-hot-reload-in-the-browser)
- - [How does the Stripe Checkout plugin work?](#how-does-the-stripe-checkout-plugin-work)
-- [Creating a button](#creating-a-button)
- - [Sequence of events](#sequence-of-events)
- - [What did you just do?](#what-did-you-just-do)
-- [Importing checkout component into the homepage](#importing-checkout-component-into-the-homepage)
-- [Getting your Stripe test keys](#getting-your-stripe-test-keys)
-- [Configuring Stripe in Gatsby](#configuring-stripe-in-gatsby)
-- [Setting up a Serverless Function in AWS Lambda](#setting-up-a-serverless-function-in-aws-lambda)
-- [Setting up a separate repo](#setting-up-a-separate-repo)
- - [What did you just do?](#what-did-you-just-do-1)
-- [Editing your new repo](#editing-your-new-repo)
- - [How does the code work on this site?](#how-does-the-code-work-on-this-site)
-- [Pushing code to AWS](#pushing-code-to-aws)
-- [Configuring serverless with your AWS credentials](#configuring-serverless-with-your-aws-credentials)
+ - [How does the StripeJS plugin work?](#how-does-the-stripejs-plugin-work)
+ - [Getting your Stripe test keys](#getting-your-stripe-test-keys)
+- [Examples](#examples)
+ - [Easy: One Button](#easy-one-button)
+ - [Advanced: Import SKUs via source plugin](#advanced-import-skus-via-source-plugin)
+ - [Custom: Fully custom checkout flow (requires backend component)](#custom-fully-custom-checkout-flow-requires-backend-component)
- [Testing Payments](#testing-payments)
# Why use Gatsby for an e-commerce site?
-In this advanced tutorial, you’ll learn how to use Gatsby to build the UI for a basic e-commerce site that can accept payments, with Stripe as the backend for processing payments. Benefits of using Gatsby for e-commerce sites include the following:
+In this advanced tutorial, you’ll learn how to use Gatsby to build the UI for a basic e-commerce site that can accept payments, with [Stripe](https://stripe.com) as the backend for processing payments. Benefits of using Gatsby for e-commerce sites include the following:
- Security inherent in static sites
- Blazing fast performance when your pages are converted from React into static files
@@ -41,21 +33,16 @@ You can see the working demo hosted here: https://gatsby-ecommerce.netlify.com/
- Since this is a more advanced tutorial, building a site with Gatsby before will likely make this tutorial less time-consuming ([see the main tutorial here](/tutorial/))
- Stripe account: [register for an account here](https://dashboard.stripe.com/register)
-- AWS account (free tier that covers anywhere from several thousand to a million requests per month): [register for an account here](https://aws.amazon.com/free/?sc_channel=PS&sc_campaign=acquisition_US&sc_publisher=google&sc_medium=cloud_computing_b&sc_content=aws_account_e_control_q32016&sc_detail=create%20an%20aws%20account&sc_category=cloud_computing&sc_segment=102882721242&sc_matchtype=e&sc_country=US&s_kwcid=AL!4422!3!102882721242!e!!g!!create%20an%20aws%20account&ef_id=Wd_k7wAAAVgVBk9m:20180604172833:s)
-- Willingness to navigate around janky AWS UIs
-## How does Gatsby work with Stripe and AWS?
+## How does Gatsby work with Stripe?
-Stripe is a payment processing service that allows you to securely collect and process payment information from your customers. To try out Stripe for yourself, go to [Stripe’s Quick Start Guide](https://stripe.com/docs/quickstart).
+Stripe is a payment processing service that allows you to securely collect and process payment information from your customers. To try out Stripe for yourself, go to [Stripe’s Quick Start Guide](https://stripe.com/docs/payments/checkout#tryout).
There are alternatives to Stripe, like Square and Braintree, and their setup is very similar to Stripe.
-Stripe requires a server to process the information to make a charge, so you’ll need more than just static pages. Gatsby builds the pages for your frontend, but it won’t be able to handle the server logic that Stripe requires to process payments. That means you’ll need to set up a simple function that your Gatsby project can POST to in order to handle a payment.
+Stripe offers a [hosted checkout](https://stripe.com/docs/payments/checkout) that doesn't require any backend component. You can configure products, SKUs, and subscription plans in the [Stripe Dashboard](https://stripe.com/docs/payments/checkout#configure). If you're selling a single product or subscription (like an eBook) you can hardcode the product's SKU ID in your Gatsby side. If you're selling multiple products, you can use the [Stripe source plugin](https://www.gatsbyjs.org/packages/gatsby-source-stripe/) to retrieve all SKUs at build time. If you want your Gastby site to automatically update, you can use the Stripe webhook event to [trigger a redeploy](https://www.netlify.com/docs/webhooks/) when a new product or SKU is added.
-That function can be set up a number of different ways. To set up that function from scratch, you could:
-
-- Write your own simple server and deploy it somewhere, making it accessible via an endpoint
-- Write and deploy a hosted serverless function through a service like AWS Lambda or Google Cloud
+> **NOTE**: Stripe Checkout is currently in beta. You can sign up to receive updates on the [Stripe website](https://stripe.com/docs/payments/checkout). In the meantime, if you're looking to build more custom checkout flows, you might need to set up a simple function that your Gatsby project can POST to in order to handle the payment. See the ["custom example"](#custom-fully-custom-checkout-flow-requires-backend-component) section below for more details.
# Setting up a Gatsby site
@@ -66,84 +53,75 @@ gatsby new ecommerce-gatsby-tutorial
cd ecommerce-gatsby-tutorial
```
-# Installing Stripe Checkout plugin
+# Installing the StripeJS plugin
-You can extend the functionality of this default starter with plugins. One such plugin is `gatsby-plugin-stripe-checkout`, which you’ll install in this project:
+You can extend the functionality of this default starter with plugins. One such plugin is `gatsby-plugin-stripe`, which you’ll install in this project:
```shell
-npm install gatsby-plugin-stripe-checkout
+npm install gatsby-plugin-stripe
```
-Open the root site directory in a text editor and navigate to `gatsby-config.js` and add the Stripe Checkout plugin to `gatsby-config.js` in the plugins section. Your `gatsby-config.js` should look like the following code example:
+Open the root site directory in a text editor and navigate to `gatsby-config.js` and add the StripeJS plugin to `gatsby-config.js` in the plugins section. Your `gatsby-config.js` should look like the following code example:
-```jsx:title=gatsby-config.js
+```js:title=gatsby-config.js
module.exports = {
siteMetadata: {
- title: "Gatsby Default Starter",
+ title: "Gatsby E-Commerce Starter",
},
- plugins: ["gatsby-plugin-react-helmet", "gatsby-plugin-stripe-checkout"],
+ plugins: ["gatsby-plugin-react-helmet", "gatsby-plugin-stripe"],
}
```
## See your site hot reload in the browser!
-Run `gatsby develop` in the terminal, which starts a development server and reloads changes you make to your site so you can preview them in the browser. Open up your browser to [localhost:8000](http://localhost8000.com/) and you should see a default homepage.
+Run `gatsby develop` in the terminal, which starts a development server and reloads changes you make to your site so you can preview them in the browser. Open up your browser to [localhost:8000](http://localhost:8000/) and you should see a default homepage.
-> **NOTE**: If you have already started your Gatsby development server using `gatsby develop`, you will need to restart the server by pressing CTRL + C in the terminal where the command was run and running `gatsby develop` again to see changes in your `gatsby-config.js` reflected on [localhost:8000](http://localhost8000.com/)
+> **NOTE**: If you have already started your Gatsby development server using `gatsby develop`, you will need to restart the server by pressing CTRL + C in the terminal where the command was run and running `gatsby develop` again to see changes in your `gatsby-config.js` reflected on [localhost:8000](http://localhost:8000/)
-## How does the Stripe Checkout plugin work?
+## How does the StripeJS plugin work?
-Stripe Checkout processes payments with information we send it, you can read more about how it works in Stripe’s docs. The Gatsby plugin, `gatsby-plugin-stripe-checkout`, will add this snippet:
+Stripe provides a JavaScript library the allows you to securely redirect your customer to the Stripe hosted checkout page. The Gatsby plugin, `gatsby-plugin-stripe`, will add this snippet:
-```shell
-
+```html
+
```
-to the end of the `
` tag across all of your pages in your Gatsby project, allowing you to call the Stripe checkout methods from Stripe’s API to create charges.
+to the end of the `` tag across all of your pages. This helps facilitate Stripe's [fraud detection](https://stripe.com/docs/stripe-js/reference#including-stripejs).
If you want to further customise the checkout process or pull Stripe data into your site, check out [Gatsby's plugin library for more Stripe plugins](https://www.gatsbyjs.org/plugins/?=stripe).
-# Creating a button
+## Getting your Stripe test keys
+
+View your API credentials by logging into your Stripe account, and then going to Developers > API Keys.
+
+
+
+You have 2 keys in both test mode and production mode:
-## Sequence of events
+- a publishable key
+- a secret key
-`configure()` sets up Stripe and automatically runs every time the page loads. Then you run `open()` when the buy button is clicked, which then triggers the Stripe payment overlay to open.
+While testing, you must use the key(s) that include _test_. For production code, you will need to use the live keys. As the names imply, your publishable key may be included in code that you share publicly (for example, on the frontend, and in GitHub), whereas your secret key should not be shared with anyone or committed to any public repo. It’s important to restrict access to this secret key because anyone who has it could potentially read or send requests from your Stripe account and see information about charges or purchases or even refund customers.
-Essentially, this is the sequence of events:
+# Examples
-- _page load_ -> `configure()`
-- _some time passes..._
-- _user clicks button_ -> `open()`
+You can find an implementation of these examples [on GitHub](https://github.com/thorsten-stripe/ecommerce-gatsby-tutorial).
-The next paragraphs describe how to set up these events.
+## Easy: One Button
-There is a default checkout modal that is available through the plugin we’re using, shown in the image below. When we call the `.open()` method through Stripe Checkout, the rest of the screen is darkened, and a modal appears over the top, directing the user’s attention to the checkout form. You’ll need to create a button component that calls this method or triggers Stripe from your site.
+If you're selling a simple product, like an eBook for example, you can create a single button that will perform a redirect to the Stripe Checkout page:
-
+### Create a product and SKU
-> Notice the input fields for email and credit card information—this design is already made by Stripe for you to use without styling anything.
+For Stripe Checkout to work without any backend component, you need to create a product listing in the Stripe Dashboard. This is required for Stripe to validate that the request coming from the frontend is legitimate and to charge the right amount for the selected product/SKU. To set this up, simply follow the steps in the [Stripe docs](https://stripe.com/docs/payments/checkout#configure).
-To launch the Stripe Checkout modal (shown above), you need to call the `.configure()` method from Stripe Checkout in your Gatsby site. The only information you are required to provide is your publishable API key so that Stripe knows what account on their platform to send payments to. You can read about other recommended and optional configurations like currency or shipping information in the Stripe Checkout Reference. You are going to make a `checkout.js` file that handles this configuration.
+### Create a checkout component that loads StripeJS and redirects to the checkout
Create a new file at `src/components/checkout.js`. Your `checkout.js` file should look like this:
```jsx:title=src/components/checkout.js
import React from "react"
-// hardcoded amount (in US cents) to charge users
-// you could set this variable dynamically to charge different amounts
-const amount = 2500
-const cardStyles = {
- display: "flex",
- flexDirection: "column",
- justifyContent: "space-around",
- alignItems: "flex-start",
- padding: "3rem",
- boxShadow: "5px 5px 25px 0 rgba(46,61,73,.2)",
- backgroundColor: "#fff",
- borderRadius: "6px",
- maxWidth: "400px",
-}
const buttonStyles = {
fontSize: "13px",
textAlign: "center",
@@ -156,80 +134,37 @@ const buttonStyles = {
letterSpacing: "1.5px",
}
-// Below is where the checkout component is defined.
-// It has several functions and some default state variables.
const Checkout = class extends React.Component {
- state = {
- disabled: false,
- buttonText: "BUY NOW",
- paymentMessage: "",
- }
-
- resetButton() {
- this.setState({ disabled: false, buttonText: "BUY NOW" })
- }
-
+ // Initialise Stripe.js with your publishable key.
+ // You can find your key in the Dashboard:
+ // https://dashboard.stripe.com/account/apikeys
componentDidMount() {
- this.stripeHandler = window.StripeCheckout.configure({
- // You’ll need to add your own Stripe public key to the `checkout.js` file.
- // key: 'pk_test_STRIPE_PUBLISHABLE_KEY',
- key: "pk_test_kuhbxb0MMZsp6fj6aTNDnxUu",
- closed: () => {
- this.resetButton()
- },
+ this.stripe = window.Stripe("pk_test_jG9s3XMdSjZF9Kdm5g59zlYd", {
+ betas: ["checkout_beta_4"],
})
}
- openStripeCheckout(event) {
+ async redirectToCheckout(event) {
event.preventDefault()
- this.setState({ disabled: true, buttonText: "WAITING..." })
- this.stripeHandler.open({
- name: "Demo Product",
- amount: amount,
- description: "A product well worth your time",
- token: token => {
- fetch(`AWS_LAMBDA_URL`, {
- method: "POST",
- mode: "no-cors",
- body: JSON.stringify({
- token,
- amount,
- }),
- headers: new Headers({
- "Content-Type": "application/json",
- }),
- })
- .then(res => {
- console.log("Transaction processed successfully")
- this.resetButton()
- this.setState({ paymentMessage: "Payment Successful!" })
- return res
- })
- .catch(error => {
- console.error("Error:", error)
- this.setState({ paymentMessage: "Payment Failed" })
- })
- },
+ const { error } = await this.stripe.redirectToCheckout({
+ items: [{ sku: "sku_DjQJN2HJ1kkvI3", quantity: 1 }],
+ successUrl: `http://localhost:8000/page-2/`,
+ cancelUrl: `http://localhost:8000/`,
})
+
+ if (error) {
+ console.warn("Error:", error)
+ }
}
render() {
return (
-
-
Spend your Money!
-
- Use any email, 4242 4242 4242 4242 as the credit card number, any 3
- digit number, and any future date of expiration.
-
-
- {this.state.paymentMessage}
-
+
)
}
}
@@ -237,290 +172,354 @@ const Checkout = class extends React.Component {
export default Checkout
```
-## What did you just do?
+### What did you just do?
+
+You imported React, added a button with some styles, and introduced some React functions. The `componentDidMount()` and `redirectToCheckout()` functions are most important for the Stripe functionality. The `componentDidMount()` function is a React lifecycle method that launches when the component is first mounted to the DOM, making it a good place to initialise the Stripe.js client. It looks like this:
+
+```js:title=src/components/checkout.js
+ componentDidMount() {
+ this.stripe = window.Stripe('pk_test_jG9s3XMdSjZF9Kdm5g59zlYd', {
+ betas: ['checkout_beta_4'],
+ })
+ }
+```
-You imported React, set a default price for your product, added some styles, and introduced some React functions. The `componentDidMount()` and `openStripeCheckout()` functions are most important for the Stripe functionality. The `componentDidMount()` function is a React lifecycle method that launches when the component is first mounted to the DOM, making it a good place to configure the Stripe Checkout handler. It looks like this:
+This identifies you with the Stripe platform, validates the checkout request against your products and security settings, and processes the payment on your Stripe account.
```js:title=src/components/checkout.js
- componentDidMount() {
- this.stripeHandler = StripeCheckout.configure({
- key: 'pk_test_kuhbxb0MMZsp6fj6aTNDnxUu',
- closed: () => {
- this.resetButton()
- },
- })
- }
+ async redirectToCheckout(event) {
+ event.preventDefault()
+ const { error } = await this.stripe.redirectToCheckout({
+ items: [{ sku: 'sku_DjQJN2HJ1kkvI3', quantity: 1 }],
+ successUrl: `http://localhost:8000/page-2/`,
+ cancelUrl: `http://localhost:8000/`,
+ })
+
+ if (error) {
+ console.warn('Error:', error)
+ }
+ }
```
-This gives Stripe our key, and tells Stripe to call the Checkout component’s resetButton() method when the Stripe modal is closed.
+The `redirectToCheckout()` function validates your checkout request and either redirects to the Stripe hosted checkout page or resolves with an error object. Make sure to replace `successUrl` and `cancelUrl` with the appropriate URLs for your application.
-The `openStripeCheckout()` function gives additional information to Stripe as a user launches the checkout modal, and will send the information they input to our serverless function once we create it.
+```js:title=src/components/checkout.js
+ render() {
+ return (
+
+ )
+ }
+```
-The tags in the `render()` function define the structure of HTML elements that lay out how the component is structured.
+The `render()` function applies our styles to the button and binds the `redirectToCheckout()` function to the button's onclick event.
-# Importing checkout component into the homepage
+### Importing the checkout component into the homepage
-Now go to your `src/pages/index.js` file. This is your homepage that shows at the root URL. Import your new checkout component in the file underneath the other two imports and replace the tags inside the first `
` tag with a `` tag. Your `index.js` file should now look like this:
+Now go to your `src/pages/index.js` file. This is your homepage that shows at the root URL. Import your new checkout component in the file underneath the other imports and add your `` component within the `` element. Your `index.js` file should now look like similar to this:
```js:title=src/pages/index.js
import React from "react"
import { Link } from "gatsby"
+
+import Layout from "../components/layout"
+import Image from "../components/image"
+import SEO from "../components/seo"
+
import Checkout from "../components/checkout" // highlight-line
const IndexPage = () => (
-
+
+
+
Hi people
+
Welcome to your new Gatsby site.
+
Now go build something great.
{/* highlight-line */}
-
+
+
+
+ Go to page 2
+
)
export default IndexPage
```
-If you go back to [localhost:8000](http://localhost8000.com/) in your browser and you have `gatsby develop` running, you should have a big, enticing button on a card where the filler text used to be.
+If you go back to [localhost:8000](http://localhost:8000/) in your browser and you have `gatsby develop` running, you should now see a big, enticing "BUY MY BOOK" button. C'mon and give it a click!
-# Getting your Stripe test keys
+## Advanced: Import SKUs via source plugin
-View your API credentials by logging into your Stripe account, and then going to Developers > API Keys.
+Instead of hardcoding the SKU IDs, you can use the [gatsby-source-stripe plugin](https://www.gatsbyjs.org/packages/gatsby-source-stripe/) to retrieve your SKUs at build time.
-
+### Add the Stripe source plugin
-You have 2 keys in both test mode and production mode:
-
-- a publishable key
-- a secret key
-
-While testing, you can use the keys that begin with pk*test* and sk*test*. For production code, you will want to use the keys that don’t say test. As the names imply, your publishable key may be included in code that you share publicly (for example, in GitHub), whereas your secret key should not be shared with anyone or committed to any public repo. It’s important to restrict access to this secret key because anyone who has it could potentially read or send requests from your Stripe account and see information about charges or purchases or even refund customers.
+Add the [gatsby-source-stripe plugin](https://www.gatsbyjs.org/packages/gatsby-source-stripe/) which you can use to pull in the SKUs from your Stripe account.
-# Configuring Stripe in Gatsby
-
-Add your Stripe publishable key to `src/components/checkout.js`.
-
-Inside the `componentDidMount()` function, you are calling configure on `StripeCheckout`. Replace the text in the single quotes with your own public key. This tells Stripe to send any payments through to your account.
-
-```js:title=src/components/checkout.js
-componentDidMount() {
- this.stripeHandler = StripeCheckout.configure({
- // You’ll need to add your own Stripe public test key here.
- // key: 'pk_test_YOUR_KEY_GOES_HERE',
- key: 'pk_test_kuhbxb0MMZsp6fj6aTNDnxUu',
- closed: () => {
- this.resetButton()
- },
- })
- }
+```shell
+npm install gatsby-source-stripe
```
-After you replace `pk_test_YOUR_KEY_HERE` with your actual pk_test key and save the change, your button should launch the Stripe Checkout modal and allow you to enter in payment information. You can try and submit a payment, but it will fail because you haven’t set up your serverless function yet. Your Gatsby site is almost ready!
-
-# Setting up a Serverless Function in AWS Lambda
+Now you can add the plugin configuration in your `gatsby-config` file:
-Lambda is a service offered through Amazon Web Services that allows you to run code that would normally run on a server without having to provision or manage servers. For a simple function like a Stripe charge, Lambda will suit your use case nicely. AWS offers many options for configurations; you are going to use the Serverless Framework to help you minimize the steps to deployment, and also allow you to deploy to other cloud providers if needed.
+```js:title=gatsby-config.js
+module.exports = {
+ siteMetadata: {
+ title: `Gatsby E-Commerce Starter`,
+ },
+ plugins: [
+ `gatsby-plugin-react-helmet`,
+ "gatsby-plugin-stripe",
+ {
+ resolve: `gatsby-source-stripe`,
+ options: {
+ objects: ["Sku"],
+ secretKey: process.env.STRIPE_SECRET_KEY,
+ downloadFiles: true,
+ },
+ },
+ ],
+}
+```
-> **NOTE**: You can follow an adaptation of these steps using this tutorial and Serverless’ docs as a reference if you want to deploy your serverless function to a different provider like Google Cloud or Azure.
+To retrieve your SKUs from your Stripe account you will need to provide your secret API key. This key needs to kept secret and must never be shared on the frontend or on GitHub. Therefore we need to set an environment variable to store the secret key. You can read more about the usage of env variables in Gatsby [here](https://www.gatsbyjs.org/docs/environment-variables/).
-# Setting up a separate repo
+In the root directory of your project add a `.env.development` file:
-You’ll be setting up a separate repo for the code that you’ll deploy to Lambda. To look through the example repo, [inspect the code in GitHub](https://github.com/gillkyle/gatsby-stripe-serverless-backend).
+```text:title=.env.development
+# Stripe secret API key
+STRIPE_SECRET_KEY=sk_test_xxx
+```
-Clone the code to a new location on your computer and then change directories into this new folder:
+To use the defined env variable you need to require it in your `gatsby-config.js` or `gatsby-node.js` like this:
-```shell
-`git clone https://github.com/gillkyle/gatsby-stripe-serverless-backend.git`
-`cd gatsby-stripe-serverless-backend`
+```js:title=gatsby-config.js
+require("dotenv").config({
+ path: `.env.${process.env.NODE_ENV}`,
+})
```
-Then you need to run `npm install` to install the dependencies in the `package.json` file, which in this case is just the Stripe library.
+Lastly make sure that your `.gitignore` file excludes all of your `.env.*` files:
-```shell
-npm install
+```text:title=.gitignore
+# dotenv environment variables files
+.env
+.env.development
+.env.production
```
-## What did you just do?
-
-By running `npm install`, you’ve created a node_modules folder that you’ll upload to AWS along with your code to make a charge. All of the code in this file will be hosted online by Amazon, and you need to provide it with the libraries you utilize in your project. By making this repository separate from our Gatsby project, we can decouple it from our site making it easier to switch to a different cloud hosting provider, and significantly decreasing the size of the files we upload to Amazon’s servers.
+### Create a component that lists your SKUs
-# Editing your new repo
+In your components folder add a new `Products` folder. This folder will entail your components that interact with the Stripe SKUs. First you need a components that queries and lists your SKUs:
-Open gatsby-stripe-serverless-backend in your code editor.
+```jsx:title=src/components/Products/Skus.js
+import React from "react"
+import { graphql, StaticQuery } from "gatsby"
+
+export default props => (
+ (
+
+ {skus.edges.map(({ node: sku }) => (
+
{sku.attributes.name}
+ ))}
+
+ )}
+ />
+)
+```
-- Rename the `secrets.example.json` file to `secrets.json`.
-- Replace the string that says "sk_test_STRIPE_SECRET_KEY" in `secrets.json` with your secret test key from your Stripe account, and keep the quotation marks around it (using the test keys allows orders to go through without needing real credit card details, which is useful for testing)
+You can validate your query and see what data is being returned in GraphiQL, which is available at http://localhost:8000/___graphql when running `gatsby develop`.
-Your secret key can be included here if you don’t upload this file to a version control system. The .gitignore file in the project includes a line that will tell any Git commands you run in this folder not to keep track of your secrets file as long as it is named `secrets.json`.
+Once you're happy with your query, create a new page where you can import the newly created Sku componenet:
-## How does the code work on this site?
+```jsx:title=src/pages/advanced.js
+import React from "react"
+import { Link } from "gatsby"
-You don’t need to change any code in the `checkout.js` (not to be confused with the `checkout.js` file we used to create our component in Gatsby), but go ahead and open it up to review what it’s doing.
+import Layout from "../components/layout"
+import SEO from "../components/seo"
-The beginning of the file looks like this:
+import Skus from "../components/Products/Skus" // highlight-line
-```js:title=checkout.js
-// highlight-start
-const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY);
+const AdvancedExamplePage = () => (
+
+
+
This is the advanced example
+ {/* highlight-line */}
+
+)
-module.exports.handler = (event, context, callback) => {
-// highlight-end
-.
-.
-.
+export default AdvancedExamplePage
```
-Stripe is being initialized here, this time with your secret key. You’ll notice it is referencing the variable `STRIPE_SECRET_KEY` from `process.env`, because after you upload your code to AWS, your environment variables like API keys are available in that manner.
+When navigating to http://localhost:8000/advanced/ you should now see a list of paragraphs with your sku names.
-The next line exports `handler`, a function that will handle your checkout logic.
+### Create a component that presents a single SKU
-The next snippet of code (shown below), pulls some of the information on the `event` object that this function receives and stores them in the variables `requestData`, `amount`, and `token`.
+To make your SKUs more visually appealing and interactive, create a new `SkuCard` component in your `Products` folder:
-```js:title=checkout.js
-// Pull out the amount and id for the charge from the POST
-console.log(event)
-const requestData = JSON.parse(event.body)
-console.log(requestData)
-const amount = requestData.amount
-const token = requestData.token.id //highlight-line
-```
-
-The next 2 lines are to comply with web browser security standards. Because our Gatsby site will be at a different url than the function that we are going to upload to AWS, we have to include these headers in our response to say it’s okay to communicate with different URLs on the internet.
+```jsx:title=src/components/Products/SkuCard.js
+import React from "react"
-```js:title=checkout.js
-// Headers to prevent CORS issues
-const headers = {
- "Access-Control-Allow-Origin": "*",
- "Access-Control-Allow-Headers": "Content-Type",
+const cardStyles = {
+ display: "flex",
+ flexDirection: "column",
+ justifyContent: "space-around",
+ alignItems: "flex-start",
+ padding: "1rem",
+ marginBottom: "1rem",
+ boxShadow: "5px 5px 25px 0 rgba(46,61,73,.2)",
+ backgroundColor: "#fff",
+ borderRadius: "6px",
+ maxWidth: "300px",
+}
+const buttonStyles = {
+ fontSize: "13px",
+ textAlign: "center",
+ color: "#fff",
+ outline: "none",
+ padding: "12px",
+ boxShadow: "2px 5px 10px rgba(0,0,0,.1)",
+ backgroundColor: "rgb(255, 178, 56)",
+ borderRadius: "6px",
+ letterSpacing: "1.5px",
}
-```
-
-The last section of code is where the actual Stripe charge is created, and then the information about whether that charge was successful or not is sent back as a response.
-```js:title=checkout.js
-return stripe.charges
- .create({
- // Create Stripe charge with token
- amount,
- source: token,
- currency: "usd",
- description: "Serverless test Stripe charge",
- })
- .then(charge => {
- // Success response
- console.log(charge)
- const response = {
- headers,
- statusCode: 200,
- body: JSON.stringify({
- message: `Charge processed!`,
- charge,
- }),
- // highlight-start
- }
- callback(null, response)
- })
- .catch(err => {
- // Error response
- console.log(err)
- const response = {
- headers,
- statusCode: 500,
- body: JSON.stringify({
- error: err.message,
- }),
- }
- callback(null, response)
+const formatPrice = (amount, currency) => {
+ let price = (amount / 100).toFixed(2)
+ let numberFormat = new Intl.NumberFormat(["en-US"], {
+ style: "currency",
+ currency: currency,
+ currencyDisplay: "symbol",
})
-// highlight-end
-```
+ return numberFormat.format(price)
+}
-A few things happen with `stripe.charges.create()`: it takes an object as an argument that tells the amount to charge, the unique token made by stripe that hides all the credit card information from us, as well as other information like currency to provide more information about the transaction.
+const SkuCard = class extends React.Component {
+ async redirectToCheckout(event, sku, quantity = 1) {
+ event.preventDefault()
+ const { error } = await this.props.stripe.redirectToCheckout({
+ items: [{ sku, quantity }],
+ successUrl: `http://localhost:8000/page-2/`,
+ cancelUrl: `http://localhost:8000/advanced`,
+ })
-If the charge was successful, the code continues into the `then` block and prepares a successful response. If something went wrong, an error response is made and then that response (whether successful or not) is returned in the callback.
+ if (error) {
+ console.warn("Error:", error)
+ }
+ }
-# Pushing code to AWS
+ render() {
+ const sku = this.props.sku
+ return (
+
+
{sku.attributes.name}
+
Price: {formatPrice(sku.price, sku.currency)}
+
+
+ )
+ }
+}
-Now you need to push your code up to AWS so we can hook it up to your Gatsby site.
+export default SkuCard
+```
-Install the serverless framework globally on your computer with this command: `npm install -g serverless` (the -g stands for global and allows you to use serverless in other projects besides just this one)
+This component renders a neat card for each individual SKU, with the SKU name, nicely formatted pricing, and a "BUY ME" button. The button triggers the `redirectToCheckout()` function with the corresponding SKU ID.
-Serverless is a CLI tool that helps speed up the development of serverless functions and connects the dots between writing the code and making the necessary configurations on different hosting providers.
+Lastly, we need to refactor our `Skus` component to initialise the Stripe.js client, and render `SkuCards` while handing down the Stripe.js client in the `props`:
-You can read more about the configurations you’ll use in the `serverless.yml` file in the repo you just cloned or in the Serverless docs.
+```jsx:title=src/components/Products/Skus.js
+import React, { Component } from 'react'
+import { graphql, StaticQuery } from 'gatsby'
+import SkuCard from './SkuCard' // highlight-line
-# Configuring serverless with your AWS credentials
+const conatinerStyles = {
+ display: 'flex',
+ flexDirection: 'row',
+ flexWrap: 'wrap',
+ justifyContent: 'space-between',
+ padding: '1rem 0 1rem 0',
+}
-Configure serverless with your AWS credentials, so you can make updates on AWS through the serverless tools with this command:
+class Skus extends Component {
+ // Initialise Stripe.js with your publishable key.
+ // You can find your key in the Dashboard:
+ // https://dashboard.stripe.com/account/apikeys
+ // highlight-start
+ state = {
+ stripe: window.Stripe('pk_test_qOUT7QyfVVOJlWXtnbzzZ9Tn', {
+ betas: ['checkout_beta_4'],
+ }),
+ }
+ // highlight-end
-> **NOTE**: It’s helpful to edit this command somewhere other than the terminal as you replace the dummy keys with your real keys, or else it might run halfway through your editing process
+ render() {
+ return (
+ (
+
+ )}
+ />
+ )
+ }
+}
-```shell
-serverless config credentials --provider aws --key AAAAAAAEXAMPLE --secret aaaaaaaa/BBBBBBB/CCCdddEXAMPLEKEY
+export default Skus
```
-Where `AAAAAAAEXAMPLE` is your key and `aaaaaaaa/BBBBBBB/CCCdddEXAMPLEKEY` your secret.
+### Adding a cart component
-> **NOTE:** If you have trouble finding your way around AWS to get your keys, you can follow the [steps from the Serverless AWS Credentials docs](https://serverless.com/framework/docs/providers/aws/guide/credentials#creating-aws-access-keys).
+You can call `redirectToCheckout()` providing an array of SKUs and their quantities to charge for multiple items at the same time. Instead of each "BUY ME" button redirecting to the checkout page, you can therefore provide a central "GO TO CHECKOUT" button that uses the state of a cart component. You can see the necessary changes for this example [on GitHub](https://github.com/thorsten-stripe/ecommerce-gatsby-tutorial/tree/cart-example).
-In the gatsby-stripe-serverless-backend project, run `serverless deploy` and your function will be packaged up and uploaded to AWS.
+## Custom: Fully custom checkout flow (requires backend component)
-The output of `serverless deploy` should look something like this in your terminal:
-
-```shell
-Serverless: Packaging service...
-Serverless: Excluding development dependencies...
-Serverless: Creating Stack...
-Serverless: Checking Stack create progress...
-.....
-Serverless: Stack create finished...
-Serverless: Uploading CloudFormation file to S3...
-Serverless: Uploading artifacts...
-Serverless: Uploading service .zip file to S3 (143.3 KB)...
-Serverless: Validating template...
-Serverless: Updating Stack...
-Serverless: Checking Stack update progress...
-.................................
-Serverless: Stack update finished...
-Service Information
-service: gatsby-serverless-stripe
-stage: dev
-region: us-east-1
-stack: gatsby-serverless-stripe-dev
-api keys:
- None
-endpoints:
- POST - https://random-text.execute-api.aws-zone.amazonaws.com/dev/checkout
-functions:
- checkout: gatsby-serverless-stripe-dev-checkout
-```
-
-Copy the URL after the “-” in the post endpoint section, and paste it into your ecommerce-gatsby-tutorial site in the src > components > checkout.js file where it says `AWS_LAMBDA_URL`
-
-```js:title=src/components/checkout.js
-openStripeCheckout(event) {
- event.preventDefault()
- this.setState({ disabled: true, buttonText: 'WAITING...' })
- this.stripeHandler.open({
- name: 'Demo Product',
- amount: amount,
- description: 'A product well worth your time',
- token: token => {
- fetch(`AWS_LAMBDA_URL`, { // highlight-line
- method: 'POST',
- body: JSON.stringify({
- token,
- amount,
- }),
- headers: new Headers({
- 'Content-Type': 'application/json',
- }),
- })
- .then(res => {
-.
-.
-.
-```
-
-Now you have all the pieces in place!
+Stripe Checkout is currently in beta. You can sign up to receive updates on the [Stripe website](https://stripe.com/docs/payments/checkout). In the meantime, if you're looking to build more custom checkout flows, you can set up a simple function that your Gatsby project can POST to in order to handle the payment. See the previous version of [this tutorial](https://github.com/gatsbyjs/gatsby/blob/6b3c08782d0898719b61181638b6a0967da49dd6/docs/docs/ecommerce-tutorial/index.md) for detailed steps.
# Testing Payments
-You can test that your function is working by using this test credit card number offered by Stripe specifically for testing: 4242 4242 4242 4242, with any future date of expiration, any email, and any 3 digit CVC code.
-
-Logs of the Stripe code can be viewed in the terminal. In your `gatsby-stripe-serverless-backend` project, run the command `serverless logs -f -t` with the name of your function instead of . If you didn’t change anything in the `serverless.yml` file your function should be called checkout, like so: `serverless logs -f checkout -t`.
+In test mode (when using the API key that includes _test_) Stripe provides [test cards](https://stripe.com/docs/testing#cards) for you to test different checkout scenarios.