こんにちは!
DX が流行っている影響で、今まで SaaS サービスを利用していたけど自社システム運用をしたい企業様が大変増えてきました。今まで Amazon を使用して商品販売していたけど、自社ブランドで商品販売したいので EC システムを0から構築〜運用する、というお客様が多くいらっしゃいます。
本記事では、決済サービス選定の思考フローから、多種多様なサービスでよく利用される決済サービス「PayJP」を使用した決済処理構築手順を紹介&解説します。
TypeScript で綺麗に書いたコードも後述しますので、PayJPで実装を検討されている方は必見です。
決済サービスには、ソフトバンク社の提供する SBPS や、ペイパル社の提供する PayPal、キャリア決済 ( Docomo, Softbank, Au ) 等様々なサービスが存在しますが、どれを選べば良いのか悩みどころだと思います。
私たちは、決済サービスを以下の指標で選定しています。
特に決済サービスがベンダーロックインになってしまうケースが度々ありますので、将来的な展望を見据えてしっかり慎重に選定することをお勧めします。ここを慎重にやらずに進めると、後々実装面で痛手を被ります。
PayJP を利用する上で重要となる3つの機能を紹介します。以下3つを抑えれば、基本的な実装は全て対応できるかと思います。
機能 | 概要 |
---|---|
カード情報のトークン化 | ユーザーが入力したクレジットカード情報をトークン文字列化します。これにより、ユーザーは一度入力したクレジットカード情報について、トークンを使用して呼び出すことが可能となります。 |
支払い処理 | クレジットカードのトークンを使用して、即時決済を行います。 |
定期課金 | クレジットカードのトークンを使用して、定期決済プランの作成を行います。 定期課金の停止から再開、課金間隔の指定など柔軟に行うことが可能です。 |
PayJP では、WEB フロントエンド、NodeJS 向けに SDK が提供されていますので、それを呼び出すだけで簡単にクレジットカードのトークンを取得することができます。
取得したクレジットカードのトークンと、PayJP 管理画面で生成したシークレットトークンを使用して、サーバーサイド(NodeJS)で支払い要求を行うワークフローとなります。
※ よくある決済サービスと同様にクレジットカード番号を直接 PayJP へリクエストする形ではなくトークンを使用して支払い要求を行います
※ 定期支払いの場合は別途定期決済用のプラン作成などが必要です
まずはじめに、PayJP にはサーバーサイド用 SDK、フロントエンド用 SDK の2種類が提供されています。
ここで1点、実装方法の紹介の前に、残念なお知らせがあります。
こちらのIssueで取り上げているように、TypeScript 形式のモジュールの提供はありません。
そのため、後述しますが自前で TypeScript に対応させることが必要 ( ≒ 推奨 ) なのと、加えて CDN 提供しかされていないので DOM のマウント後に CDN を読み込むカスタム実装が必要となります。
私たち独自の、TypeScript を使用した実装方法を紹介します。先ほどあげた残念なところもうまく回避していますので、ぜひ参考にしてください。
appendPayJpScriptTag
関数に payjp.js を読み込む Script
タグを生成処理実装しています。これにより、CDN 提供しかされていないモジュールに対応することが可能です。また、payjp.js のコールバックを受ける関数をグローバルに定義することが必要なため、window オブジェクトに関数をアサインして対応しています。
import _ from "lodash";
type Option = {
id?: string;
src?: string;
class?: string;
"data-partial"?: boolean; //入力後にtokenを作成しwindowを閉じるか否か
"data-text"?: string;
"data-submit-text"?: string;
"data-lang"?: string;
"data-on-created"?: string;
"data-on-failed"?: string;
"data-name-placeholder"?: string;
};
export default class PayjpService {
private dataKey: string;
private scriptTagAppendDom: HTMLElement;
private option?: Option;
private defaultOption: Option = {
id: "payjp-script",
src: "https://checkout.pay.jp/",
class: "payjp-button",
"data-partial": true,
"data-text": "決済画面に進む",
"data-submit-text": "支払い",
"data-lang": "ja",
"data-on-created": "onTokenCreated",
"data-on-failed": "onTokenFailed",
};
constructor(
dataKey: string,
scriptTagAppendDom: HTMLElement,
onTokenCreated: Function,
onTokenFailed: Function,
option?: Option
) {
this.dataKey = dataKey;
this.scriptTagAppendDom = scriptTagAppendDom;
this.option = option;
window.onTokenCreated = onTokenCreated;
window.onTokenFailed = onTokenFailed;
}
public appendPayJpScriptTag() {
const option: Option = Object.assign(
{
...this.defaultOption,
"data-key": this.dataKey,
},
this.option || {}
);
const scriptEl = document.createElement("script");
_.forEach(option, (v, k) => {
scriptEl.setAttribute(k, v as string);
});
this.scriptTagAppendDom.appendChild(scriptEl);
}
}
Vue ファイルでは、先程の appendPayJpScriptTag
関数を DOM のマウント後に実行し、Script
タグを生成しています。
// Vue
import {
defineComponent,
onMounted,
useContext
} from "@nuxtjs/composition-api";
import _ from "lodash";
import PayjpService from "~/services/payjpService";
export default defineComponent({
middleware: "authenticated",
setup() {
const context = useContext();
const onTokenCreated = () => {
settlementLoading.value = true;
const payjpTokenElm = document.getElementsByName(
"payjp-token"
)[0] as HTMLInputElement;
if (!payjpTokenElm) throw new Error("not found token element.");
const token = payjpTokenElm.value;
console.log(token);
// TODO: トークンをサーバーへ送信し決済処理を完了させること(以下API送信処理を参考)
setTimeout(() => {
settlementLoading.value = false;
settlementComplete.value = true;
}, 2000);
};
const onTokenFailed = (res: Error) => {
throw new Error(JSON.stringify(res.message, null, 2));
};
onMounted(() => {
// HTML描画のDOMに依存する処理なのでMauntedにて実行
const scriptTagAppendDom = document.getElementById("payjp-area");
if (scriptTagAppendDom === null)
throw new Error("not found scriptTagAppendDom.");
const payjpService = new PayjpService(
context.$config.PAYJP_PUBLIC_KEY, // nuxt.config.jsのpublicRuntimeConfigに要設定
scriptTagAppendDom,
onTokenCreated,
onTokenFailed
);
payjpService.appendPayJpScriptTag();
});
return {
columns,
settlementLoading,
settlementComplete,
onClickBackToMypage,
};
}
});
本記事では、チェックアウトと呼ばれる PayJP が用意してくれている UI を使用するサンプルとなっていますが、独自に UI 実装を行いたい場合は、payjp.js 実装ガイドを見ながら実装してください。独自の UI・デザインへも柔軟に対応可能となっています。
本記事では PayJP を使用した決済処理を紹介しましたが、口座振替などの要件に対応する場合は SBPA 等々のサービスの利用を検討してください。
PayJP は手軽にクレジットカード決済を実現できますのでオススメのサービスとなっています。
DX に関する決済処理・決済プラットフォーム・AWS の開発はお気軽にお問い合わせください。
スモールスタート開発支援、サーバーレス・NoSQLのことなら
ラーゲイトまでご相談ください
低コスト、サーバーレスの
モダナイズ開発をご検討なら
下請け対応可能
Sler企業様からの依頼も歓迎