LoginSignup
23
26

More than 5 years have passed since last update.

LINE Pay APIをPythonから叩いてみた

Posted at

こんにちは、こちらは国産Web API Advent Calendar 2018の1日目の記事です (※誰がなんと言おうと1日目の記事です、依頼日は12/4、投稿日は12/17でも1日目の記事です) 。普段はLINE株式会社でClovaのSoftware engineerをしています。本日はLINE Pay API (Clova APIじゃない!?) をPythonから叩いてみたというお題目で記事を書きたいと思います。

はじめに

本記事はLINE株式会社の許諾を得て投稿していますが、本記事で紹介するソースコードはLINE公式ではありません。ご利用の際は自己責任でお願い致します。

本記事は「LINE Pay APIを使ってアプリに決済を組み込む方法」をPythonで書いてみたものになります。LINE Payを使うまでの下準備 (アカウント登録、Sandbox環境の準備、など) はこちらが大変分かりやすいのでそちらを参照してください。

前置きが長くなりましたが、LINE Pay APIは誰でも無償で申請でき、簡単に利用できます。組み込み実装も簡単でした。なぜかネット上でLINE Pay API使ってみた系の情報があまり見つからず、唯一こちらのNode.js版の非公式SDKだけが有用な情報だったので、今回はPythonでSDK的な何かを作ってLINE Pay APIを使ってみたいと思います。

必要なもの

  • LINE Pay Sandbox環境
  • 固定IPがあるサーバー
  • Python 3.6

ソースコード

下準備 (LINE Pay Sandbox環境の準備)

こちらを参考にしてください。

LINE Pay APIをPythonから叩いてみる

今回のデモの決済の流れは、ざっくりと以下になります。

支払い予約 (Server) → ユーザーの認可 (Client) → 支払いの実行 (Server)

とにかく一旦デモを動かしてみましょう。

$ git clone https://github.com/keigohtr/line-pay-python-example.git
$ cd line-pay-python-example

app.pyというのがデモの本体です。LINE Pay Sandbox環境のパラメータを設定してください。

LINE_PAY_CHANNEL_ID = 'your channel'
LINE_PAY_CHANNEL_SECRET = 'your secret'

下記コマンドでデモを起動します。デモを起動すると http://localhost:5000/ に「LINE Pay」ボタンがあります。押すとLINE認証の要求画面が出て、認証後に「チョコレート」を「1円」で決済できます。これはデモなので安心して決済してください。Sandbox環境では実際にお金を支払うことはありません。

$ pip install -r requirements.txt
$ python app.py
$ open http://localhost:5000/

デモの構成

line-pay-python-example
 |- app.py          Flask Webサービス
 |- line_pay.py     自家製LINE Pay SDK的な何か
 |- models/         sqliteでtransaction IDを管理
 |- static/         今回はLINE Payのiconを格納
 |- templates/      Flask + Jinja2のテンプレート

WebフレームワークとしてFlaskを使いました。SQLAlchemyでsqliteのDBを立て、transactionの管理をしています。非常にシンプルな構成です。line_pay.py というLINE Pay SDK的な何かを作りましてLINE Pay APIの全てを網羅しましたが、動作確認できているのは今回のデモで使用した「支払い予約 POST: /v2/payments/request」と「支払い実行 POST: /v2/payments/{transaction_id}/confirm」だけですのでご注意ください。

デモの実装を追ってみる

設定項目は以下の4つです。

LINE_PAY_URL = 'https://sandbox-api-pay.line.me'
LINE_PAY_CHANNEL_ID = 'your channel'
LINE_PAY_CHANNEL_SECRET = 'your secret'
LINE_PAY_CONFIRM_URL = 'http://localhost:5000/pay/confirm'
pay = LinePay(channel_id=LINE_PAY_CHANNEL_ID, channel_secret=LINE_PAY_CHANNEL_SECRET,
              line_pay_url=LINE_PAY_URL, confirm_url=LINE_PAY_CONFIRM_URL)

今回のデモではLINE_PAY_URLがsandbox環境に向いています。Productionで利用する場合はProduction用のURLを使いますが、その前にLINE Pay APIの利用審査があります。LINE_PAY_CONFIRM_URLは「支払い予約」をしてユーザーが支払いOKと決めたとき、LINE Pay側からデモサーバーにcallbackするURLになります。デモではlocalhostを向いていますが、Productionで利用する場合はLINE Pay Developersに設定したとおり「固定IP」を持つ「https」のエンドポイントである必要があります。以上の4つの設定項目がLinePayclassの最低限必要な引数となります。

続いて、支払い予約の部分を解説します。

@app.route("/pay/reserve", methods=['POST'])
def pay_reserve():
    product_name = "チョコレート"
    amount = 1
    currency = "JPY"

    (order_id, response) = pay.request_payments(product_name=product_name, amount=amount, currency=currency)
    transaction_id = response["info"]["transactionId"]
    obj = Transactions(transaction_id=transaction_id, order_id=order_id,
                       product_name=product_name, amount=amount, currency=currency)
    db.session.add(obj)
    db.session.commit()
    db.session.close()
    redirect_url = response["info"]["paymentUrl"]["web"]
    return redirect(redirect_url)

今回のデモではproduct_nameamountcurrencyを決め打ちにしました。支払い予約をするためには、product_nameamountcurrencyorder_idをLINE Pay APIにPOST: /v2/payments/requestする必要があります。order_idはorder毎に振られるユニークな値でユーザーが自由に定義することができます。デモではpay.request_payments()の中でorder_idを自動生成し、APIリクエストを行っています。

APIレスポンスには色々と含まれているのですが、支払い予約が成功しているならばresponse["info"]["transactionId"]transaction_idが含まれています。transaction_idはLINE Pay側から吐き出されたユニークな値です。自分たちのサービスで吐き出されたtransactionであることをちゃんと管理したいので、transaction_idはDBに保存しておきます。最後に、response["info"]["paymentUrl"]["web"]に「ユーザーの認可」用のredirect_urlが含まれていますので、ClientをredirectしてユーザーにLINE Payで認可してもらいます。

続いて、支払い実行部分を解説します。

@app.route("/pay/confirm", methods=['GET'])
def pay_confirm():
    transaction_id = request.args.get('transactionId')
    obj = Transactions.query.filter_by(transaction_id=transaction_id).one_or_none()
    if obj is None:
        raise Exception("Error: transaction_id not found.")

    response = pay.confirm_payments(transaction_id=transaction_id, amount=obj.amount, currency=obj.currency)
    db.session.query(Transactions).filter(Transactions.transaction_id == transaction_id).delete()
    db.session.commit()
    db.session.close()
    return "Payment successfully finished."

ユーザーがLINE Payで認可していれば、callbackに指定したURLにGETでcallbackが返ってきます。Query parameterにtransaction_idが含まれているので、先程DBに保存した値と一致するかチェックします。自分たちのサービスで吐き出されたtransactionであることが確認できたら、実際に支払い実行を行います。支払い実行をするためには、amountcurrencyをLINE Pay APIにPOST: /v2/payments/{transaction_id}/confirmする必要があります。デモではpay.confirm_payments()の中で適切なURLにAPIリクエストを行っています。

APIリクエストに成功したら、DBから当該transaction_idのエントリを削除します。ただ、実際にProduction環境で利用する場合は、DBエントリを削除するのではなく"支払い済み"statusでもつけてください。transaction_idorder_idは過去に実行したTransactionの参照や管理にも使いますので。

おわりに

今回はLINE Pay APIをPythonから叩いてみました。APIドキュメントは非常に読みやすく、構成もシンプルです。今回のデモを作るにあたって詰まった場所はありませんでしたし、組み込み難易度は非常に低いと思います。まだまだLINE Pay APIを使ってみた系の有用な情報が少ないと感じましたので、今回の記事が参考になれば幸いです。

参考情報

筆者について

LINE株式会社でSoftware engineerをしています、服部 (keigohtr) です。担当プロダクトはClovaで、担当領域はNLU (Natural Language Understanding) および機械学習まわりです。Kubernetes上で機械学習モジュールの配信基盤を作っていて、一連のソフトウェアをRekcurdと名付けてOSSとして公開しています。スターください(迫真)。また個人的に情報科学技術をWebAPIで売り買いできるWebAPIのマーケットプレイス Apitore を運営しています。世の中のあらゆる技術を簡単にデプロイでき、かつ誰でも簡単に利用できる、そんな世界を夢見ています。

23
26
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
26