Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Stripe Appsではじめる サービス連携・UIカスタマイズ/stripe-apps-1

Stripe Appsではじめる サービス連携・UIカスタマイズ/stripe-apps-1

More Decks by Hidetaka Okamoto (Stripe)

Other Decks in Programming

Transcript

  1. Stripe Appsではじめる
    サービス連携・UIカスタマイズ
    JP_Stripes in サッポロ Vol.7 Stripe再入門 & アプリ開発入門
    @hidetaka_dev
    June 2022

    View Slide

  2. 2
    #Stripe #JP_Stripes
    https://marketplace.stripe.com/

    View Slide

  3. 2022/06/18時点でStripe AppsはPublic Betaです。
    システムや機能が大きく変わる可能性があることに
    ご了承ください。

    View Slide

  4. Stripe Apps: Stripeを拡張し、運営を効率化するツール
    4
    JP_Stripes in サッポロ Vol.7 Stripe再入門 & アプリ開発入門
    運用の効率化
    ● 複雑な決済処理フローを簡素化
    ● Stripe APIを組み合わせたタスク
    ● 外部サービスと連携した自動化
    ● 独自WF用のPrivateアプリ開発
    ツール間のコンテキスト共有
    ● Stripeとツールでデータをリンク
    ● より詳細なビジネス分析
    ● CRMでの顧客管理
    ● 会計データの自動連携
    Why use Stripe Apps?
    Now available in beta

    View Slide

  5. Stripe Apps活用方法は3種類(現時点ではAのみ)
    A. Privateアプリを開発し、自社で必要なデータ連携や
    ワークフローの自動化効率化を実現する
    B. Marketplaceのアプリを組み合わせ、
    ノーコードで業務の効率化を実現する
    C. Marketplaceにアプリを公開し、
    自社サービスの顧客獲得やネイティブ課金での収益化を実現する
    5
    JP_Stripes in サッポロ Vol.7 Stripe再入門 & アプリ開発入門
    #JP_Stripes

    View Slide

  6. 機能 Marketplace公開済みアプリの例
    会計業務効率化 Xero, Bench
    マーケティング・CRM・顧客サポート Intercom, Mailchimp, SendOwl
    コンテンツ・コラボレーション・スケジューリング DocuSign, Dropbox, Nylas
    金融業務 Ramp, FundBox
    分析 Baremetrics, Chartmogul
    Climate Persefoni, Climatiq, Vaayu
    Others (e.g. 税務, データ連携 Exemptax.com, Render
    Appでできること(例)
    Stripe Apps
    6

    View Slide

  7. マーケットプレイスからアプリをインストール
    7
    JP_Stripes in サッポロ Vol.7 Stripe再入門 & アプリ開発入門
    #JP_Stripes

    View Slide

  8. インストール時に権限確認(& アカウント連携)
    8
    JP_Stripes in サッポロ Vol.7 Stripe再入門 & アプリ開発入門
    #JP_Stripes

    View Slide

  9. セットアップが完了すると、ダッシュボードに表示
    9
    JP_Stripes in サッポロ Vol.7 Stripe再入門 & アプリ開発入門
    #JP_Stripes

    View Slide

  10. [設定 > インストール済みアプリ]からアプリ管理
    10
    JP_Stripes in サッポロ Vol.7 Stripe再入門 & アプリ開発入門
    #JP_Stripes

    View Slide

  11. アプリのUIはページ毎に設定可能
    ● ダッシュボードのページ毎に
    表示内容が変更可能 ( Viewport )
    ● 開発時に表示させたいViewportを指定する
    ○ stripe.dashboard.customer.detail
    ○ stripe.dashboard.drawer.default
    ○ settings
    ● ページ毎に固有のコンテキストがある
    ○ 顧客詳細ページ: customer id
    ○ 商品詳細ページ: product id
    ○ etc…
    11
    JP_Stripes in サッポロ Vol.7 Stripe再入門 & アプリ開発入門

    View Slide

  12. Stripe Apps開発入門

    View Slide

  13. 開発ドキュメント: stripe.com/docs/stripe-apps
    13
    JP_Stripes in サッポロ Vol.7 Stripe再入門 & アプリ開発入門
    #JP_Stripes

    View Slide

  14. Stripe CLIからセットアップ
    14
    JP_Stripes in サッポロ Vol.7 Stripe再入門 & アプリ開発入門
    # v1.8.11以前の場合はアップグレード
    $ stripe version
    # Apps開発用のStripeアカウントにログイン
    $ stripe login
    # Apps用のプラグインをインストール
    $ stripe plugin install apps
    # アプリセットアップ
    $ stripe apps create helloworld

    View Slide

  15. セットアップ時にアプリIDと表示名を設定
    ● アプリIDはグローバルで一意
    ○ 重複が発生すると、
    apps uploadでのアップロードが
    エラーになるケースも
    ○ 重複しにくいIDを設定しよう
    ● 表示名・IDどちらも後から変更可能
    ○ stripe-app.json
    ○ 混乱を避けるため、
    IDはupload後からは変更しない
    ● npmまたはyarnを使って
    プロジェクトセットアップ
    ○ PCに未インストールの場合は
    インストールしてリトライ
    15
    JP_Stripes in サッポロ Vol.7 Stripe再入門 & アプリ開発入門
    🖊 Enter details of your new Stripe app (these can be changed later)
    ✔ App ID: com.example.helloworld-1█
    ✔ Display name: Helloworld 1█
    ✔ Created skeleton files
    ✔ Created default view
    ✔ Wrote package.json
    yarn add v1.22.17
    info No lockfile found.
    [1/5] Validating package.json...
    [2/5] Resolving packages...

    View Slide

  16. Stripe CLIでローカル開発を開始
    16
    JP_Stripes in サッポロ Vol.7 Stripe再入門 & アプリ開発入門
    $ stripe apps start
    [18:17:37] compiled successfully
    💻 Running development server on http://localhost:4242 (^C to
    quit)
    ✨ You can now preview Helloworld 1 in your Stripe account.
    🌐 Press Enter to open the Stripe dashboard
    ● デフォルトでは、顧客詳細ページのみ
    ● 初回起動時は確認画面が表示される

    View Slide

  17. Appsの実装はReact & TypeScript
    ● 専用のUIコンポーネントのみを使う
    ○ @stripe/ui-extension-sdk/ui
    ○ HTMLタグなどはエラーに
    ○ CSSはinlineで定義
    ○ React Nativeに近い
    ● ページ毎にエントリーポイント
    ○ 1ファイル1ページ
    ○ default exportした要素が親に
    ○ stripe-app.jsonで設定を確認
    ● 3つのViewコンポーネントを親に設定
    ○ ContextView: 標準
    ○ FocusView:  モーダル的要素
    ○ SettingsView: 設定ページ
    17
    JP_Stripes in サッポロ Vol.7 Stripe再入門 & アプリ開発入門
    import { Box, ContextView, Inline, Link } from "@stripe/ui-extension-sdk/ui";
    import type { ExtensionContextValue } from "@stripe/ui-extension-sdk/context";
    const App = ({ userContext, environment }: ExtensionContextValue) => {
    return (


    css={{
    background: "container",
    marginTop: "small",
    padding: "large",
    }}>
    Edit{" "}
    src/views/App.tsx{" "}
    and save to reload this view.


    View Slide

  18. 利用できるUI要素はドキュメント参照
    18
    JP_Stripes in サッポロ Vol.7 Stripe再入門 & アプリ開発入門
    #JP_Stripes

    View Slide

  19. ページの追加はstripe apps add
    ● ダッシュボードのページID指定か
    設定ページかを選べる
    ● Viewを選んだ場合は、
    追加したいページのviewport idを指定
    ● 追加すると、stripe-app.jsonが更新される
    ○ ui_extensions.viewが増える
    ○ viewportがviewportのID
    ○ componentが読み込むファイル名
    ● Viewportの一覧と詳細
    https://stripe.com/docs/stripe-apps/refere
    nce/viewports 
    19
    JP_Stripes in サッポロ Vol.7 Stripe再入門 & アプリ開発入門
    $ stripe apps add
    Use the arrow keys to navigate: ↓ ↑ → ←
    ? Select an entry point:
    ▸ view
    settings
    ? Select a viewport to go into:
    ▸ stripe.dashboard.payment.list
    stripe.dashboard.payment.detail
    stripe.dashboard.customer.list
    stripe.dashboard.customer.detail
    stripe.dashboard.invoice.list
    stripe.dashboard.invoice.detail
    ✔ Enter view name (e.g. ExampleComponentName): PaymentListView█

    View Slide

  20. React Hookでデータ処理を実装
    ● useState / useMemo / useEffect
    useCallback + React Context / etc..
    ● UIコンポーネントのonイベントや
    useEffectなどでイベントを発火
    ● 注意点(一部)
    ○ Refは現状未サポート
    ○ Reactはバージョンv17
    ○ 環境変数設定不可
    ● 実装の詳細や注意点
    https://stripe.com/docs/stripe-apps/how-u
    i-extensions-work  
    20
    JP_Stripes in サッポロ Vol.7 Stripe再入門 & アプリ開発入門
    export const usePaymentLinkDetail = (
    environment: ExtensionContextValue["environment"]
    ) => {
    const paymentLinkId = useMemo(() => {
    if (environment.objectContext.object !== "payment_link") return null;
    return environment.objectContext.id || null;
    }, [environment]);
    const [paymentLink, setPaymentLink] = useState(null);
    useEffect(() => {
    if (!paymentLinkId) return;
    stripeClient.paymentLinks.retrieve(paymentLinkId)
    .then((link) => setPaymentLink(link))
    }, [setPaymentLink, paymentLinkId]);
    return { paymentLink, loadPaymentLinkDetail };
    };

    View Slide

  21. AppsでStripe SDK(node)が利用可能
    ● サーバー側アプリなしで
    Stripe APIが呼び出せる
    ● Stripeクラスの初期化時に
    ui-extension-sdk/http_clientの
    ヘルパーを利用
    ● データ連携機能を組み込みたい場合、
    このSDKでWebhook管理するAPIを利用
    https://stripe.com/docs/stripe-apps/build-
    backend#receiving-events-webhooks 
    ● 事前に権限設定が必要なことに注意
    https://stripe.com/docs/stripe-apps/refere
    nce/permissions 
    21
    JP_Stripes in サッポロ Vol.7 Stripe再入門 & アプリ開発入門
    import Stripe from "stripe";
    import {
    createHttpClient,
    STRIPE_API_KEY,
    } from "@stripe/ui-extension-sdk/http_client";
    export const stripeClient = new Stripe(STRIPE_API_KEY, {
    httpClient: createHttpClient() as Stripe.HttpClient,
    apiVersion: "2020-08-27",
    });
    #設定
    stripe apps grant permission "PERMISSION_NAME" "EXPLANATION"
    #解除
    stripe apps revoke permission "PERMISSION_NAME"

    View Slide

  22. 外部API呼び出しは、事前登録と署名チェックが必要
    ● Stripe API以外のAPIを呼ぶには、
    ホワイトリストへの登録が必須
    ○ stripe apps grant url
    ○ URLと用途を登録
    ● ワイルドカード(*)はサブドメインのみ
    ● 動的なパスを持つ場合、
    「https://example.com/api/」のように
    「/」で終わる形で登録する
    ● 実装詳細:
    https://stripe.com/docs/stripe-apps/buil
    d-ui#use-third-party-apis
    22
    JP_Stripes in サッポロ Vol.7 Stripe再入門 & アプリ開発入門
    22
    $ stripe apps grant url
    ✔ Enter a connect-src URL (to call a third-party API from your app): https://e
    Enter a connect-src URL (to call a third-party API from your app):
    https://example.com/api
    ✔ Enter a purpose for the grant: Processing subscription event in our SaaS
    ser
    Enter a purpose for the grant: Processing subscription event in our SaaS
    server
    ✔ Granted url https://example.com/api

    View Slide

  23. 署名チェックはフロント・サーバー両方に実装
    23
    JP_Stripes in サッポロ Vol.7 Stripe再入門 & アプリ開発入門
    const stripe = require('stripe')(process.env.STRIPE_API_KEY);
    // Find your app's secret in your app settings page in the Developers
    Dashboard.
    const appSecret = 'absec_...';
    app.post('/do_secret_stuff', (request, response) => {
    const sig = request.headers['stripe-signature'];
    // Retrieve user id and account id from the request body
    const payload = JSON.stringify({
    user_id: request.body['user_id'],
    account_id: request.body['account_id']
    });
    try {
    // Verify the payload and signature from the request with the app secret.
    stripe.webhooks.signature.verifyHeader(payload, sig, appSecret);
    } catch (error) {
    response.status(400).send(error.message);
    }
    import fetchStripeSignature from '@stripe/ui-extension-sdk/signature';
    const App = ({ userContext, environment }) => {
    const makeRequestToMyBackend = async (endpoint, requestData) =>
    {
    // By default the signature is signed with user id and account id.
    const signaturePayload = {
    user_id: userContext?.id,
    account_id: userContext?.account.id,
    };
    return fetch(`https://example.com/${endpoint}/`, {
    method: 'POST',
    headers: {
    'Stripe-Signature': await fetchStripeSignature(),
    'Content-Type': 'application/json',
    },
    body: JSON.stringify({ ...requestData, ...signaturePayload, }),
    });
    };
    ...
    }

    View Slide

  24. 外部サービスとの連携は、原則OAuth 2.0 PKCE
    ● Privateアプリやローカルで試す分には、
    APIキー認証でも動作します
    ○ Marketplaceに公開する場合は、
    OAuth 2.0 PKCEを利用
    ● createOAuthStateや
    Apps用のリダイレクトURLで実装
    ● 認証成功後のアクセストークンは
    StripeのSecret Store APIに保存
    ● 実装詳細:
    https://stripe.com/docs/stripe-apps/oau
    th
    24
    JP_Stripes in サッポロ Vol.7 Stripe再入門 & アプリ開発入門
    import {createOAuthState} from '@stripe/ui-extension-sdk/oauth';
    import type {ExtensionContextValue} from '@stripe/ui-extension-sdk/context';
    const clientID = 'your_client_id';
    const getRedirectURL = (mode: 'live' | 'test') => `https://dashboard.stripe.com/${ mode ===
    'test' ? 'test/' : ''}apps-oauth/com.example.oauth-example`;
    const getAuthURL = (state: string, challenge: string, mode: 'live' | 'test') =>
    `https://www.example.com/oauth2/authorize?response_type=code&client_id=${clientID}&re
    direct_uri=${getRedirectURL(mode)}&state=${state}&code_challenge=${challenge}&code_ch
    allenge_method=S256`;
    const ExampleApp = ({environment}: ExtensionContextValue) => {
    const {mode} = environment;
    const [authURL, setAuthURL] = useState('');
    useEffect(() => {
    createOAuthState().then(({state, challenge}) => {
    setAuthURL(getAuthURL(state, challenge, mode));
    });
    }, [mode]);

    View Slide

  25. Stripe Apps開発のおさらい
    ● 基本的にはReact + TypeScriptアプリ
    ○ UIコンポーネントやCSS・環境変数などに制約あり
    ○ Stripe SDK(node)がそのまま使える
    ○ ユニットテストはJest
    ● 1View 1ファイルのNext.jsに近いスタイル
    ○ Viewの追加や変更はCLIとstripe-app.json
    ● 外部APIやサービス連携も可能
    ○ ただしホワイトリストの登録やOAuth 2.0での連携などが必要
    25
    JP_Stripes in サッポロ Vol.7 Stripe再入門 & アプリ開発入門
    #JP_Stripes

    View Slide

  26. サンプルコード:
    https://github.com/stripe/stripe-apps/tree/main/examples
    ● 開発の参考になるサンプルアプリ群
    ○ TODO
    ○ Webhookインストール
    ○ OAuth
    ○ FocusView / SettingsView
    ○ etc..
    26
    JP_Stripes in サッポロ Vol.7 Stripe再入門 & アプリ開発入門

    View Slide

  27. ビデオチュートリアル(英語)
    27
    JP_Stripes DeepDive 2022/05
    https://www.youtube.com/watch?v=0Ha5NRIs49o

    View Slide

  28. Discord: #stripe-apps-beta-help
    28
    JP_Stripes DeepDive 2022/05
    https://discord.com/channels/841573134531821608/974592073229549638

    View Slide

  29. 日本語チュートリアル in Qiita
    29
    JP_Stripes DeepDive 2022/05
    https://qiita.com/hideokamoto/items/0a167387d046e154d2cf

    View Slide

  30. 今後のロードマップ(一部)
    30
    JP_Stripes DeepDive 2022/05

    View Slide