Itrp::Client

Client for accessing the ITRP REST API

Installation

Add this line to your application's Gemfile:

gem 'itrp-client'

And then execute:

$ bundle

Or install it yourself as:

$ gem install itrp-client

Configuration

Global

Itrp.configure do |config|
  config.api_token = 'd41f5868feb65fc87fa2311a473a8766ea38bc40'
  config.account = 'my-sandbox'
  config.logger = Rails.logger
  ...
end

All options available:

  • logger: The Ruby Logger instance, default: Logger.new(STDOUT)
  • host: The ITRP API host, default: 'https://api.itrp.com'
  • api_version: The ITRP API version, default: 'v1'
  • api_token: (required) The ITRP API token
  • account: Specify a different account to work with
  • source: The source used when creating new records
  • max_retry_time: maximum nr of seconds to wait for server to respond (default = 5400 = 1.5 hours)
    The sleep time between retries starts at 2 seconds and doubles after each retry, i.e. 2, 6, 18, 54, 162, 486, 1458, 4374, 13122, ... seconds.
    One retry will always be performed unless you set the value to -1.
  • read_timeout: HTTP read timeout in seconds (default = 25)
  • block_at_rate_limit: Set to true to block the request until the rate limit is lifted, default: false
  • proxy_host: Define in case HTTP traffic needs to go through a proxy
  • proxy_port: Port of the proxy, defaults to 8080
  • proxy_user: Proxy user
  • proxy_password: Proxy password
  • ca_file: Certificate file (defaults to the provided ca-bundle.crt file from Mozilla)

Override

Each time an ITRP Client is instantiated it is possible to override the global configuration like so:

client = Itrp::Client.new(account: 'trusted-sandbox', source: 'my special integration')

Proxy

The proxy settings are limited to basic authentication only. In case ISA-NTLM authentication is required, make sure to setup a local proxy configured to forward the requests. And example local proxy host for Windows is Fiddle.

ITRP Client

Minimal example:

require 'itrp/client'

client = Itrp::Client.new(api_token: '3a4e4590179263839...')
response = client.get('me')
puts response[:primary_email]

Retrieve a single record

The get method can be used to retrieve a single record from ITRP.

response = Itrp::Client.new.get('organizations/4321')
puts response[:name]

By default this call will return all fields of the Organization.

The fields can be accessed using symbols and strings, and it is possible chain a number of keys in one go:

response = Itrp::Client.new.get('organizations/4321')
puts response[:parent][:name]    # this may throw an error when +parent+ is +nil+
puts response[:parent, :name]    # using this format you will retrieve +nil+ when +parent+ is +nil+
puts response['parent', 'name']  # strings are also accepted as keys

Browse through a collection of records

Although the get method can be also used to retrieve a collection of records from ITRP, the preferred way is to use the each method.

count = Itrp::Client.new.each('organizations') do |organization|
  puts organization[:name]
end
puts "Found #{count} organizations"

By default this call will return all collection fields for each Organization. For more fields, check out the field selection documentation.

The fields can be accessed using symbols and strings, and it is possible chain a number of keys in one go:

count = Itrp::Client.new.each('organizations', fields: 'parent') do |organization|
  puts organization[:parent][:name]    # this may throw an error when +parent+ is +nil+
  puts organization[:parent, :name]    # using this format you will retrieve +nil+ when +parent+ is +nil+
  puts organization['parent', 'name']  # strings are also accepted as keys
end

Note that an Itrp::Exception could be thrown in case one of the API requests fails. When using the blocking options the chances of this happening are rather small and you may decide not to explicitly catch the Itrp::Exception here, but leave it up to a generic exception handler.

Retrieve a collection of records

The each method described above is the preferred way to work with collections of data.

If you really want to paginate yourself, the get method is your friend.

@client = Itrp::Client.new
response = @client.get('organizations', {per_page: 10, page: 2})

puts response.json # all data in an array

puts "showing page #{response.current_page}/#{response.total_pages}, with #{response.per_page} records per page"
puts "total number of records #{response.total_entries}"

# retrieve collection for other pages directly from the response
first_page = @client.get(response.pagination_link(:first))
prev_page  = @client.get(response.pagination_link(:prev))
next_page  = @client.get(response.pagination_link(:next))
last_page  = @client.get(response.pagination_link(:last))

By default this call will return all collection fields for each Organization. For more fields, check out the field selection documentation.

The fields can be accessed using symbols and strings, and it is possible chain a number of keys in one go:

response = Itrp::Client.new.get('organizations', {per_page: 10, page: 2, fields: 'parent'})
puts response[:parent, :name]    # an array with the parent organization names
puts response['parent', 'name']  # strings are also accepted as keys

Create a new record

Creating new records is done using the post method.

response = Itrp::Client.new.post('people', {primary_email: '[email protected]', organization_id: 777})
if response.valid?
  puts "New person created with id #{response[:id]}"
else
  puts response.message
end

Make sure to validate the success by calling response.valid? and to take appropriate action in case the response is not valid.

Update an existing record

Updating records is done using the put method.

response = Itrp::Client.new.put('people/888', {name: 'Mrs. Susan Smith', organization_id: 777})
if response.valid?
  puts "Person with id #{response[:id]} successfully updated"
else
  puts response.message
end

Make sure to validate the success by calling response.valid? and to take appropriate action in case the response is not valid.

Delete an existing record

Deleting records is done using the delete method.

response = Itrp::Client.new.delete('organizations/88/addresses/')
if response.valid?
  puts "Addresses of Organization with id #{response[:id]} successfully removed"
else
  puts response.message
end

Make sure to validate the success by calling response.valid? and to take appropriate action in case the response is not valid.

Note Attachments

To add attachments to a note is rather tricky when done manually as it involves separate file uploads to Amazon S3 and sending confirmations back to ITRP.

To make it easy, a special attachments parameter can be added when using the post or put method when the note field is available.

response = Itrp::Client.new.put('requests/416621', {
  status: 'waiting_for_customer',
  note: 'Please complete the attached forms and reassign the request back to us.',
  attachments: ['/tmp/forms/Inventory.xls', '/tmp/forms/PersonalData.xls']
})

If an attachment upload fails, the errors are logged but the post or put request will still be sent to ITRP without the failed attachments. To receive exceptions add attachments_exception: true to the data.

begin
  response = Itrp::Client.new.put('requests/416621', {
    status: 'waiting_for_customer',
    note: 'Please complete the attached forms and reassign the request back to us.',
    attachments: ['/tmp/forms/Inventory.xls', '/tmp/forms/PersonalData.xls']
  })
  if response.valid?
    puts "Request #{response[:id]} updated and attachments added to the note"
  else
    puts "Update of request failed: #{response.message}"
  end
catch Itrp::UploadFailed => ex
  puts "Could not upload an attachment: #{ex.message}"
end

Importing CSV files

ITRP also provides an Import API. The ITRP Client can be used to upload files to that API.

response = Itrp::Client.new.import('\tmp\people.csv', 'people')
if response.valid?
  puts "Import queued with token #{response[:token]}"
else
  puts "Import upload failed: #{response.message}"
end

The second argument contains the import type.

It is also possible to monitor the progress of the import and block until the import is complete. In that case you will need to add some exception handling to your code.

begin
  response = Itrp::Client.new.import('\tmp\people.csv', 'people', true)
  puts response[:state]
  puts response[:results]
  puts response[:message]
catch Itrp::UploadFailed => ex
  puts "Could not upload the people import file: #{ex.message}"
catch Itrp::Exception => ex
  puts "Unable to monitor progress of the people import: #{ex.message}"
end

Note that blocking for the import to finish is required when you import multiple CSVs that are dependent on each other.

Exporting CSV files

ITRP also provides an Export API. The ITRP Client can be used to download (zipped) CSV files using that API.

response = Itrp::Client.new.export(['people', 'people_contact_details'], DateTime.new(2012,03,30,23,00,00))
if response.valid?
  puts "Export queued with token #{response[:token]}"
else
  puts "Export failed: #{response.message}"
end

The first argument contains the export types. The second argument is optional and limits the export to all changed records since the given time.

It is also possible to monitor the progress of the export and block until the export is complete. In that case you will need to add some exception handling to your code.

require 'open-uri'

begin
  response = Itrp::Client.new.export(['people', 'people_contact_details'], nil, true)
  puts response[:state]
  # write the export file to disk
  File.open('/tmp/export.zip', 'wb') { |f| f.write(open(response[:url]).read) }
catch Itrp::UploadFailed => ex
  puts "Could not queue the people export: #{ex.message}"
catch Itrp::Exception => ex
  puts "Unable to monitor progress of the people export: #{ex.message}"
end

Note that blocking for the export to finish is recommended as you will get direct access to the exported file.

Blocking

By default all actions on the ITRP Client will block until the ITRP API is accessible, see the max_retry_time option in the configuration. This is especially helpfull for flaky internet connections.

By setting the block_at_rate_limit to true in the configuration all actions will also block in case the rate limit is reached. The action is retried every 5 minutes until the rate limit is lifted again, which might take up to 1 hour.

Exception handling

The standard methods get, post, put and delete will always return a Response with an error message in case something went wrong.

By calling response.valid? you will know if the action succeeded or not, and response.message provides additinal information in case the response was invalid.

response = Itrp::Client.new.get('organizations/1a2b')
puts response.valid?
puts response.message

The methods each and import may throw an Itrp::Exception in case something failed, see the examples above.