T

SPIKEのWebhookをRailsで受け取る

久しぶりにブログでも書こう。

手数料無料の驚きのカード決済サービスSPIKE、使わない手はないということで試してみたのだけれど、RailsでWebhookを受け取るとエラーになってしまう。

Error occurred while parsing request parameters.
Contents:

なんかURLエンコードされた文字列

JSONをPOSTされた際にうまくパースできないようなのだが、コントローラで受けたときにはもうエラーになっているのでアプリケーションのレベルでは対処しようがない。結局、こちらを参考にモンキーパッチで動かしてみたのだけれど、もっと楽なやり方があれば教えてもらいたい。

まずはinitializerを用意して、特定のページへのアクセスでデフォルトのパーサを迂回させる。

# config/initialize/webhook.rb
# https://github.com/intridea/grape/issues/340
require File.dirname(__FILE__) + '/../../lib/webhook_parser.rb'

MyApp::Application.config.middleware.swap ActionDispatch::ParamsParser, MyApp::ParamsParser, :ignore_prefix => '/path/to/webhook'

これでwebhookへのアクセスのときはlib/webhook_parser.rbが呼び出されるようになった。

#lib/webhook_parser.rb
# https://github.com/intridea/grape/issues/340
module MyApp
  class ParamsParser < ActionDispatch::ParamsParser
    def initialize(app, opts = {})
      @app = app
      @opts = opts
      super
    end

    def call(env)
      if @opts[:ignore_prefix].nil? or !env['PATH_INFO'].start_with?(@opts[:ignore_prefix])
        super(env)
      else
        @app.call(env)
      end
    end
  end
end

これでSPIKEからのWebhookをエラー無しにコントローラで処理できるようにはなった。

  #webhookを受け取るコントローラ
  def webhook
    # SPIKEから送信されるrequest bodyから余計なバックスラッシュと先頭と最後のダブルクォートを消す
    parsed_request_body = JSON.parse(URI.decode(request.body.read).match(/\A"(.+)"\Z/)[1].gsub(/\\/, ''))
    # あとはお好きなように
  end