0

I'm working on a small program to get from and post to several resources for an API. The current version of my program works fine but isn't very legible, so now I'm trying to refactor my code in order to get a better separation of concerns (prep the data, send the data, logging, etc). But now I'm stuck.

I've figured out a way to send for a method ( api_call ) from within another ( send_data ) method (using send), that also feeds into a logger. This seems like a nice seperation of concerns. However, I can't figure out how to apply the necessary parameters to the method I'm sending for.

I've tried following a few other stackoverflow questions and tutorials related to send and params, but I can't seem to figure how to do it correctly.

If I don't include the params, I obviously get a "0 for n" error. If I try including them into the send, I get an error telling me it doesn't expect parameters.

  1. What would be a good way to send for the api_method from within send_data , whilst allowing me to variably set the params?

  2. Should I perhaps set the params in an array, and *splat that array as params? I'm not entirely sure how I'd do that.

  3. Is this even a smart way of approaching this? I'm thinking I might as well just create some more methods for different resources, which inherit from "api_call", so I can get rid of most params? But that doesn't seem very DRY?

Here's a simplified example of my code:

class ApiConnector

  def send_data(method_name)
    begin
      @attempts += 1
      puts "#{@attempts}th attempt"
      send(method_name)     # (how) do I set params here?
    rescue Errno::ETIMEDOUT => e
      retry if @attempts < 3
    end
  end

  def api_call(endpoint_URL: , resource: 'cases' , action: nil , method: 'get', uuid: nil)
    request = Typhoeus::Request.new(
      "#{endpoint_URL}/api/v1/#{resource}/#{uuid}/#{action}",
      verbose: true,
      method: :post,
      headers: { 'Content-Type' => "multipart/form-data", "API-key" => "123", "API-Interface-ID" => "123", "User-Agent" => "AGENT" }
    )

    request.run 
  end

end

Any referrals to relevant documentation are obviously also welcome. Much obliged.

4
  • 1
    Are all the arguments keyword arguments as in api_call? Are they all positional? A mix of both? Commented Nov 1, 2018 at 14:47
  • 1
    I'm not sure how this code is supposed to work. Should send_data call api_call or vice versa? If so, where does that call happen? What kind of "params" do you want to pass and where do these "params" come from? It would certainly help to see the (maybe simplified) current version of your program, i.e. working code. Commented Nov 1, 2018 at 14:48
  • @muistooshort I would prefer keyword args, but could go for a positional version. Commented Nov 5, 2018 at 15:58
  • @Stefan send_data calls for the api_call. I would at least like to use the following params: - endpoint_url - a resource (i.e. "cases" or "users" or "documents") - the method (post or get) in order to use the 'general' api_call method to retrieve various resources (instead of several methods for several resources). Commented Nov 5, 2018 at 15:58

2 Answers 2

1

perhaps better to use the condition solely for this method:

if method == :api_call
  send method_name, endpoint_URL: __TEST_URL__, resource: 'cases' , action: nil , method: 'get', uuid: nil
else
  send method_name
end

If I don't include the params, I obviously get a "0 for n" error.

try to specify all of args for current method, looks like is missed endpoint_URL:

def api_call(endpoint_URL: _MISS_, resource: 'cases' , action: nil , method: 'get', uuid: nil)
Sign up to request clarification or add additional context in comments.

Comments

0

The method api_call from your question use the modern syntax of keyword arguments. You could call this method using send with arguments passed as a hash:

params = {
  endpoint_URL: 'https://www.google.com',
  # other params
}
send(:api_call, params)

(Since endpoint_URL argument has no default value you have to pass it to avoid ArgumentError error)


If the method was written using common positional arguments:

def api_call(endpoint_URL, resource = 'cases' , action = nil , method = 'get', uuid = nil)
  # ...
end

you could call it with send as well, but the array of arguments should be *splat:

params = [
  'https://www.google.com',
  # other params
]
send(:api_call, *params)

1 Comment

Thanks! I will give that a try!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.