Polymer + Firebase + Stripe で寄付コンポーネント


[Polymer Cafe #1](https://polymer-japan.connpass.com/event/77121/)でのLT資料です。ちなみに制限時間5分で2-3ページ分しかしゃべれませんでした、、、

## 自己紹介

- ニックネーム: howking     
  ![howking](https://avatars3.githubusercontent.com/u/13231263?v=4&s=80)  
  開発環境: <img src="https://qiita-image-store.s3.amazonaws.com/0/90678/c4014b17-fbc7-6aad-b258-83f225750a74.png" height="27"> Chromebook + <img src="https://qiita-image-store.s3.amazonaws.com/0/90678/2f45f001-ff71-9263-d8e1-bcfcb78e95c6.png" height="27"> Emacs
- 元々サーバサイドエンジニアで、フロントエンド(Polymer)歴は2年半ぐらい  
  <img src="https://cdn.rawgit.com/Polymer-Japan/polymer-jp.org/e3e3db98/assets/logos/polymer-jp-logo-mark-32.png" height="28"> [Polymer-jp.org](https://polymer-jp.org)のサイト構築のお手伝いしてます。  
- <img src="https://qiita-image-store.s3.amazonaws.com/0/90678/1605c056-5516-c3b8-6eb3-502636296202.png" width="24"> [Qiita](https://qiita.com/howking)にちょこちょこPolymerネタを書いてます。
  * [Polymer サンプルコード (1)](https://qiita.com/howking/items/d23c850265c0965ef55c) 〜 [(6)](https://qiita.com/howking/items/953d016ea6e948ed77cd#_reference-ac11dd4043e73850cf7e)
  * [Web Componentsを公開しよう!](https://qiita.com/howking/items/dedda16b890d9a7e8328)
  * [Polymer-jp.orgを支える技術](https://qiita.com/howking/items/4861c6fcc26e9120ee06) 等  
- 今日の資料もQiitaにアップ予定、ソースコードは [Polymer-Japan/polymer-jp.org#30](https://github.com/Polymer-Japan/polymer-jp.org/pull/30)

## 概要

  - Polymer-jp.orgにStripeで寄付ボタンを設置してみた
    - Polymer-jp.orgとは
        * **100% pure <img src="https://www.polymer-project.org/images/logos/p-logo.png" height="26"> Polymer Library & Toolbox**
        * **100% only <img src="https://firebase.google.com/_static/images/firebase/touchicon-180.png" height="30"> Firebase Infrastructure**
        * 特色: PWA (Lighthouse100点)、Markdownで動的にコンテンツ編集できる
    - <img src="https://stripe.com/img/about/logos/logos/blue.png" height="25"> [Stripe](https://stripe.com/jp)とは
        * 最近カード決済では急成長している決済代行会社(手数料: 一律3.6%)
        * [Stripe Elements](https://stripe.com/docs/stripe-js/elements/payment-request-button)のPayment Request Buttonを設置(いわゆるWeb Componentではない)
        * [Payment Request API](https://developers.google.com/web/fundamentals/payments/?hl=ja), Android, Apple Pay対応 
  - ざっくり決済フローとその実装
    * 今後のWebアプリ時代で快適な決済方法
  - まとめ、感想
    * 注意点やセキュリティなど

## 寄付コンポーネント(使い方)

https://polymer-jp.org/about/ のページの一番下  

<img src="https://qiita-image-store.s3.amazonaws.com/0/90678/6a24fb28-44c2-c530-c142-db02abfbae2f.png">

※ **注意!** 実際に**100円**課金されます。
※ **Mac Safariで現状動いてない**です。。。([公式サンプル](https://stripe.com/docs/stripe-js/elements/payment-request-button)でも表示されない?)  
  実質 PCはChromeのみ、iPhoneはApple PayでOK、AndroidもOK。

## フロー

<img src="http://www.plantuml.com/plantuml/png/TLHRQnD157wVNp74jq2hlXQH6X7qhLXz4y9aTj8ioSx4sLdJ8aAoOxLAIx68YXSmfM9LR5fyAQtQ7pFTNlw5PtOtsSqsGc3td9plEz-vxQolY5I1rq9-q-Lj8ec77oECFS45RKZXCQnamC3ZDuWZEYvVm7NIygrddZqC6AUi8XOhX3ONf0YuSrEqXCIN7CSfH0ZfC9dysscuoXBCGMgNkct2rHnn7CjzzGhu8JndFq4Drs6uBeIgYKM425N0STzd4XCV1_14uCUb1_osy1M0Ia3HpgXnAHeyFJvyPy9VHiFlaz6_ZLwBtrTAbgF3QWN8l99kczrgCO-11I6iLVLZNo6m8aKdLL9BNX7Z3hP2Kr6u7d2gNC5zR8LHmPKKBUm8JXIpk3gj9aOHIThkT99qcWhlGbMNQOFHfWXKN8ElgaDxGY2H2omBizOe6IA14ZpmQY0TsMxYgUks8tW66_tUzYhSZzRVH7_VsiwxZwngsx2HCQmRMH1WHwq2XcZbs-dhxTEDtMXJczwEqJqJVZLQct2G4MIzZIckJKsDSPpi7PpihqJhWpFz9rLeGrA9tTLqkbsOw4SJ7jcvXXjd_UtJhOEie3pXP0oe2mT6Vq_LeGm1yBJ66LZPfNWbxjhDzXM-CNSdfoaD6uaskcl2BHDk6ltJXBkcspj__kgylmR9YWABq1Ez77tUWy1e-KlqyaDUptYcSjc4F-ALVf5WokM2-DngsEh7eo73URTtVDJFvf5VfKBQSIfV19AogX9Dnf739XDC6kd_W8LD0EsZuoYW9iZExWXbg67vTkKj1QEIgMgJBS4inlYwlQJloO0ApOWF9iSwQaLAcwxepkhnmRCBZKZ0mpRa2xhN8Bo9bqHWT3zUkyFatBBYSbovyWetaD5aQvK3scFDcSDpdOKF07pt_m40">

<a href="http://www.plantuml.com/plantuml/uml/TLHRQnD157wVNp74jq2hlXQH6X7qhLXz4y9aTj8ioSx4sLdJ8aAoOxLAIx68YXSmfM9LR5fyAQtQ7pFTNlw5PtOtsSqsGc3td9plEz-vxQolY5I1rq9-q-Lj8ec77oECFS45RKZXCQnamC3ZDuWZEYvVm7NIygrddZqC6AUi8XOhX3ONf0YuSrEqXCIN7CSfH0ZfC9dysscuoXBCGMgNkct2rHnn7CjzzGhu8JndFq4Drs6uBeIgYKM425N0STzd4XCV1_14uCUb1_osy1M0Ia3HpgXnAHeyFJvyPy9VHiFlaz6_ZLwBtrTAbgF3QWN8l99kczrgCO-11I6iLVLZNo6m8aKdLL9BNX7Z3hP2Kr6u7d2gNC5zR8LHmPKKBUm8JXIpk3gj9aOHIThkT99qcWhlGbMNQOFHfWXKN8ElgaDxGY2H2omBizOe6IA14ZpmQY0TsMxYgUks8tW66_tUzYhSZzRVH7_VsiwxZwngsx2HCQmRMH1WHwq2XcZbs-dhxTEDtMXJczwEqJqJVZLQct2G4MIzZIckJKsDSPpi7PpihqJhWpFz9rLeGrA9tTLqkbsOw4SJ7jcvXXjd_UtJhOEie3pXP0oe2mT6Vq_LeGm1yBJ66LZPfNWbxjhDzXM-CNSdfoaD6uaskcl2BHDk6ltJXBkcspj__kgylmR9YWABq1Ez77tUWy1e-KlqyaDUptYcSjc4F-ALVf5WokM2-DngsEh7eo73URTtVDJFvf5VfKBQSIfV19AogX9Dnf739XDC6kd_W8LD0EsZuoYW9iZExWXbg67vTkKj1QEIgMgJBS4inlYwlQJloO0ApOWF9iSwQaLAcwxepkhnmRCBZKZ0mpRa2xhN8Bo9bqHWT3zUkyFatBBYSbovyWetaD5aQvK3scFDcSDpdOKF07pt_m40"><img src="https://qiita-image-store.s3.amazonaws.com/0/90678/8527ed9e-21ee-164d-dadb-2f8bb2a9d92a.png" height="26"> PlantUML</img></a>

## 寄付ボタンの表示部分 /about

- コンテンツにMarkdownで寄付コンポーネントのタグ(`<polymer-jp-donate>`)を入れて表示しています。

```markdown
# 寄付

以下のボタンで100円寄付されます(検証中)。
<polymer-jp-donate pub-key="pk_test_uUgI4YrGzPWHLamUPQZpaTNW" amount="100"></polymer-jp-donate>
寄付金についてはサイトやイベントの運用費用に充てさせていただきます。
```

- 公開キーはStripeの管理画面から

![Stripe](https://qiita-image-store.s3.amazonaws.com/0/90678/a8491afa-8c11-801a-4f2e-488484a51d5a.png)

## 寄付ボタンコンポーネント
- ほぼStripeが公開している[サンプルコード](https://github.com/stripe/elements-examples)のまま。

```html:src/polymer-jp-donate.html
...
<script src="https://js.stripe.com/v3/"></script>

<dom-module id="polymer-jp-donate">
  <template>
    <style>
      ...
      [hidden] {
        display: none !important;
      }
    </style>
    <!-- 寄付ボタン -->
    <div id="payment-request">
      <div id="payment-request-button" hidden$="[[_sourceId]]"></div>
    </div>
  ...
```

## 寄付ボタンの生成

- `pub-key`と`amount`で指定された属性を使ってStripeElementを生成(指定した金額で実際に決済(charge)されない)

```javascript:src/polymer-jp-donate.html
    class PolymerJpDonate extends Polymer.Element {
      ...
      ready(){
        const stripe = Stripe(this.pubKey);
        const paymentRequest = stripe.paymentRequest({
          country: 'JP', currency: 'jpy',
          total: { label: '合計',  amount: this.amount }
        });
        // 決済に対応しているブラウザであれば、Elementを表示
        paymentRequest.canMakePayment().then(ok=>{
          if (! ok) return;
          stripe.elements().create('paymentRequestButton', {
            paymentRequest,
            style: {
              paymentRequestButton: { type: 'donate', theme: 'light-outline' }
            }
          }).mount(this.shadowRoot.querySelector('#payment-request-button'));
        });
        ...
```

## 寄付ボタンクリック時

- ダイアログからの戻りを定義

```javascript:src/polymer-jp-donate.html
    class PolymerJpDonate extends Polymer.Element {
      ...
      ready(){
        ...
        paymentRequest.on('source', e => {
          try {
            this.set('_sourceId',e.source.id);
            this.set('_donateResponse','...');
            e.complete('success');
          } catch (error) {
            e.complete('fail');
          }
        });
        ...
```

## source_tokenの処理と完了メッセージ

- `<iron-ajax>`で`_souceId`を取得した時点で`/donate`を呼び出し、戻り値を`_donateResponse`に格納する

```html:src/polymer-jp-donate.html
    <iron-ajax
      auto="[[_sourceId]]"
      url="/donate?sid=[[_sourceId]]"
      handle-as="text"
      last-response="{{_donateResponse}}"></iron-ajax>

    <!-- 決済完了のメッセージ -->
    <div id="donate-response" hidden="[[!_sourceId]]">[[_donateResponse]]</div>
  </template>
  <script>
```

## stripeへの決済

- `config.stripe.amount`の金額で実際に決済される

```javascript:functions/index.js
const stripe = require("stripe")(config.stripe.token);
...
exports.donate = functions.https.onRequest((req, res) => {
  ...
  stripe.charges.create({
    amount: config.stripe.amount,
    currency: "jpy",
    source: req.query.sid,
    description: "Polymer-jp donate"
  }, (err, charge)=>{
    ...
    if(err){
      return res.status(500).end();
    }
    res.send('Thank you!!');
  });
});
```

- 参考URL: [firebase/functions-samples/stripe](https://github.com/firebase/functions-samples/tree/master/stripe)

## まとめ、感想

- Stripeはすぐ使えてお手軽! [Payment Request API](https://developers.google.com/web/fundamentals/payments/?hl=ja)のUIも素晴しい
  * 入金には身分証を送る必要があるけど、その場でなくてもよい
  * PCI DSS準拠 カード番号を知らなくて済む
  * Apple Payは管理画面でドメイン設定、ファイル配置が必要
  * [Stripe Elements](https://stripe.com/docs/stripe-js/elements/payment-request-button)はhttps接続が必須([ngrok](https://ngrok.com)は動作検証に便利だった)
- Firebase Functionsはローカルエミュレータがv6.11.x縛りでデバックしにくい  
  firebaseは有料プランにしないと外部APIが叩けないので注意
- Polymer
  手軽にWebコンポーネントにできて便利!
 
  **(Polymerを使って)素敵な有料Webアプリをつくっていきましょう!**
  
  <img alt="polymer" src="https://www.polymer-project.org/images/logos/p-logo.png" width="70"> <img src="https://firebase.google.com/_static/images/firebase/touchicon-180.png" width="70"> <img src="https://stripe.com/img/about/logos/logos/blue.png" width="100">

# :bow: 以上!


ご静聴、ありがとうございました! (よかったら寄付お願いします!w)

<img alt="qrcode" width="150" src="https://qiita-image-store.s3.amazonaws.com/0/90678/516d9caa-56d9-12ac-ceac-0229204d5339.png">