RubyでPayPayのAPIを呼んでみる

# 目的
PayPayのAPIをRubyで使いたいです。しかし公式のSDKはPython, Node, PHP, JavaしかないのでREST APIを叩くことにします。リファレンスは[こちら](https://www.paypay.ne.jp/opa/doc/jp/v1.0/webcashier)です。APIキーの取得などは[Developerサイト](https://developer.paypay.ne.jp/)で確認してください。

# プログラム
プログラムはNodeのSDKのコードを参考に作りました。リファレンスもかなり詳細に書いてあるので助かります。APIはQRコードの作成だけ実装してあります。

```ruby:Gemfile
# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem 'httpclient'
```

```ruby:paypay.rb
require 'base64'
require 'json'
require 'openssl'
require 'securerandom'
require 'time'
require 'httpclient'

module PayPay
  PROD = 'api.paypay.ne.jp'
  STAGING = 'stg-api.sandbox.paypay.ne.jp'
  PERF_MODE = 'perf-api.paypay.ne.jp'

  class QrCodeCreateBuilder
    def initialize()
      @result = {
        amount: {
          amount: 0,
          currency: 'JPY',
        },
        orderItems: [],
        metadata: {},
        codeType: 'ORDER_QR',
        storeInfo: 'store',
        storeId: '1',
        terminalId: '1',
        requestedAt: Time.now.to_i,
        redirectUrl: 'https://paypay.ne.jp/',
        redirectType: 'WEB_LINK',
        isAuthorization: false,
        authorizationExpiry: Time.now.to_i + 60,
      }
    end

    def merchantPaymentId(uuid = nil)
      @result["merchantPaymentId"] = uuid.nil? ? SecureRandom::uuid : uuid
    end

    def addItem(name, category, quantity, product_id, unit_amount)
      item = {
        name: name,
        category: category,
        quantity: quantity,
        productId: product_id,
        unitPrice: {
          amound: unit_amount,
          currency: 'JPY',
        },
      }
      @result[:orderItems] << item
      @result[:amount][:amount] = @result[:amount][:amount] + quantity * unit_amount
    end

    def finish()
      @result
    end
  end

  class Client
    def initialize(api_key, api_secret, merchant_id, production_flag = false, pref_flag = false)
      @api_key = api_key
      @api_secret = api_secret
      @merchant_id = merchant_id
      @host_name = 'https://' + if pref_flag
        PERF_MODE
      elsif production_flag
        PROD
      else
        STAGING
      end
    end

    def qr_code_create(params)
      method = 'POST'
      url = '/v2/codes'
      opa, content_type = PayPay.calc(@api_key, @api_secret, url, method, params)
      client = HTTPClient.new()
      #client.debug_dev = STDOUT
      client.post(@host_name + url, params.to_json, {"Authorization" => opa, "X-ASSUME-MERCHANT" => @merchant_id, 'Content-Type' => content_type})
    end
  end

  def self.calc(api_key, api_secret, url, method, body)
    nonce = SecureRandom.alphanumeric(8)
    epoch = Time.now.to_i.to_s
    payload, content_type = if body.nil? || body == ""
      ['empty', 'empty']
    else
      content_type = 'application/json;charset=UTF-8;'
      [
        Base64.strict_encode64(
          OpenSSL::Digest::MD5.digest(
            content_type + body.to_json
          )
        ),
        content_type
      ]
    end
    hashed64 = Base64.strict_encode64(
      OpenSSL::HMAC.digest(
        'sha256',
        api_secret,
        [url, method, nonce, epoch, content_type, payload].join("\n")
      )
    )
    ["hmac OPA-Auth:#{[api_key, hashed64, nonce, epoch, payload].join(":")}", content_type]
  end
end
```

```ruby:main.rb
require './paypay'

builder = PayPay::QrCodeCreateBuilder.new()
builder.merchantPaymentId()
builder.addItem("ame", "sugger", 1, "1", 1)

client = PayPay::Client.new(ENV['API_KEY'], ENV['API_SECRET'], '12345')
response = client.qr_code_create(builder.finish())
pp response
```

# まとめ
当初RubyとPayPayでぐぐったら誰かサンプルくらい書いてるかと思ったけど全然書いて無くて涙目でした。リファレンスがちゃんとしているので実装しやすいREST APIだと思います。もしお仕事でちゃんと使うなら他のSDKと同等くらいにしてgemで公開しようかと思います。