interagent / heroics

Ruby HTTP client for APIs represented with JSON schema

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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&param2=10&param3

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&param=12&param=14

Arrays are often done with something like /resource/link?param[]=10&param[]=12&param=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