simonmorley
simonmorley

Reputation: 2804

Dealing with Custom Exceptions Codes from Failed API Call

I'm connecting our Rails (3.2) application to an external web service (campaign monitor) which requires a few calls to their system to set a client up.

I've put each action into separate rescue blocks and wrapped in a transaction but things aren't looking so great. I need it to escape after each error and display the correct message. Currently it just escapes.

I have a list of possible errors per action - how is it possible to read these and format as a flash message?

For example, the following error:

 CreateSend::BadRequest: The CreateSend API responded with the following error - 172: You can create a maximum of five (5) clients per thirty (30) minutes

I currently have this in my controller:

  def create_send_setup
     ...
      begin

       client = CreateSend::Client.create(@user.company_name, @user.username, @user.email, "(GMT) Dublin, Edinburgh, Lisbon, London", @user.country)

       rescue
        flash[:notice] = "Uh oh, there's been a problem. Please try again. Client"
       end

       begin
         @client = CreateSend::Client.new(@user.createsend_client_api)
         @client.set_access(@user.username, @password, @user.createsend_access_level)
         @client.set_monthly_billing(@user.createsend_currency, true, @user.createsend_markup)

       rescue
          flash[:notice] = "Uh oh, there's been a problem. Please try again. Access"
       end

          flash[:notice] = "Great, now you just need to choose a plan"
          redirect_to edit_user_registration_path    

 end

In a previous integration, I've used something like

case bla.code.to_s
     when /2../
     when '403'
       raise "Could not update subscriber: new-customer-id is already in use."
     ...
 end

What's the best way to extract the error code from the response and display as a flash message?

Upvotes: 1

Views: 1469

Answers (3)

James Dennes
James Dennes

Reputation: 51

The best way of handling errors in this specific situation is by specifically handing the errors which the library defines itself. createsend-ruby defines CreateSendError, BadRequest, and Unauthorized. You do not need to parse any strings.

Here is an example take from the README, of handling errors:

require 'createsend'

CreateSend.api_key 'your_api_key'

begin
  cl = CreateSend::Client.new "4a397ccaaa55eb4e6aa1221e1e2d7122"
  id = CreateSend::Campaign.create cl.client_id, "", "", "", "", "", "", "", [], []
  puts "New campaign ID: #{id}"
  rescue CreateSend::BadRequest => br
    puts "Bad request error: #{br}"
    puts "Error Code:    #{br.data.Code}"
    puts "Error Message: #{br.data.Message}"
  rescue Exception => e
    puts "Error: #{e}"
end

The data field always contains a Code and Message, which correspond to the status codes API documentation.

Upvotes: 1

JeanMertz
JeanMertz

Reputation: 2270

As Dave said, if the exception is all you've got, you can only capture the exception and do something with that exception as a string.

For example:

begin
  ...
rescue Exception => ex
  # here "ex.message" contains your string, you can do anything you want with it
  # or parse as is:
  flash[:notice] = ex.message
end

redirect_to edit_user_registration_path

UPDATE

If you combine my proposed solution with those put forward by Dave, you'd get something like this, with which you can use your own error strings:

begin
  ...
rescue Exception => ex
  code = ex.message.match(/.*?- (\d+): (.*)/)[1]

  case code
  when '172'
    flash[:notice] = 'Please wait 30 minutes to create more clients'
  end
end

redirect_to edit_user_registration_path

Upvotes: 1

Dave Newton
Dave Newton

Reputation: 160191

All you can do is work with the exception given-if there's no data payload you can try to parse the message strings, use it as-is, map all or part of it to your own messages, etc.

For example, if the example message you show is normalized, a regex could be used to grab the numeric and message portions:

[1] pry(main)> s = "CreateSend::BadRequest: The CreateSend API responded with the following error - 172: You can create a maximum of five (5) clients per thirty (30) minutes"
=> "CreateSend::BadRequest: The CreateSend API responded with the following error - 172: You can create a maximum of five (5) clients per thirty (30) minutes"
[2] pry(main)> md = s.match /.*?- (\d+): (.*)/
=> #<MatchData
 "CreateSend::BadRequest: The CreateSend API responded with the following error - 172: You can create a maximum of five (5) clients per thirty (30) minutes"
 1:"172"
 2:"You can create a maximum of five (5) clients per thirty (30) minutes">
[3] pry(main)> md[1]
=> "172"
[4] pry(main)> md[2]
=> "You can create a maximum of five (5) clients per thirty (30) minutes"

Upvotes: 2

Related Questions