はじめに
先月メルカリさん主催のイベントに参加し、実はその時に初めてPaymentRequestAPIなるものの存在を知りました。触ってみたいなと思いつつも結局はまだ触らず終いでした。
そんな中、昨日このようなツイートを拝見しました。
まもなくリリースされる新しいSafariでは、Payment Request APIを介してApple Payを利用できるようになります。その仕様が公開されましたhttps://t.co/GiRrywgrMv
— Eiji Kitamura / えーじ (@agektmr) 2018年3月27日
いいきっかけだと思って触ってみることにしました。
PaymentRequestAPIとは
先ほどのツイートをされている方が書いた記事になります。ここに凝縮されています。
ウェブでの新しいお金の払い方 - Web Payments と Payment Request API について: Tender Surrender
Payment Request API は、ウェブでの支払いを標準化しようという一連の仕様である Web Payments を構成する要素のひとつであり、中心を成すものです。Web Payments を構成する要素には下記のようなものがあります。
・Payment Request API
・Payment Handler API
・Payment Method Identifiers
・Basic Card Payment
→Payment Request APIというのはそれ単体で決済完了までできるものではなく、決済の仕組みの中の構成要素の一つなんですね。
Payment Request API を使ってできることは、基本的にフォームの置き換えになります。それ自体は支払い処理を行わない、という点に注意してください。つまり、この API を使ってできるのは支払情報を取得するところまでであり、その先の支払い処理は別途開発者が行わなければなりません。
→あくまでも入力フォームの置き換えで、決済処理自体は自分たちでやってね、とのこと。
専用の入力フォームの表示と支払情報の取得までがこのAPIの役割みたいです。
デモサイト
https://polykart-credential-payment.appspot.com/
先ほどの記事内にリンクがあったので貼っておきます。
(実際に商品を購入することはできません。また、クレジットカードなどの情報がサーバーに渡されることはありません)。
とのことです。
統合ガイドの写経
Payment Request API: 統合ガイド
いろいろ書いてありますが、一番下にまとめのコードがあります。このscriptを
function onBuyClicked(event) {
if (!window.PaymentRequest) {
return;
}
// Payment Request API is available.
// Stop the default anchor redirect.
event.preventDefault();
var supportedInstruments = [{
supportedMethods: [
'visa', 'mastercard', 'amex', 'discover', 'maestro',
'diners', 'jcb', 'unionpay', 'bitcoin'
]
}];
var details = {
displayItems: [{
label: 'Original donation amount',
amount: { currency: 'USD', value: '65.00' }
}, {
label: 'Friends and family discount',
amount: { currency: 'USD', value: '-10.00' }
}],
total: {
label: 'Total due',
amount: { currency: 'USD', value : '55.00' }
}
};
var options = {
requestShipping: true,
requestPayerEmail: true,
requestPayerPhone: true,
requestPayerName: true
};
// Initialization
var request = new PaymentRequest(supportedInstruments, details, options);
// When user selects a shipping address
request.addEventListener('shippingaddresschange', e => {
e.updateWith(((details, addr) => {
var shippingOption = {
id: '',
label: '',
amount: { currency: 'USD', value: '0.00' },
selected: true
};
// Shipping to US is supported
if (addr.country === 'US') {
shippingOption.id = 'us';
shippingOption.label = 'Standard shipping in US';
shippingOption.amount.value = '0.00';
details.total.amount.value = '55.00';
// Shipping to JP is supported
} else if (addr.country === 'JP') {
shippingOption.id = 'jp';
shippingOption.label = 'International shipping';
shippingOption.amount.value = '10.00';
details.total.amount.value = '65.00';
// Shipping to elsewhere is unsupported
} else {
// Empty array indicates rejection of the address
details.shippingOptions = [];
return Promise.resolve(details);
}
// Hardcode for simplicity
if (details.displayItems.length === 2) {
details.displayItems[2] = shippingOption;
} else {
details.displayItems.push(shippingOption);
}
details.shippingOptions = [shippingOption];
return Promise.resolve(details);
})(details, request.shippingAddress));
});
// When user selects a shipping option
request.addEventListener('shippingoptionchange', e => {
e.updateWith(((details) => {
// There should be only one option. Do nothing.
return Promise.resolve(details);
})(details));
});
// Show UI then continue with user payment info
request.show().then(result => {
// POST the result to the server
return fetch('/pay', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(result.toJSON())
}).then(res => {
// Only if successful
if (res.status === 200) {
return res.json();
} else {
throw 'Failure';
}
}).then(response => {
// You should have received a JSON object
if (response.success == true) {
return result.complete('success');
} else {
return result.complete('fail');
}
}).then(() => {
console.log('Thank you!',
result.shippingAddress.toJSON(),
result.methodName,
result.details.toJSON());
}).catch(() => {
return result.complete('fail');
});
}).catch(function(err) {
console.error('Uh oh, something bad happened: ' + err.message);
});
}
// Assuming an anchor is the target for the event listener.
document.querySelector('#start').addEventListener('click', onBuyClicked);
また、
Payment Request API shim の読み込み
セクションに追加することを強くお勧めします。
この開発中の標準 API に随時対応する手間を省くために、この shim をコードの
とのことなのでこれを<head>
内に書きました。ちなみに書かなくても動きました。
<script src="https://storage.googleapis.com/prshim/v1/payment-shim.js">
結果
ほんとクライアントサイドは簡単できちゃいました。
なお、PAY.JPとの連携をしている記事があったので参考に貼らせてもらいます。
PAY.JP で Google Chrome の Payment Request API を使って決済する
まとめ
このAPIを介してApplePayが使えるようになる、というのが最初のツイートの内容ですね。今でもすでにそれができるようになるJSがあるみたいですけど、もっとシームレスに簡単に連携できるということなのでしょうか。わかりません。
また、最初のリンクに記載がありますが、モバイルでの購入処理の取りやめはパソコンでのそれの2倍らしいです。やっぱりスマホは入力しづらいですもんね。アマゾンなんかは1クリックで買えちゃうのでほんと便利だなと思います。
アマゾンのような会員を抱えているサービスであれば別にわざわざこのAPIを使う必要はなさそうですが、顧客情報・支払情報を持っていない新規サービスには有用だなと思いました。
今後決済のあるサービスを作る場合は検討してみようと思います。