A Guide to Integrating Stripe into your GraphQL-based React Web App
--
This article is currently out of date since Graphcool introduced functions. Please read their documentation, here, until such a time that this article will be updated with the latest instructions:
https://www.graph.cool/docs/reference/functions/overview-boo6uteemo/
https://github.com/graphcool-examples/functions/tree/master/stripe-create-customer
You can follow the example code by typing in your Terminal app:git clone https://github.com/ConsciousApps/StripeGraphQL.git
(use atom or another code editor)
cd StripeGraphQL
atom .
As someone who prefers simplicity over abstraction, I’m a fan of using advanced technologies that are simple at the same time. Thus, for developing JavaScript
web apps, I eventually settled on the following technologies, which—to me—seem to be both advanced and simple enough at the same time:
React
(developed by Facebook) for the front-end. Because components are the future of web development, and because you can share code between web apps (React
) and mobile apps (React Native
).GraphQL
(also developed by Facebook) for the back-end, because it is both simpler and more flexible thanREST
APIs.- To interface between
React
andGraphQL
, I chose the open-sourceApollo Client
, since the other option—Relay
(developed by Facebook)—seemed far too complex at the time of this writing. - And, finally, as my
GraphQL
service provider I chose Graphcool for their simple yet versatile user interface, excellent customer service, supportive community, and competitive pricing model.
The current app I’m developing — the Life Purpose App — requires in-app payment. While in-app payments are being handled in the App Store and Google Play Store for native mobile apps, we have to create an in-app payment method for web apps. As payment provider, I’m choosing Stripe because of Stripe Checkout (the product speaks for itself).
So this tutorial employs all these tools and requires familiarity with React, and, to a lesser extent, GraphQL/Apollo Client. If you haven’t yet learned any of them, I highly recommend each of these tools.
Furthermore, this tutorial has been inspired by and builds upon graph.cool’s original tutorial on how to integrate Stripe Checkout into a web app. I recommend you check it out as well, with the caveat that — as of this writing — it does not use GraphQL subscriptions
, which are necessary for a successful checkout process.
Let’s begin!
GraphQL Models
We need the following models in GraphQL
:
User
, a collection of appusers
,StripeToken
, a collection of Stripetokens
, related to theUser
model in a one-to-one relationship: one Stripetoken
peruser
, andPurchase
, a collection ofpurchases
made by individualusers
, related to theUser
model in a many-to-one relationship: manypurchases
peruser
.
The three models will require the following schema:
If you want to learn more about GraphQL models, I highly recommend graph.cool’s ‘cool’ documentation.
Logic
Now, the actual logic. For security reasons, you are unable to create Stripe payment charges via your front-end app; a back-end server has to do that, since a server is designed to be inaccessible to unauthorized users. That’s why Stripe has implemented this particular logic.
I’ll be referring to the following steps throughout this tutorial in bold as well as in the actual code as Logic #1, Logic #2, etc., so be sure to reference them here later on.
- When the
Stripe Checkout
modal is loaded and user clicks “Purchase”, Stripe creates atoken
and sends it back to the app. - Our app then creates a
node
(a new entry) in theStripeToken
model, and assigns it the Stripetoken
and connects that node to theUser
model via theuser.id
. - A
Mutation Callback
is activated once our app hascreated
anode
in theStripeToken
model. ThisMutation Callback
sends thetoken
to our back-endcreateCustomer
server, which then uses Stripe’s API to create a Stripecustomer
using thattoken
and ouruser
’s data (such asemail
,name
, etc.). Stripe will return a unique Stripecustomer.id
to the server. - On successful creation of a Stripe
customer
, ourcreateCustomer
server thenupdates
theuser
that made the purchase in theUser
model with Stripe’scustomer.id
and stores it in a field, for example, calledstripeId
. - Meanwhile, our front-end web app has been listening to any updates to the
stripeId
of the specific user with the help of a GraphQLsubscription
. Once our web app realizes that theuser
has received astripeId
update, we move on to the next step. - Once user has received a
stripeId
, our front-end web app creates anode
in thePurchase
model using a purchasedescription
(e.g.“Life Purpose App”
), anamount
(e.g.999
for $9.99), and aboolean
isPaid
set tofalse
. This is important because the app itself hasn’t yet actually been paid for, even though we’ve already created a new purchasenode
in thePurchase
model. - A different
Mutation Callback
is activated once our app hascreated
anode
in thePurchase
model. ThisMutation Callback
sends thestripeId
,description
, andamount
to a second server, ourcreateCharge
server, which then creates a Stripecharge
. - On successful creation of a Stripe
charge
, ourcreateCharge
server thenupdates
totrue
theisPaid
field of the specificpurchase
in thePurchase
model, since we’ve now received the money, honey. - Meanwhile, our front-end web app has been listening to any updates to the
isPaid
of the specific transaction with the help of a GraphQLsubscription
. Once our web app realizes that thepurchase
we’ve been listening to via thesubscription
has received anisPaid
istrue
update
, we move on to the next step. - Now our web app is free to implement any logic to indicate that the user has successfully upgraded, for example by setting a
paid
field in theUser
model totrue
.
Implementation
Now, the code.
Step #A: Create a component to interface with Stripe
- Create a basic
React
component. - Add the
react-stripe-checkout
module. - Obtain Stripe API keys and enter publishable
test
key into yourReact
component. - Your component could look similar to this:
Step #B. Create GraphQL code
To keep the code compartmentalized from React
components, I’ll save them in a different file, for example /graphql/purchase.js
and import them into components as needed. That’s why each step requires an export
before the const
. Read the graph.cool documentation for more background information.
Be sure to also create a userQuery
to get the current user.id
. I keep it in a separate file /graphql/user.js
:
Step #C: Connect Component with GraphQL code
Import graphql
code into component (at the top of the component).
And connect component
to graphql
(at the bottom of the component).
Step #D: Create your backend servers and connect them to your Mutation Callbacks
Graph.cool has a detailed overview of how to create your own server using zeit.co’ now service. Highly recommend you check it out.
1. Create an authentication token in your graph.cool console: https://console.graph.cool/YOURAPPNAME/settings/authentication
2. Install now
. In your Terminal app, type in: sudo npm i -g now
3. Assign the following environment variables to your now
server via the Terminal.
now secret add stripe-secret sk_test_XXXXXXXXXXXXXXXXXXXXXXXX
(your Stripe secret key)now secret add gc-pat XXX
(the graph.cool auth token created in step 1)now secret add endpoint https://api.graph.cool/simple/v1/PROJECTID
(your graph.cool project endpoint)now secret add create-secret XXX
(a randomized number/letter combination to later securely connect yourMutation Callback
to yourcreateCustomer
server — and remember to write it down somewhere else).now secret add charge-secret XXX
(a randomized number/letter combination to later securely connect yourMutation Callback
to yourchargeCustomer
server — and remember to write it down somewhere else).now secret add log XXX
(a randomized number/letter combination to later securely log what’s happening during development stage—but be sure to remove logs for production—and remember to write it down somewhere else).
4. Clone the following repository: https://github.com/graphcool-examples/micro-stripe-example.git You may have to tweak some of the code in either createCustomer.js
or in createCharge.js
to match your unique GraphQL schema (data.createdNode
returns data according to your schema naming convention).
5. From the repository’s root directory, in Terminal, launch the server that creates Stripe customers:now -e STRIPE_SECRET=@stripe-secret -e GC_PAT=@gc-pat -e ENDPOINT=@endpoint -e TOKEN=@create-secret -e LOG=@log create/
6. now
will return the URL to your newly created webhook. For example:
https://yourappname-create-customer-zftydstlej.now.sh Copy that URL and add to it your create-secret token
(which you created in step #3 above), like this:https://yourappname-create-customer-zftydstlej.now.sh?token=XXX
7. Create a new Mutation Callback
in your GraphQL console. Into StripeToken is created
, paste the following trigger:
8. Paste the URL from step #6 into the Mutation Callback
handler created in step #7.
9. From the repository’s root directory, in Terminal, launch the server that creates Stripe charges:now -e STRIPE_SECRET=@stripe-secret -e GC_PAT=@gc-pat -e ENDPOINT=@endpoint -e TOKEN=@charge-secret -e LOG=@log charge/
10. now
will return the URL to your newly created webhook. For example: https://yourappname-create-charge-xpibjdifiv.now.sh
Copy that URL and add to it your charge-secret token
(which you created in step #3 above), like this:https://yourappname-create-charge-xpibjdifiv.now.sh?token=XXX
11. Create another Mutation Callback
in your GraphQL console. Into Purchase is created
, paste the following trigger:
12. Paste the URL from step #10 into the second Mutation Callback
handler created in step #11.
Step #E: Implement logic into front-end component
Going back to our component, we now need to make sure Logic #1 — #10 (remember these?) are followed. But first, to make our test app work, let’s bring in the user
(in your app, the user
has most likely been previously called). For the sake of this example (https://github.com/ConsciousApps/StripeGraphQL.git
), let’s add the user into a componentWillMount
.
Into the onToken
function, let’s add Logic #2 (create node
in StripeToken
model). So now, onToken
looks like this:
Next, we’ll add Logic #5 and #6 (Logic #3 and #4 are done on the server) to componentDidUpdate
.
Logic #6 should trigger Logic #7 and #8 on the server, so let’s add Logic #9 and #10 to our app. We’ll simply insert another subscription
after the first one inside componentDidUpdate
.
So now we have our final component:
And FINALLY…
Step #F: Set Correct Permissions in Console
To make sure that the user cannot just call updateUser
with paid
set to true
and thereby manually skip the purchase process, be sure to only set read
permission for the paid
field.
Testing your App
To test your app, run your front-end component, but also consider using the logger on your now
server, too, to see what happens on the back-end: Add logs to your server code, re-do steps #D5 — #D12 (no need do #D7 and #D11 again), then enter in Terminal: now-logs XXX
(using the secret you added in Step #D3). Now run your front-end component and see what happens on the back-end when you go through the payment process.
So that was quite a tutorial. If you’ve made it this far, thanks for reading; I hope you get your in-app purchase to work using Stripe, and that you build apps that do good things in the world. ❤️
To learn more about the app that made me learn all this in-app purchase stuff, feel free to visit: http://LifePurposeApp.com (as of this writing, this comprehensive update is scheduled for release mid-April 2017).
Take care,
Martin Adams
GitHub | ConsciousApps.com