更新のおしらせ
本記事はwebpay-pythonのバージョン1系(できたて)に即して記述しています。
その後、メジャーバージョンアップを行いました。
ほとんどの内容はそのまま利用できますが、メソッド名などが一部変更になっています。
最新の情報はWebPay公式サイトのPython APIドキュメントを参照してください。
また、メジャーバージョンアップに合わせてgithub上のリポジトリは更新を停止しました。
ライブラリ情報はライブラリドキュメントをご覧ください。
WebPayアドベントカレンダーも後半戦に突入しました。じわりじわりと増える皆様のストック数を励みに頑張っております。
今日は「少しのコードでWebPayを導入する」シリーズです。
これまでRuby、PHPバージョンが登場していましたが、満を持して登場するのはPythonバージョンです。しかも、しかも、なんとですね、動かす環境にはGoogle App Engineを使ってみました。
昨今ではたくさんのPaaSが世の中を賑わせていて、便利なプログラミング環境が溢れているのでGAEなんて忘れてしまった人もいると思いますが、GAEは老舗の中の老舗ともいえる歴史あるPaaSです。たまにはGAEのことも思い出してあげてくださいね。
webpay-python
WebPayの公式Pythonライブラリ(webpay-python)がリリースされました!
祝リリース
さて、このPythonライブラリを使ってGAE上に爆速でWebPayを導入していきましょう。
webpay meets GAE
さっそくプログラミングを開始しましょう。GAEの大きな特徴はローカル開発向けのSDKが提供されていて、GAEの環境をローカルに再現できるところです。しかし、環境がプリセットされている反面、GAEが提供しているライブラリやバージョンに制限があるため自由にライブラリを読み込んで使うことができません。基礎的なフレームワークであればメジャーバージョンがサポートされていますが、決済ゲートウェイのライブラリなどはもちろん組み込まれていません。
今どきのプログラマーの皆さんは、車輪の再発明や自由にライブラリが使えない世界なんて耐え難い世界だと思います。私だって耐えれません。
そこでGAEで外部ライブラリを使うときのポイントも一緒に解説していくのでぜひ参考にしてください。
今回はGAEに組み込まれているwebapp2
と外部ライブラリとしてwebpay-python
を利用します。
SDKをインストールする
手元にMervericsのMacをお持ちの方であれば、
GAE SDKからGoogleAppEngineLauncher-1.8.8.dmg
をダウンロードして、開いたファイル(GoogleAppEngineLauncher.app)をApplicationフォルダに配置するだけでオッケイです。GoogleAppEngineLauncher.appを起動するとGAEのローカル開発環境用のpythonスクリプトを/usr/local/bin
にインストールしてくれます。
PythonからWebPayを使う
プロジェクト用に適当なディレクトリを用意します。そこにapp.yamlとappengine_config.pyを用意します。下のようなディレクトリ構成になっていると思います。
webpay-sample
├── app.yaml
└── appengine_config.py
app.yamlの内容は、
application: webpay-sample
version: 1
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /.*
script: main.app
このようにruntime
にはpython27
を設定しておきましょう。GAEも2.7の時代へと移ってきています。applicationにはGAEのダッシュボードで作成したapplication_idを指定しましょう。ローカルだけで試す場合はGAEのダッシュボードでアプリケーションの作成は不要です。threadsafeのパラメータは、昔GAEを使っていた人には馴染みが無いかもしれませんが、python27が使えるようになってからは明示的に指定するようになりました。(本題からそれるので詳しく解説しませんが、threadsafe: true
と設定するとprint等で標準出力を使ってクライアントにデータを返すことができなくなります。)
次は、appengine_config.py
です。
import os
import sys
ROOTPATH = os.path.dirname(__file__)
LIBPATH = os.path.join(ROOTPATH, 'lib')
sys.path.append(LIBPATH)
appengine_config.pyは特別なファイルで、プロジェクト内で共通して使われるような設定やライブラリパスの設定などに使います。今回は外部ライブラリをlib
以下に保存するので、lib
ディレクトリをライブラリパスに追加します。
いよいよメインのプログラム部分を作成します。今回は、app.yaml
でscript: main.app
と指定したので、main.py
というファイル名で作成しましょう。加えて、main.py
で読み込むテンプレートとしてindex.html
とsucceeded.html
の2つのファイルを用意します。
webpay-sample
├── app.yaml
├── lib
├── main.py
├── index.html
├── succeeded.html
└── appengine_config.py
それぞれのファイルを見てみましょう。
# -*- coding: utf-8 -*-
import os
import webapp2
from google.appengine.ext.webapp import template
from webpay import WebPay
SECRET_KEY = 'test_secret_eHn4TTgsGguBcW764a2KA8Yd'
PUBLIC_KEY = 'test_public_19DdUs78k2lV8PO8ZCaYX3JT'
class MainPage(webapp2.RequestHandler):
def get(self):
template_values = {
'public_key': PUBLIC_KEY
}
path = os.path.join(os.path.dirname(__file__), 'index.html')
self.response.out.write(template.render(path, template_values))
def post(self):
amount = self.request.POST.get('amount')
token = self.request.POST.get('webpay-token')
webpay = WebPay(SECRET_KEY)
try:
# webpay-pythonライブラリを利用したWebPayへのアクセス
charge = webpay.charges.create(
amount=amount,
currency="jpy",
card=token
)
template_values = {
'charge': charge
}
path = os.path.join(os.path.dirname(__file__), 'succeeded.html')
self.response.out.write(template.render(path, template_values))
except webpay.errors.CardError, e:
# カードが拒否された場合
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write("CardException")
self.response.out.write("Status is: %d" % e.status)
self.response.out.write("Type is: %s" % e.type)
self.response.out.write("Code is: %s" % e.code)
self.response.out.write("Param is: %s" % e.param)
self.response.out.write("Message is: %s" % e)
except webpay.errors.InvalidRequestError, e:
# リクエストで指定したパラメータが不正な場合
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write("InvalidRequestException")
except webpay.errors.AuthenticationError, e:
# 認証に失敗した場合
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write("AuthenticationException")
pass
except webpay.errors.ApiConnectionError, e:
# APIへの接続エラーが起きた場合
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write("APIConnectionException")
pass
except webpay.errors.WebpayError, e:
# WebPayのサーバでエラーが起きた場合
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write("APIException")
pass
except Exception, e:
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write("Unexpected exception")
app = webapp2.WSGIApplication([('/', MainPage)],
debug=True)
main.pyはMainPage
クラスにget
とpost
メソッドを実装したwebapp2
アプリです。
1つ目のget
メソッドでは、path = os.path.join(os.path.dirname(__file__), 'index.html')
でテンプレートのパスを作成してself.response.out.write(template.render(path, template_values))
でhtmlをレンダリングしています。CheckoutHelperで使うpublic_key
はテンプレート変数としてアサインしておきます。
charge = webpay.charges.create(
amount=amount,
currency="jpy",
card=token
)
2つ目のpost
メソッドでは、上に示しているwebpay.charges.create()
を使って課金処理を行っています。CheckoutHelperで作ったトークンがクライアントから送られてくるのでtoken = self.request.POST.get('webpay-token')
のようなコードでPOSTされた値を取得します。
最後にindex.html
とsucceeded.html
のテンプレートの中身を確認しましょう。index.html
では、RubyやPHPのアドベントカレンダーの時と同様に、カード番号を入力させるためのダイアログを表示させるCheckoutHelperというJavascriptのライブラリを利用しています。
<html>
<head>
<meta charset="utf-8">
<title>WebPay Google App Engine Python sample</title>
</head>
<body>
<h1>WebPay Google App Engine Python sample</h1>
<form action="/" method="post">
<input type="number" name="amount" value="300" /> 円を支払います。<br />
<!-- 御自身のサーバにクレジットカード情報を送信すると、クレジットカード情報を適切に扱う義務が生じます。
JavaScript を利用して webpay token を生成することで、クレジットカード情報を直接あつかわずに済みます。
webpay-token という name を持つ input が自動的に追加されます。 -->
<script src="https://checkout.webpay.jp/v1/" class="webpay-button"
data-text="カード情報を入力して支払う"
data-key="{{ public_key }}"></script>
</form>
</body>
</html>
succeeded.html
は結果を表示するだけのシンプルなテンプレートです。
<html>
<head>
<meta charset="utf-8">
<title>WebPay PHP sample</title>
</head>
<body>
<h1>お支払いありがとうございました</h1>
<ul>
<li>お支払い金額: {{charge.amount}}</li>
<li>カード名義: {{charge.card.name}}</li>
<li>カード番号: ****-****-****-{{charge.card.last4}}</li>
</ul>
</body>
</html>
ここまでで、プログラミングは終了です。
さて、いよいよライブラリの組み込みを行いましょう。
pythonのライブラリはpipやeasy_installで管理することが一般的です。しかし、それは通常のPython環境の場合であってGAE環境では異なります。今回は最初に作成したlib
ディレクトリにwebpay-python
とその依存ライブラリを配置しましょう。
まずライブラリをgit clone
します。(別の方法でライブラリを手元に用意してもいいです。 zipとかeggとか。)
mkdir tmp && cd tmp
git clone git@github.com:webpay/webpay-python.git
git clone https://github.com/kennethreitz/requests.git
cloneが完了したらライブラリをbuildします。buildが終わったら以下の様にlib
ディレクトリにbuild済みのファイルを移動します。
cd webpay-python
python setup.py build
cd ../requests
python setup.py build
cd ../../
mv tmp/webpay-python/build/lib/webpay lib/
mv tmp/requests/build/lib/requests lib/
最終的には以下の様なディレクトリ構成になっていると思います
webpay-sample
├── app.yaml
├── lib
├── webpay
└── requests
├── tmp
├── main.py
├── index.html
├── succeeded.html
└── appengine_config.py
ではローカル開発環境で動かしてみましょう。webpay-sample
ディレクトリの中で以下のコマンドを実行します。
dev_appserver.py .
http://localhost:8080/ へアクセスしてみましょう。
どうですか?表示されましたか?
うまく表示された人は、Google App Engineにデプロイしましょう。
appcfg.py update .
デプロイが終われば
のようなページが見えていると思います。rubyやphpの記事に比べると少し分量が多くなってしまいましたが、簡単かつ誰でも使うことができる代表的なPaaSであるGAEでも公式ライブラリを使ってWebPayを導入できることを体験して頂けたのではないでしょうか。
おわりに
クラウド時代の幕開けとなった懐かしのGAEでもWebPayを動かすことが出来ましたね。