itrp-client 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MzMxOGY1Yzg5YmViZTBkODhlN2Q2MjM2ZmZiZDg0ZmMyZGJlM2QyYw==
5
+ data.tar.gz: !binary |-
6
+ NmRmY2MwMmQ2OGUwYTE0MmViYzJlZTE2NzE4ZDlhYTIxNjQ4OWU1NA==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NGZlYjg2NzZkYzllNDU4NWM4MDdlNjU2NGU0NjczZjZkOGZlOTFkMDQ5ODk2
10
+ ZTg4YjdjNzY5ZWJhYmQ1YTY5MWRlZWU1MzcyZjExNzA4ZDQ3YWY1OWY3ODI0
11
+ MmE4YjdmNTg5OGJjYTVkNTc1ZjJlOTBlN2FiZDUxY2ZiNmJjNGE=
12
+ data.tar.gz: !binary |-
13
+ YWRmZTQyMzNhMWViNmZkODQyMTM4YmM1MDNjZWVhNmVjMTEyY2E5NDVkYjlk
14
+ NDA1MzExM2Y4ZmZkNmI4NTNiMWFjNThiOGQwYWQzOGFmNTA4MTU3ZjIwYmY0
15
+ MTAwZDZjNjAxYThhZGI3NWQ5YjA0NTYxYzc4YWU4NDUwNTJhMTY=
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in itrp-client.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,58 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ itrp-client (1.0.0)
5
+ activesupport
6
+ gem_config
7
+ mime-types
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ activesupport (4.0.1)
13
+ i18n (~> 0.6, >= 0.6.4)
14
+ minitest (~> 4.2)
15
+ multi_json (~> 1.3)
16
+ thread_safe (~> 0.1)
17
+ tzinfo (~> 0.3.37)
18
+ addressable (2.3.5)
19
+ atomic (1.1.14)
20
+ crack (0.4.1)
21
+ safe_yaml (~> 0.9.0)
22
+ diff-lcs (1.2.4)
23
+ gem_config (0.2.4)
24
+ i18n (0.6.5)
25
+ mime-types (2.0)
26
+ minitest (4.7.5)
27
+ multi_json (1.8.0)
28
+ rake (10.1.0)
29
+ rspec (2.14.1)
30
+ rspec-core (~> 2.14.0)
31
+ rspec-expectations (~> 2.14.0)
32
+ rspec-mocks (~> 2.14.0)
33
+ rspec-core (2.14.5)
34
+ rspec-expectations (2.14.2)
35
+ diff-lcs (>= 1.1.3, < 2.0)
36
+ rspec-mocks (2.14.3)
37
+ safe_yaml (0.9.5)
38
+ simplecov (0.7.1)
39
+ multi_json (~> 1.0)
40
+ simplecov-html (~> 0.7.1)
41
+ simplecov-html (0.7.1)
42
+ thread_safe (0.1.3)
43
+ atomic
44
+ tzinfo (0.3.38)
45
+ webmock (1.13.0)
46
+ addressable (>= 2.2.7)
47
+ crack (>= 0.3.2)
48
+
49
+ PLATFORMS
50
+ ruby
51
+
52
+ DEPENDENCIES
53
+ bundler (~> 1.3)
54
+ itrp-client!
55
+ rake
56
+ rspec
57
+ simplecov
58
+ webmock
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 ITRP Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,304 @@
1
+ # Itrp::Client
2
+
3
+ Client for accessing the [ITRP REST API](http://developer.itrp.com/v1/)
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'itrp-client'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install itrp-client
18
+
19
+ ## Configuration
20
+
21
+ ### Global
22
+
23
+ ```
24
+ Itrp.configure do |config|
25
+ config.api_token = 'd41f5868feb65fc87fa2311a473a8766ea38bc40'
26
+ config.account = 'my-sandbox'
27
+ config.logger = Rails.logger
28
+ ...
29
+ end
30
+ ```
31
+
32
+ All options available:
33
+
34
+ * _logger_: The [Ruby Logger](http://www.ruby-doc.org/stdlib-1.9.3/libdoc/logger/rdoc/Logger.html) instance, default: `Logger.new(STDOUT)`
35
+ * _host_: The [ITRP API host](http://developer.itrp.com/v1/#service-url), default: 'https://api.itrp.com'
36
+ * _api_version_: The [ITRP API version](http://developer.itrp.com/v1/#service-url), default: 'v1'
37
+ * _api_token_: (**required**) The [ITRP API token](http://developer.itrp.com/v1/#api-tokens)
38
+ * _account_: Specify a [different account](http://developer.itrp.com/v1/#multiple-accounts) to work with
39
+ * _source_: The [source](http://developer.itrp.com/v1/general/source/) used when creating new records
40
+ * _max_retry_time_: maximum nr of seconds to wait for server to respond (default = 5400 = 1.5 hours)<br/>
41
+ The sleep time between retries starts at 2 seconds and doubles after each retry, i.e.
42
+ 2, 6, 18, 54, 162, 486, 1458, 4374, 13122, ... seconds.<br/>
43
+ One retry will always be performed unless you set the value to -1.
44
+ * _read_timeout_: [HTTP read timeout](http://ruby-doc.org/stdlib-2.0.0/libdoc/net/http/rdoc/Net/HTTP.html#method-i-read_timeout-3D) in seconds (default = 25)
45
+ * _block_at_rate_limit_: Set to `true` to block the request until the [rate limit](http://developer.itrp.com/v1/#rate-limiting) is lifted, default: `false`
46
+ * _proxy_host_: Define in case HTTP traffic needs to go through a proxy
47
+ * _proxy_port_: Port of the proxy, defaults to 8080
48
+ * _proxy_user_: Proxy user
49
+ * _proxy_password_: Proxy password
50
+
51
+ ### Override
52
+
53
+ Each time an ITRP Client is instantiated it is possible to override the [global configuration](#global-configuration) like so:
54
+
55
+ ```
56
+ client = Itrp::Client.new(account: 'trusted-sandbox', source: 'my special integration')
57
+ ```
58
+
59
+ ## ITRP Client
60
+
61
+ Minimal example:
62
+
63
+ ```
64
+ require 'itrp/client'
65
+
66
+ client = Itrp::Client.new(api_token: '3a4e4590179263839...')
67
+ response = client.get('me')
68
+ puts response[:primary_email]
69
+ ```
70
+
71
+ ### Retrieve a single record
72
+
73
+ The `get` method can be used to retrieve a single record from ITRP.
74
+
75
+ ```
76
+ response = Itrp::Client.new.get('organizations/4321')
77
+ puts response[:name]
78
+ ```
79
+
80
+ By default this call will return all [fields](http://developer.itrp.com/v1/organizations/#fields) of the Organization.
81
+
82
+ The fields can be accessed using *symbols* and *strings*, and it is possible chain a number of keys in one go:
83
+ ```
84
+ response = Itrp::Client.new.get('organizations/4321')
85
+ puts response[:parent][:name] # this may throw an error when +parent+ is +nil+
86
+ puts response[:parent, :name] # using this format you will retrieve +nil+ when +parent+ is +nil+
87
+ puts response['parent', 'name'] # strings are also accepted as keys
88
+ ```
89
+
90
+ ### Browse through a collection of records
91
+
92
+ 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.
93
+
94
+ ```
95
+ count = Itrp::Client.new.each('organizations') do |organization|
96
+ puts organization[:name]
97
+ end
98
+ puts "Found #{count} organizations"
99
+ ```
100
+
101
+ By default this call will return all [collection fields](http://developer.itrp.com/v1/organizations/#collection-fields) for each Organization.
102
+ For more fields, check out the [field selection](http://developer.itrp.com/v1/general/field_selection/#collection-of-resources) documentation.
103
+
104
+ The fields can be accessed using *symbols* and *strings*, and it is possible chain a number of keys in one go:
105
+ ```
106
+ count = Itrp::Client.new.each('organizations', fields: 'parent') do |organization|
107
+ puts organization[:parent][:name] # this may throw an error when +parent+ is +nil+
108
+ puts organization[:parent, :name] # using this format you will retrieve +nil+ when +parent+ is +nil+
109
+ puts organization['parent', 'name'] # strings are also accepted as keys
110
+ end
111
+ ```
112
+
113
+ Note that an `Itrp::Exception` could be thrown in case one of the API requests fails. When using the [blocking options](#blocking) 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.
114
+
115
+ ### Retrieve a collection of records
116
+
117
+ The `each` method [described above](#browse-through-a-collection-of-records) is the preferred way to work with collections of data.
118
+
119
+ If you really want to [paginate](http://developer.itrp.com/v1/general/pagination/) yourself, the `get` method is your friend.
120
+
121
+ ```
122
+ @client = Itrp::Client.new
123
+ response = @client.get('organizations', {per_page: 10, page: 2})
124
+
125
+ puts response.json # all data in an array
126
+
127
+ puts "showing page #{response.current_page}/#{response.total_pages}, with #{response.per_page} records per page"
128
+ puts "total number of records #{response.total_entries}"
129
+
130
+ # retrieve collection for other pages directly from the response
131
+ first_page = @client.get(response.pagination_link(:first))
132
+ prev_page = @client.get(response.pagination_link(:prev))
133
+ next_page = @client.get(response.pagination_link(:next))
134
+ last_page = @client.get(response.pagination_link(:last))
135
+ ```
136
+
137
+ By default this call will return all [collection fields](http://developer.itrp.com/v1/organizations/#collection-fields) for each Organization.
138
+ For more fields, check out the [field selection](http://developer.itrp.com/v1/general/field_selection/#collection-of-resources) documentation.
139
+
140
+ The fields can be accessed using *symbols* and *strings*, and it is possible chain a number of keys in one go:
141
+ ```
142
+ response = Itrp::Client.new.get('organizations', {per_page: 10, page: 2, fields: 'parent'})
143
+ puts response[:parent, :name] # an array with the parent organization names
144
+ puts response['parent', 'name'] # strings are also accepted as keys
145
+ ```
146
+
147
+ ### Create a new record
148
+
149
+ Creating new records is done using the `post` method.
150
+
151
+ ```
152
+ response = Itrp::Client.new.post('people', {primary_email: 'new.user@example.com', organization_id: 777})
153
+ if response.valid?
154
+ puts "New person created with id #{response[:id]}"
155
+ else
156
+ puts response.message
157
+ end
158
+ ```
159
+
160
+ Make sure to validate the success by calling `response.valid?` and to take appropriate action in case the response is not valid.
161
+
162
+
163
+ ### Update an existing record
164
+
165
+ Updating records is done using the `put` method.
166
+
167
+ ```
168
+ response = Itrp::Client.new.put('people/888', {name: 'Mrs. Susan Smith', organization_id: 777})
169
+ if response.valid?
170
+ puts "Person with id #{response[:id]} successfully updated"
171
+ else
172
+ puts response.message
173
+ end
174
+ ```
175
+
176
+ Make sure to validate the success by calling `response.valid?` and to take appropriate action in case the response is not valid.
177
+
178
+
179
+ ### Note Attachments
180
+
181
+ To add attachments to a note is rather tricky when done manually as it involves separate file uploads to Amazon S3 and sending
182
+ confirmations back to ITRP.
183
+
184
+ To make it easy, a special `attachments` parameter can be added when using the `post` or `put` method when the `note` field is available.
185
+
186
+ ```
187
+ response = Itrp::Client.new.put('requests/416621', {
188
+ status: 'waiting_for_customer',
189
+ note: 'Please complete the attached forms and reassign the request back to us.',
190
+ attachments: ['/tmp/forms/Inventory.xls', '/tmp/forms/PersonalData.xls']
191
+ })
192
+ ```
193
+
194
+ If an attachment upload fails, the errors are logged but the `post` or `put` request will still be sent to ITRP without the
195
+ failed attachments. To receive exceptions add `attachments_exception: true` to the data.
196
+
197
+ ```
198
+ begin
199
+ response = Itrp::Client.new.put('requests/416621', {
200
+ status: 'waiting_for_customer',
201
+ note: 'Please complete the attached forms and reassign the request back to us.',
202
+ attachments: ['/tmp/forms/Inventory.xls', '/tmp/forms/PersonalData.xls']
203
+ })
204
+ if response.valid?
205
+ puts "Request #{response[:id]} updated and attachments added to the note"
206
+ else
207
+ puts "Update of request failed: #{response.message}"
208
+ end
209
+ catch Itrp::UploadFailed => ex
210
+ puts "Could not upload an attachment: #{ex.message}"
211
+ end
212
+ ```
213
+
214
+ ### Importing CSV files
215
+
216
+ ITRP also provides an [Import API](http://developer.itrp.com/v1/import/). The ITRP Client can be used to upload files to that API.
217
+
218
+ ```
219
+ response = Itrp::Client.new.import('\tmp\people.csv', 'people')
220
+ if response.valid?
221
+ puts "Import queued with token #{response[:token]}"
222
+ else
223
+ puts "Import upload failed: #{response.message}"
224
+ end
225
+
226
+ ```
227
+
228
+ The second argument contains the [import type](http://developer.itrp.com/v1/import/#parameters).
229
+
230
+ It is also possible to [monitor the progress](http://developer.itrp.com/v1/import/#import-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.
231
+
232
+ ```
233
+ begin
234
+ response = Itrp::Client.new.import('\tmp\people.csv', 'people', true)
235
+ puts response[:state]
236
+ puts response[:results]
237
+ puts response[:message]
238
+ catch Itrp::UploadFailed => ex
239
+ puts "Could not upload the people import file: #{ex.message}"
240
+ catch Itrp::Exception => ex
241
+ puts "Unable to monitor progress of the people import: #{ex.message}"
242
+ end
243
+ ```
244
+
245
+ Note that blocking for the import to finish is required when you import multiple CSVs that are dependent on each other.
246
+
247
+
248
+ ### Exporting CSV files
249
+
250
+ ITRP also provides an [Export API](http://developer.itrp.com/v1/export/). The ITRP Client can be used to download (zipped) CSV files using that API.
251
+
252
+ ```
253
+ response = Itrp::Client.new.export(['people', 'people_contact_details'], DateTime.new(2012,03,30,23,00,00))
254
+ if response.valid?
255
+ puts "Export queued with token #{response[:token]}"
256
+ else
257
+ puts "Export failed: #{response.message}"
258
+ end
259
+
260
+ ```
261
+
262
+ The first argument contains the [export types](http://developer.itrp.com/v1/export/#parameters).
263
+ The second argument is optional and limits the export to all changed records since the given time.
264
+
265
+ It is also possible to [monitor the progress](http://developer.itrp.com/v1/export/#export-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.
266
+
267
+ ```
268
+ require 'open-uri'
269
+
270
+ begin
271
+ response = Itrp::Client.new.export(['people', 'people_contact_details'], nil, true)
272
+ puts response[:state]
273
+ # write the export file to disk
274
+ File.open('/tmp/export.zip', 'wb') { |f| f.write(open(response[:url]).read) }
275
+ catch Itrp::UploadFailed => ex
276
+ puts "Could not queue the people export: #{ex.message}"
277
+ catch Itrp::Exception => ex
278
+ puts "Unable to monitor progress of the people export: #{ex.message}"
279
+ end
280
+ ```
281
+
282
+ Note that blocking for the export to finish is recommended as you will get direct access to the exported file.
283
+
284
+
285
+ ### Blocking
286
+
287
+ 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](#global-configuration). This is especially helpfull for flaky internet connections.
288
+
289
+ By setting the _block_at_rate_limit_ to `true` in the [configuration](#global-configuration) all actions will also block in case the [rate limit](http://developer.itrp.com/v1/#rate-limiting) is reached. The action is retried every 5 minutes until the [rate limit](http://developer.itrp.com/v1/#rate-limiting) is lifted again, which might take up to 1 hour.
290
+
291
+
292
+ ### Exception handling
293
+
294
+ The standard methods `get`, `post`, `put` and `delete` will always return a Response with an [error message](http://developer.itrp.com/v1/#http-status-codes) in case something went wrong.
295
+
296
+ 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.
297
+
298
+ ```
299
+ response = Itrp::Client.new.get('organizations/1a2b')
300
+ puts response.valid?
301
+ puts response.message
302
+ ```
303
+
304
+ The methods `each` and `import` may throw an `Itrp::Exception` in case something failed, see the examples above.
@@ -0,0 +1,40 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'itrp/client/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "itrp-client"
8
+ spec.version = Itrp::Client::VERSION
9
+ spec.platform = Gem::Platform::RUBY
10
+ spec.required_ruby_version = '>= 1.9.3'
11
+ spec.authors = ["ITRP"]
12
+ spec.email = %q{developers@itrp.com}
13
+ spec.description = %q{Client for accessing the ITRP REST API}
14
+ spec.summary = %q{Client for accessing the ITRP REST API}
15
+ spec.homepage = "https://developer.itrp.com"
16
+ spec.license = "MIT"
17
+
18
+ spec.files = Dir.glob("lib/**/*") + [
19
+ "LICENSE.txt",
20
+ "README.md",
21
+ "Gemfile",
22
+ "Gemfile.lock",
23
+ "itrp-client.gemspec"
24
+ ]
25
+ spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
26
+ spec.test_files = `git ls-files -- {test,spec}/*`.split("\n")
27
+ spec.require_paths = ["lib"]
28
+ spec.rdoc_options = ["--charset=UTF-8"]
29
+
30
+ spec.add_runtime_dependency 'gem_config'
31
+ spec.add_runtime_dependency 'activesupport'
32
+ spec.add_runtime_dependency 'mime-types'
33
+
34
+ spec.add_development_dependency "bundler", "~> 1.3"
35
+ spec.add_development_dependency "rake"
36
+ spec.add_development_dependency 'rspec'
37
+ spec.add_development_dependency 'webmock'
38
+ spec.add_development_dependency 'simplecov'
39
+
40
+ end