HitoHana(ひとはな)の舞台裏

HitoHana(ひとはな)運営の舞台裏をご紹介いたします!

RMSのAPIをRubyで実装したい 4/3 (楽天ペイ対応)

前回のブログより

新人の田中です。この記事ではRMSの受注APIをRailsのアプリケーションに導入した事例を紹介しています。前回一応出来上がりはしたのですが、完成度に物足りなさを感じ、機能を追加しよう!というところまで進みました。

追加しようとした機能はこちら

  • ログを出力する
  • APIの深いネスト構造をカプセル化し、外から必要な属性に簡単にアクセスできるようにする

なんですが

会社のRMSの契約が変更となり、楽天ペイというサービスを使うことになったため、楽天ペイのAPIで上記の機能も含めて実装することになりました。

ですので今回の記事からは受注APIではなく、楽天ペイAPIのお話です。ご注意ください。

backstage.hitohana.tokyo

まずはいつものように完成形をイメージしてみる

完成形はいつもみたいにクラスメソッドを呼び出す感じにします。

また、クラスメソッド名、リクエストのパラメタ名、レスポンスへのアクセス方法もいままでと同じようなルールにします。

# メソッドの種類や引数の型や内容は公式ページを参照してください。
# - メソッド名
#     公式のAPI名をスネークケースにしたもの。
#         ex) getOrder => get_order, updateOrderShipping => update_order_shipping
# - 引数名
#     公式では引数名をスネークケースとしたもの。ただし、先頭文字が大文字の場合は引数名の先頭のみ大文字とする。(ちょっと苦しい)
#         ex) order_number => orderNumber, ShippingModelList => Shipping_model_list

response = Rms::PayOrder.get_order(order_number_list: ['楽天の注文番号1', '楽天の注文番号2'])

# - レスポンスへのアクセス
#     公式の属性名をスネークケースにしたメッセージをレスポンスのボディへ送ることでアクセスする。
#         ex) orderModelList => order_model_list

r_orders = response.body.order_model_list

# ついでにレスポンスのHTTPステータスはAPIの戻り値にstatusメッセージを投げることで取得する。

result = response.status
# => 200

実装の方針

楽天ペイAPIは受注APIとは違ってSoap通信ではありません。そこで今回は拡張性の高いMiddlewareパターンを実装できるFaradayを使うことにしました。

github.com

github.com

実装

まずメインのソースはこちら。クラス全体のデザインはこれまでと変わりありません。なお、初期設定やRms::Auth.keyについてはこのシリーズの第2回の記事を参照してください。

require 'faraday'
require 'rms/auth'
require 'rms/middleware'

module Rms
  class PayOrder
    BASE_URL = 'https://api.rms.rakuten.co.jp'.freeze
    API_METHODS = %w[
      get_order
      search_order
      confirm_order
      update_order_shipping
      update_order_delivery
      update_order_orderer
      update_order_remarks
      update_order_sender
      update_order_memo
      get_payment
      cancel_order
      get_sub_status_list
      update_order_sub_status
    ].freeze

    class << self
      API_METHODS.each do |api_method|
        define_method api_method do |args = nil|
          connection.post do |req|
            req.url "/es/2.0/order/#{api_method.camelize(:lower)}"
            req.headers['Content-Type'] = 'application/json; charset=utf-8'
            req.headers['Authorization'] = Rms::Auth.key
            req.body = args
          end
        end
      end

      private

      def connection
        Faraday.new(url: BASE_URL) do |faraday|
          faraday.request  :camelcase
          faraday.request  :url_encoded
          faraday.request  :json

          faraday.response :logger
          faraday.response :mashify
          faraday.response :snakecase
          faraday.response :json, content_type: /\bjson$/

          faraday.use :instrumentation
          faraday.adapter Faraday.default_adapter
        end
      end
    end
  end
end

connectionメソッドで使用するmiddlewareのほとんどはfaradayやfaraday_middlewareのものをそのまま使用していますが、一部自作しました。それらのソースがこちらです。 なお、deep_transform_keysメソッドなど、active_supportが読み込まれていることが前提のコードです。

require 'faraday'
require 'faraday_middleware'

module Rms
  class Middleware
    autoload :Camelcase, 'rms/middleware/camelcase'
    autoload :Snakecase, 'rms/middleware/snakecase'

    if Faraday::Middleware.respond_to? :register_middleware
      Faraday::Request.register_middleware \
        camelcase: -> { Camelcase }

      Faraday::Response.register_middleware \
        snakecase: -> { Snakecase }
    end
  end
end
module Rms
  class Middleware
    class Camelcase < Faraday::Middleware
      def call(env)
        if env[:body].respond_to? :deep_transform_keys!
          env[:body].deep_transform_keys! do |key|
            if key.to_s.first =~ /[A-Z]/
              key.to_s.camelize(:upper)
            else
              key.to_s.camelize(:lower)
            end
          end
        end
        @app.call env
      end
    end
  end
end
module Rms
  class Middleware
    class Snakecase < Faraday::Response::Middleware
      def on_complete(env)
        if env[:body].respond_to? :deep_transform_keys!
          env[:body].deep_transform_keys! { |key| key.to_s.underscore }
        end
      end
    end
  end
end

これではじめのサンプルコードが動くようになりました! 記事のボリュームが多くなってしまったので今回はここまでとします。faradayやmiddlewareについては次回記載しようと思います。

すでに 4/3 回となってしまいましたが、このシリーズはもうちょっとだけ続きます。

おわりに

HitoHana(ひとはな)では、仕事が大好きで個性的なエンジニアを大募集しています!

www.wantedly.com