How to…

Integrate a checkout with DADI Web

Preface

There’s a wealth of payment APIs on the market, commonly with support for the majority of programming languages and frameworks. DADI Web makes it particularly easy to integrate third-party services, and by leveraging the power of DADI Web’s Event System, I’ll show you how your webshop, booking system or cat walking business can start taking payments today.

For this tutorial I’ve chosen to show you how to integrate the popular payment service Stripe, however the logic should be easily transferable to a different service of your choosing.

Outcome

By the end of this tutorial, you’ll have a fully functioning HTML payment form that accepts card payment details. The form will save a new customer, and their card details, to your Stripe account.

Requirements

This article assumes that:

You have DADI Web installed. If you don’t, or you want a quick refresh, head over to the lovingly crafted first install guide penned by our Design Director, David Longworth.

penned by our Design Director, David Longworth. You have an active Stripe account. If you don’t, register here .

. You have your Stripe secret key ready. If you don’t, read more about API Keys here.

Using in production

Whilst this tutorial covers all of the app requirements for handling payments, there are some additional security requirements to consider when using in a production environment.

You should always use TLS and make sure you’re performing a PCI compliance test annually. More information can be found in Stripe’s security documentation.

Let’s go!

We’ll need a page where our users can pay for their service. It will contain a payment form with a button that, when submitted, sends the payment details to Stripe.

Creating the page

Add a file to workspace/pages to begin creating the payment page. For full documentation about pages in Web, see https://docs.dadi.tech/web#adding-pages.

workspace/pages/payment.json

{

"page": {

"name": "Payment",

"description": "Honestly, it's for a good cause",

"language": "en"

},

"routes": [

{

"path": "/payment"

}

]

}

The above page specification tells Web that this page should be loaded for requests to /payment . If you like, read more information about Routing in Web.

Now that we have a page specification file, we need a template to display the HTML.

I’ve chosen the Dust.js templating language, but feel free to choose a different template engine (or build your own!).

Create a new Dust.js file in workspace/pages which contains a form with input fields to capture the card details, and a submit button to post the form.

workspace/pages/payment.dust

<form action="" method="POST">

<input name="email" type="email" placeholder="Email" required />

<input name="number" placeholder="Card Number" type="number" />

<input name="cvc" placeholder="CVC" type="number" />

<select name="exp_month">

<option disabled selected>Expiry Month</option>

{! Months !}

</select>

<select name="exp_year">

<option disabled selected>Expiry Year</option>

{! Years !}

</select>

<h3>Amount</h3>

<span>£<input name="amount" type="number" placeholder="Amount" required value="5.00" /></span>

<input type="submit" value="Pay me!" />

</form>

You’ll see that the date inputs aren’t populated with options. We could do this manually, but this is a good opportunity to use Web’s Preload Events to generate data for us.

Card dates event

The payment form we’re building asks the customer to enter the valid from month and year, and to make each respective dropdown menu readable and dynamic in our page template, we’re going to create a Preload Event to generate the next 30 years worth of possible months and years.

Add a file to workspace/events called cardDates.js :

workspace/events/cardDates.js

/**

* Generate an array of years and an array of months for

* use in the frontend form

*/

const Event = function (req, res, data, callback) {

const MONTHS_TO_GENERATE = 12

const YEARS_TO_GENERATE = 30

const currentYear = new Date().getFullYear()

let years = []

let months = [] // produces an array similar to the following

// [ '2017', '2018', '2019', '2020', '2021', '2022'... ]

for (let year = 0; year <= YEARS_TO_GENERATE; year++) {

years.push((currentYear + year).toString())

} // produces the following array

// [ '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12' ]

for (let month = 1; month <= MONTHS_TO_GENERATE; month++) {

months.push(month < 10 ? `0${month}` : month.toString())

}



data.years = years

data.months = months callback(null)

} module.exports = function (req, res, data, callback) {

return new Event(req, res, data, callback)

}

To tell Web about this event, edit the page specification file to add a “preloadEvents” section:

{

"page": {

"name": "Payment",

"description": "Honestly, it's for a good cause",

"language": "en"

},

"routes": [

{

"path": "/payment"

}

],

"preloadEvents": [

"cardDates"

]

}

Now when we load the page it will contain an array of months and years in the data context, so we can iterate over these preloaded values in the form:

<select name="exp_month">

<option disabled selected>Expiry Month</option>

{#months}

<option value="{.}">{.}</option>

{/months}

</select>

<select name="exp_year">

<option disabled selected>Expiry Year</option>

{#years}

<option value="{.}">{.}</option>

{/years}

</select>

Adding feedback to the page

Finally, let’s add some error output to the page template so we can let the customer know when something’s gone wrong:

{?err}

<mark>{err.message}</mark>

{/err}

Check your progress