DEV Community

Andrey Krivko
Andrey Krivko

Posted on

Use webmock for stubbing multiple body parameters with the same name

If you use Faraday to perform requests it's likely you'll have to use the Faraday::FlatParamsEncoder.

Faraday.new(url: base_url) do |faraday|
  faraday.request :url_encoded # form-encode POST params
  faraday.options.params_encoder = Faraday::FlatParamsEncoder
  ...
end

It converts the JSON parameters to query string removing square brackets, so instead of converting { key: ['value1', 'value2'] } to key[]=value1&key[]=value2 it will convert it to key=value1&key=value2 instead. This approach is used in many services, for example, in Twilio API.

The problem happens when you try to stub that API using webmock. By default webmock does not support multiple parameters with the same name in url encoded body. So the key=value1&key=value2 will become key=value1. Here are the related issues:

The basic suggestion in the webmock repo is to use: WebMock::Config.instance.query_values_notation = :flat_array option. I prefered the different approach though.

As Faraday encodes the body with Faraday::FlatParamsEncoder we can manually encode the body and pass the result to webmock.

stub_request(:post, twilio_api_url("Accounts/#{subaccount_sid}/Calls.json"))
  .with(body: Faraday::FlatParamsEncoder.encode(request_params))
  .to_return(body: response_body)

The following code block also works, but for consistency with the faraday behavior, I used the above one.

stub_request(:post, twilio_api_url("Accounts/#{subaccount_sid}/Calls.json"))
  .with(body: URI.encode_www_form(request_params))
  .to_return(body: response_body)

I hope this will help someone or at least save some time.

Top comments (0)