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:
- https://github.com/bblimke/webmock/issues/227
- https://github.com/bblimke/webmock/issues/490
- https://github.com/bblimke/webmock/issues/584
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)