GET requests that take parameters need to pass them as query string arguments
jkakar opened this issue · comments
The way Heroics works right now is that parameters interpolated into
the URL are passed as positional arguments when the link method is
invoked. If the endpoint accepts a body, you pass that as the final
argument, and the link method machinery figures out that it needs to
treat it differently. For non-GET methods this means sending it as
the content body.
For GET requests we need to do something different. The basic idea
I've had is that you'd pass in a single-level hash and the key/value
pairs there would be turned into query string arguments. So for a GET
on /resource/link
you'd do something like:
client.resource.link(param1: 'value', param2: 10, param3: nil)
And this would be invoked on a URL like:
/resource/link?param1=value¶m2=10¶m3
There's an open question about how to handle duplicate keys. One
possibility is to treat arrays in a special way. For example, a call
like:
client.resource.link(param: [10, 12, 14])
Could invoke a URL like:
/resource/link?param=10¶m=12¶m=14
Arrays are often done with something like /resource/link?param[]=10¶m[]=12¶m=14
, but it is defacto to do so, at best (not in any spec that I'm aware of). Another option might be to just do normal query encoding all the times and/or allow you to explicitly set a query string if it doesn't match. I dunno, I'd probably just start with GET setting query params naively and deal with the array case if/when it comes up?
I'm inclined to wait on handling the array case, too.
One of the local modifications to the heroics gem I've made is a fix for this. I'm not sure if this is the right thing to do. However, it does work for our internal applications! :)
diff --git a/lib/heroics/link.rb b/lib/heroics/link.rb
index d8b429d..0ad0695 100644
--- a/lib/heroics/link.rb
+++ b/lib/heroics/link.rb
@@ -47,8 +47,20 @@ module Heroics
path = "#{@path_prefix}#{path}" unless @path_prefix == '/'
headers = @default_headers
if body
- headers = headers.merge({'Content-Type' => 'application/json'})
- body = MultiJson.dump(body)
+ case @link_schema.method
+ when :put, :post, :patch
+ # pass in parameters as json for PUT/POST/PATCH
+ headers = headers.merge({'Content-Type' => 'application/json'})
+ body = MultiJson.dump(body)
+ when :get, :delete
+ # pass in parameters as URI query for GET/DELETE
+ if body.is_a?(Hash)
+ query = body
+ else
+ query = MultiJson.load(body)
+ end
+ body = nil
+ end
end
cache_key = "#{path}:#{headers.hash}"
if @link_schema.method == :get
What do you think? I did run in to your array encoding conundrum, but was able to sidestep the issue in our API.
(To be clear, Excon automatically encodes query string parameters from a hash parameter!)
Seems pretty reasonable, and just deferring to excon for encoding is probably a good call.
Closed in #75