Simply copy and paste the following command line in your terminal to create your first Strapi project.
npx create-strapi-app
my-project
This tutorial is part of the « E-commerce website with Strapi, Nuxt.js, GraphQL and Stripe
Note: The source code is available on Github.
You must be starving by now... I am sure you want to be able to order!
Let’s create a new checkout page, and store orders in our database.
To store the orders in our database, we will create a new content type.
Order
for the Display name, and click Continue.address
in the Name field.dishes
under the Name field, then click Finish.amount
under the Name field, then click Finish.Choose the Relation field, create a many-to-one relation, user has many orders as below, then click Finish.
Finally, click Save and wait for Strapi to restart.
Now that we have created new fields for the orders collection type. We will take care of the permissions, same process as usual.
We need to make sure that authenticated users can create new orders:
In the next section, we will setup Stripe.js to get user's address and debit card information.
You are going to create a checkout page that will display your cart thanks to the Cart
component and the Stripe form.
Add Stripe to your frontend app, run:
1
yarn add vue-stripe-elements-plus
In the nuxt.config.js
file, add the Stripe script in the head
object:
1
2
3
4
5
6
7
module.exports = {
// Global page headers: https://go.nuxtjs.dev/config-head
head: {
// ...other properties
script: [{ src: 'https://js.stripe.com/v3/' }],
},
}
You can use Stripe.js’ APIs to tokenize customer information, collect sensitive payment details using customizable Stripe Elements, and accept payments with browser payment APIs like Apple Pay and the Payment Request API.
Create a new pages/checkout.vue
, open the file with your text editor, and copy/paste the following code.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// pages/checkout.vue
<template>
<div class="uk-container uk-container-xsmall">
<h1 class="uk-heading-small">Checkout</h1>
<div v-if="success" class="uk-alert-success" uk-alert>
<a class="uk-alert-close" uk-close></a>
<p>{{ success.message }}</p>
</div>
<div v-if="err" class="uk-alert-danger" uk-alert>
<a class="uk-alert-close" uk-close></a>
<p>{{ err.message }}</p>
</div>
<Cart :checkout="false" />
<div class="uk-margin">
<label class="uk-form-label">
Address
<input v-model="address" class="uk-input" type="email" />
</label>
</div>
<div class="uk-margin-top">
<StripeElements v-slot="{ elements }" ref="elms" :stripe-key="stripeKey">
<StripeElement ref="card" type="card" :elements="elements" />
</StripeElements>
<button
class="uk-button uk-button-secondary uk-margin-top uk-width-1-1"
@click="pay"
>
Pay
</button>
</div>
</div>
</template>
<script>
import { StripeElements, StripeElement } from 'vue-stripe-elements-plus'
import { mapGetters, mapMutations } from 'vuex'
export default {
components: {
StripeElements,
StripeElement,
},
data() {
return {
success: null,
err: null,
address: '',
stripeKey: process.env.stripePublishable,
}
},
computed: {
...mapGetters({
username: 'auth/username',
token: 'auth/token',
}),
},
methods: {
async pay() {
// ref in template
const groupComponent = this.$refs.elms
const cardComponent = this.$refs.card
// Get stripe element
const cardElement = cardComponent.stripeElement
const address = this.address
const username = this.username
let token = this.token
this.$http.setToken(token, 'Bearer')
try {
// Access instance methods, e.g. createToken()
token = await groupComponent.instance.createToken(cardElement)
} catch (err) {
this.err = err.response?.data?.error
}
try {
await this.$http.$post('orders', {
data: {
address,
amount: this.$store.getters['cart/price'],
user: username,
dishes: this.$store.getters['cart/items'],
token,
},
})
// this.emptyCart()
this.success = {
message: 'Payment completed successfuly',
}
} catch (err) {
this.err = err.response?.data?.error
}
},
...mapMutations({
emptyCart: 'cart/emptyList',
}),
},
}
</script>
Don’t forget to create a `stripePublishable` property inside `env` object in your `nuxt.config.js` file:
export default {
env: {
stripePublishable: process.env.STRIPE_PUBLISHABLE || '##PUBLISHABLE##'
}
}
Don't forget to replace ##PUBLISHABLE##
by your public Stripe API key.
In this page, you display a form to get user's address and debit card information. You use the Stripe Elements system. When the form is submitted, you get a token from Stripe. Then, you create the order in your Strapi API.
You are now able to let users submit their order. Bon appétit! 🇫🇷
Create a Stripe account, and navigate to API Keys.
If you have already used Stripe, you may know that the credit card information does not go through your backend server. Instead, the information is directly sent to the Stripe API. Then, your frontend receives a token. The id
of the token must be sent to your backend which will create the Stripe charge.
Open the backend
terminal, and install the stripe
package:
1
2
// Ctrl + C
yarn add stripe
The Stripe Node library provides convenient access to the Stripe API from applications written in server-side JavaScript.
In order to integrate the Stripe logic, you need to update the create
charge endpoint in your Strapi API.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// src/api/order/controllers/order.js
'use strict';
const stripe = require('stripe')(process.env.STRIPE_KEY);
/**
* order controller
*/
const { createCoreController } = require('@strapi/strapi').factories;
module.exports = createCoreController('api::order.order', ({ strapi }) => ({
async create(ctx) {
const {
amount,
address,
dishes,
token,
} = ctx.request.body.data;
try {
// Charge the customer
await stripe.charges.create({
amount: amount,
currency: 'eur',
description: `Order ${new Date()} by ${ctx.state.user.id}`,
source: token,
});
// Create the order
const entity = await strapi.service('api::order.order').create({ amount, address, dishes, user: ctx.state.user.id }).
const sanitizedEntity = await this.sanitizeOutput(entity, ctx);
return this.transformResponse(sanitizedEntity);
} catch (err) {
// return 500 error
ctx.response.status = 500;
return { error: { message: 'There was a problem creating the charge'}};
}
}
}));
Create a .env
file in the backend
directory, then copy/pase the following code:
1
STRIPE_KEY=##Secret##
Don't forget to replace ##Secret##
by your Stripe API Key.
Restart the Strapi backend with npm run develop
.
Note: In a real-world example, the amount should be checked on the backend side and the list of dishes related to the command should be stored in a more specific Content Type called
orderDetail
.
In this section, we have created a new checkout page, which let user submit a form with their address and debit card information and used Stripe API to check the amount. 🚀 In the next (and last) section, you will learn how to deploy your Strapi & Nuxt.js applications.
Pierre created Strapi with Aurélien and Jim back in 2015. He's a strong believer in open-source, remote and people-first organizations. You can also find him regularly windsurfing or mountain-biking!