From 30ac2936d1926d09aaed4ad94054a5905e49dac3 Mon Sep 17 00:00:00 2001 From: Thomas Stachl Date: Sat, 7 Sep 2013 14:32:11 -0700 Subject: [PATCH 1/3] removed vcd from this spec because it's not needed. --- spec/desk_api/request/retry_spec.rb | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/spec/desk_api/request/retry_spec.rb b/spec/desk_api/request/retry_spec.rb index 22e77ba..6c23f45 100644 --- a/spec/desk_api/request/retry_spec.rb +++ b/spec/desk_api/request/retry_spec.rb @@ -3,6 +3,8 @@ describe DeskApi::Request::Retry do before do + VCR.turn_off! + @stubs = Faraday::Adapter::Test::Stubs.new @conn = Faraday.new do |builder| builder.request :retry, { interval: 0 } @@ -10,7 +12,11 @@ end end - it 'retries three times', vcr: { record: :none } do + after do + VCR.turn_on! + end + + it 'retries three times' do times_called = 0 @stubs.post('/echo') do @@ -22,7 +28,7 @@ times_called.should eq(3) end - it 'retries once if we have too many requests', vcr: { record: :none } do + it 'retries once if we have too many requests' do times_called = 0 @stubs.post('/echo') do @@ -34,7 +40,7 @@ 'status' => 429, 'x-rate-limit-limit' => '60', 'x-rate-limit-remaining' => '0', - 'x-rate-limit-reset' => '1', + 'x-rate-limit-reset' => '0', 'content-length' => '31' } }) From 2dbd25500311c6b75f2ba271495e75f5c80e637f Mon Sep 17 00:00:00 2001 From: Thomas Stachl Date: Sat, 7 Sep 2013 14:43:54 -0700 Subject: [PATCH 2/3] adds embed resources (side loading) to the desk_api gem, fixed #1. --- lib/desk_api/action/embeddable.rb | 47 +++++++ lib/desk_api/action/embedded.rb | 12 -- lib/desk_api/error/not_embeddable.rb | 8 ++ lib/desk_api/resource.rb | 31 ++++- lib/desk_api/resource/case.rb | 2 + lib/desk_api/resource/filter.rb | 7 ++ lib/desk_api/resource/inbound_mailbox.rb | 7 ++ lib/desk_api/resource/job.rb | 2 + lib/desk_api/resource/page.rb | 37 ++---- lib/desk_api/resource/reply.rb | 2 + .../_find/has_an_alias_by_id.yml | 54 ++++++++ .../loads_the_requested_resource.yml | 14 +-- spec/desk_api/resource/page_spec.rb | 14 ++- spec/desk_api/resource_spec.rb | 68 +++++++++++ spec/spec_helper.rb | 1 + spec/stubs/case_embed_customer.json | 115 ++++++++++++++++++ spec/stubs/cases_embed_assigned_user.json | 105 ++++++++++++++++ 17 files changed, 472 insertions(+), 54 deletions(-) create mode 100644 lib/desk_api/action/embeddable.rb delete mode 100644 lib/desk_api/action/embedded.rb create mode 100644 lib/desk_api/error/not_embeddable.rb create mode 100644 lib/desk_api/resource/filter.rb create mode 100644 lib/desk_api/resource/inbound_mailbox.rb create mode 100644 spec/cassettes/DeskApi_Resource_Page/_find/has_an_alias_by_id.yml rename spec/cassettes/DeskApi_Resource_Page/{_by_id => _find}/loads_the_requested_resource.yml (90%) create mode 100644 spec/stubs/case_embed_customer.json create mode 100644 spec/stubs/cases_embed_assigned_user.json diff --git a/lib/desk_api/action/embeddable.rb b/lib/desk_api/action/embeddable.rb new file mode 100644 index 0000000..2f6d1ce --- /dev/null +++ b/lib/desk_api/action/embeddable.rb @@ -0,0 +1,47 @@ +require 'desk_api/error/not_embeddable' + +module DeskApi + module Action + module Embeddable + attr_reader :embedded + + def embed(*embedds) + # make sure we don't try to embed anything that's not defined + # add it to the query + self.query_params = { embed: embedds.each{ |embed| + unless self.base_class.embeddable?(embed) + raise DeskApi::Error::NotEmbeddable.new("`#{embed.to_s}' can not be embedded.") + end + }.join(',') } + # return self + self + end + + def setup_embedded(embedds) + if embedds.entries? + @records = embedds['entries'].map do |record| + resource(record._links.self['class']).new(client, record, true) + end + else + embedds.each_pair do |key, definition| + @_links[key]['resource'] = resource(definition['class']).new @client, definition, true + end + end + end + + module ClassMethods + def embeddable(*embeddables) + @embeddables = embeddables + end + + def embeddable?(key) + (@embeddables || []).include?(key.to_sym) + end + end + + def self.included(base) + base.extend(ClassMethods) + end + end + end +end \ No newline at end of file diff --git a/lib/desk_api/action/embedded.rb b/lib/desk_api/action/embedded.rb deleted file mode 100644 index 822e520..0000000 --- a/lib/desk_api/action/embedded.rb +++ /dev/null @@ -1,12 +0,0 @@ -module DeskApi - module Action - module Embedded - private - def setup_embedded(entries) - @records = entries.map do |record| - resource(record._links.self['class']).new(client, record, true) - end - end - end - end -end \ No newline at end of file diff --git a/lib/desk_api/error/not_embeddable.rb b/lib/desk_api/error/not_embeddable.rb new file mode 100644 index 0000000..34d4e6d --- /dev/null +++ b/lib/desk_api/error/not_embeddable.rb @@ -0,0 +1,8 @@ +require 'desk_api/error' + +module DeskApi + class Error + class NotEmbeddable < DeskApi::Error + end + end +end \ No newline at end of file diff --git a/lib/desk_api/resource.rb b/lib/desk_api/resource.rb index 0ef9299..039faef 100644 --- a/lib/desk_api/resource.rb +++ b/lib/desk_api/resource.rb @@ -1,6 +1,6 @@ require 'desk_api/action/create' require 'desk_api/action/delete' -require 'desk_api/action/embedded' +require 'desk_api/action/embeddable' require 'desk_api/action/field' require 'desk_api/action/link' require 'desk_api/action/resource' @@ -14,6 +14,7 @@ class Resource include DeskApi::Action::Resource include DeskApi::Action::Link include DeskApi::Action::Field + include DeskApi::Action::Embeddable def initialize(client, definition = {}, loaded = false) @client, @loaded, @_changed = client, loaded, {} @@ -37,16 +38,41 @@ def get_href def exec!(reload = false) return self if loaded and !reload - definition, @loaded = client.get(@_links.self.href).body, true + definition, @loaded = client.get(get_href).body, true setup(definition) end + def query_params + Addressable::URI.parse(@_links.self.href).query_values || {} + end + + def query_params_include?(param) + query_params.include?(param) ? query_params[param] : nil + end + + def query_params=(params = {}) + return @_links.self.href if params.empty? + + uri = Addressable::URI.parse(@_links.self.href) + params = (uri.query_values || {}).merge(params) + + @loaded = false unless params == uri.query_values + + uri.query_values = params + @_links.self.href = uri.to_s + end + + def base_class + self.class + end + private attr_accessor :client, :loaded, :_changed def setup(definition) setup_links(definition._links) if definition._links? + setup_embedded(definition._embedded) if definition._embedded? setup_fields(definition) self end @@ -56,6 +82,5 @@ def method_missing(method, *args, &block) raise DeskApi::Error::MethodNotSupported unless self.respond_to?(method.to_sym) self.send(method, *args, &block) end - end end \ No newline at end of file diff --git a/lib/desk_api/resource/case.rb b/lib/desk_api/resource/case.rb index d82e5ff..d589c60 100644 --- a/lib/desk_api/resource/case.rb +++ b/lib/desk_api/resource/case.rb @@ -4,6 +4,8 @@ class Case < DeskApi::Resource include DeskApi::Action::Create include DeskApi::Action::Update include DeskApi::Action::Search + + embeddable :customer, :assigned_user, :assigned_group, :locked_by end end end \ No newline at end of file diff --git a/lib/desk_api/resource/filter.rb b/lib/desk_api/resource/filter.rb new file mode 100644 index 0000000..6f48777 --- /dev/null +++ b/lib/desk_api/resource/filter.rb @@ -0,0 +1,7 @@ +module DeskApi + class Resource + class Filter < DeskApi::Resource + embeddable :user, :group + end + end +end \ No newline at end of file diff --git a/lib/desk_api/resource/inbound_mailbox.rb b/lib/desk_api/resource/inbound_mailbox.rb new file mode 100644 index 0000000..6444cef --- /dev/null +++ b/lib/desk_api/resource/inbound_mailbox.rb @@ -0,0 +1,7 @@ +module DeskApi + class Resource + class InboundMailbox < DeskApi::Resource + embeddable :default_group + end + end +end \ No newline at end of file diff --git a/lib/desk_api/resource/job.rb b/lib/desk_api/resource/job.rb index 9a3da60..8845796 100644 --- a/lib/desk_api/resource/job.rb +++ b/lib/desk_api/resource/job.rb @@ -2,6 +2,8 @@ module DeskApi class Resource class Job < DeskApi::Resource include DeskApi::Action::Create + + embeddable :user end end end \ No newline at end of file diff --git a/lib/desk_api/resource/page.rb b/lib/desk_api/resource/page.rb index 1dd2b1b..501eb3b 100644 --- a/lib/desk_api/resource/page.rb +++ b/lib/desk_api/resource/page.rb @@ -2,7 +2,6 @@ module DeskApi class Resource class Page < DeskApi::Resource include Enumerable - include DeskApi::Action::Embedded [ :all?, :any?, @@ -31,44 +30,28 @@ def create(params) [:page, :per_page].each do |method| define_method(method) do |value = nil| if not value - self.exec! if self.query_params(method.to_s) == nil - return self.query_params(method.to_s).to_i + self.exec! if self.query_params_include?(method.to_s) == nil + return self.query_params_include?(method.to_s).to_i end self.query_params = Hash[method.to_s, value.to_s] self end end - def by_id(id) - by_url("#{clean_base_url}/#{id}") + def find(id, options = {}) + res = base_class.new(client, Hashie::Mash.new({ _links: { self: { href: "#{clean_base_url}/#{id}" }}})) + if options[:embed] + options[:embed] = [options[:embed]] unless options[:embed].kind_of?(Array) + res.embed(*options[:embed]) + end + res.exec! end + alias_method :by_id, :find protected attr_reader :records - def setup(definition) - setup_embedded(definition._embedded['entries']) if definition._embedded? - super(definition) - end - - def query_params(param) - params = Addressable::URI.parse(@_links.self.href).query_values || {} - params.include?(param) ? params[param] : nil - end - - def query_params=(params = {}) - return @_links.self.href if params.empty? - - uri = Addressable::URI.parse(@_links.self.href) - params = (uri.query_values || {}).merge(params) - - @loaded = false unless params == uri.query_values - - uri.query_values = params - @_links.self.href = uri.to_s - end - def clean_base_url Addressable::URI.parse(@_links.self.href).path.gsub(/\/search$/, '') end diff --git a/lib/desk_api/resource/reply.rb b/lib/desk_api/resource/reply.rb index 21f4f7c..f4abace 100644 --- a/lib/desk_api/resource/reply.rb +++ b/lib/desk_api/resource/reply.rb @@ -3,6 +3,8 @@ class Resource class Reply < DeskApi::Resource include DeskApi::Action::Create include DeskApi::Action::Update + + embeddable :case, :sent_by, :entered_by end end end \ No newline at end of file diff --git a/spec/cassettes/DeskApi_Resource_Page/_find/has_an_alias_by_id.yml b/spec/cassettes/DeskApi_Resource_Page/_find/has_an_alias_by_id.yml new file mode 100644 index 0000000..87becae --- /dev/null +++ b/spec/cassettes/DeskApi_Resource_Page/_find/has_an_alias_by_id.yml @@ -0,0 +1,54 @@ +--- +http_interactions: +- request: + method: get + uri: https://devel.desk.com/api/v2/cases/3065 + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - application/json + User-Agent: + - desk.com Ruby Gem v0.1.2 + response: + status: + code: 200 + message: + headers: + Accept-Ranges: + - bytes + Cache-Control: + - must-revalidate, private, max-age=0 + Content-Type: + - application/json; charset=utf-8 + Date: + - Sat, 07 Sep 2013 21:40:49 GMT + ETag: + - '"cbba64bc7fe9b35611cc745f75671fb6"' + Status: + - 200 OK + Vary: + - X-AppVersion + X-AppVersion: + - '9.9' + X-Frame-Options: + - SAMEORIGIN + X-Rate-Limit-Limit: + - '60' + X-Rate-Limit-Remaining: + - '59' + X-Rate-Limit-Reset: + - '11' + X-Request-Id: + - 2c92e26b679018d276ba9790a631d5f0 + Content-Length: + - '897' + Connection: + - keep-alive + body: + encoding: UTF-8 + string: '{"external_id":null,"subject":"Testing the Tank again","priority":5,"locked_until":null,"description":null,"status":"open","type":"email","labels":[],"language":"de","active_at":"2013-05-13T19:20:59Z","created_at":"2013-05-13T18:13:39Z","updated_at":"2013-05-13T18:13:39Z","received_at":null,"custom_fields":{"my_new_custom_field":null,"my_new_number_field":null,"my_new_date_field":null,"my_new_boolean_field":null,"my_new_list_field":null},"_links":{"self":{"href":"/api/v2/cases/3065","class":"case"},"message":{"href":"/api/v2/cases/3065/message","class":"email"},"customer":{"href":"/api/v2/customers/86101780","class":"customer"},"assigned_user":null,"assigned_group":null,"locked_by":null,"replies":{"href":"/api/v2/cases/3065/replies","class":"reply"},"notes":{"href":"/api/v2/cases/3065/notes","class":"note"},"attachments":{"href":"/api/v2/cases/3065/attachments","class":"attachment"}}}' + http_version: + recorded_at: Sat, 07 Sep 2013 21:40:49 GMT +recorded_with: VCR 2.5.0 diff --git a/spec/cassettes/DeskApi_Resource_Page/_by_id/loads_the_requested_resource.yml b/spec/cassettes/DeskApi_Resource_Page/_find/loads_the_requested_resource.yml similarity index 90% rename from spec/cassettes/DeskApi_Resource_Page/_by_id/loads_the_requested_resource.yml rename to spec/cassettes/DeskApi_Resource_Page/_find/loads_the_requested_resource.yml index 0406ed2..8d2630b 100644 --- a/spec/cassettes/DeskApi_Resource_Page/_by_id/loads_the_requested_resource.yml +++ b/spec/cassettes/DeskApi_Resource_Page/_find/loads_the_requested_resource.yml @@ -10,7 +10,7 @@ http_interactions: Accept: - application/json User-Agent: - - desk.com Ruby Gem v0.1.0 + - desk.com Ruby Gem v0.1.2 response: status: code: 200 @@ -23,7 +23,7 @@ http_interactions: Content-Type: - application/json; charset=utf-8 Date: - - Mon, 19 Aug 2013 23:51:31 GMT + - Sat, 07 Sep 2013 21:40:49 GMT ETag: - '"cbba64bc7fe9b35611cc745f75671fb6"' Status: @@ -31,17 +31,17 @@ http_interactions: Vary: - X-AppVersion X-AppVersion: - - '7.9' + - '9.9' X-Frame-Options: - SAMEORIGIN X-Rate-Limit-Limit: - '60' X-Rate-Limit-Remaining: - - '59' + - '58' X-Rate-Limit-Reset: - - '29' + - '11' X-Request-Id: - - e391f97e79ee25cc928aadb97086f3ef + - a33f162a33593ce4444ffeaacb9b6364 Content-Length: - '897' Connection: @@ -50,5 +50,5 @@ http_interactions: encoding: UTF-8 string: '{"external_id":null,"subject":"Testing the Tank again","priority":5,"locked_until":null,"description":null,"status":"open","type":"email","labels":[],"language":"de","active_at":"2013-05-13T19:20:59Z","created_at":"2013-05-13T18:13:39Z","updated_at":"2013-05-13T18:13:39Z","received_at":null,"custom_fields":{"my_new_custom_field":null,"my_new_number_field":null,"my_new_date_field":null,"my_new_boolean_field":null,"my_new_list_field":null},"_links":{"self":{"href":"/api/v2/cases/3065","class":"case"},"message":{"href":"/api/v2/cases/3065/message","class":"email"},"customer":{"href":"/api/v2/customers/86101780","class":"customer"},"assigned_user":null,"assigned_group":null,"locked_by":null,"replies":{"href":"/api/v2/cases/3065/replies","class":"reply"},"notes":{"href":"/api/v2/cases/3065/notes","class":"note"},"attachments":{"href":"/api/v2/cases/3065/attachments","class":"attachment"}}}' http_version: - recorded_at: Mon, 19 Aug 2013 23:51:31 GMT + recorded_at: Sat, 07 Sep 2013 21:40:49 GMT recorded_with: VCR 2.5.0 diff --git a/spec/desk_api/resource/page_spec.rb b/spec/desk_api/resource/page_spec.rb index f75f2d7..759abb0 100644 --- a/spec/desk_api/resource/page_spec.rb +++ b/spec/desk_api/resource/page_spec.rb @@ -14,12 +14,12 @@ end it 'allows to get query params from the current resource' do - @page.send(:query_params, 'page').should eq('2') - @page.send(:query_params, 'per_page').should eq('50') + @page.send(:query_params_include?, 'page').should eq('2') + @page.send(:query_params_include?, 'per_page').should eq('50') end it 'returns nil if param not found' do - @page.send(:query_params, 'blup').should be_nil + @page.send(:query_params_include?, 'blup').should be_nil end end @@ -56,9 +56,13 @@ end end - context '#by_id' do + context '#find' do it 'loads the requested resource', :vcr do - subject.cases.by_id(3065).subject.should eq('Testing the Tank again') + subject.cases.find(3065).subject.should eq('Testing the Tank again') + end + + it 'has an alias by_id', :vcr do + subject.cases.find(3065).subject.should eq('Testing the Tank again') end end end \ No newline at end of file diff --git a/spec/desk_api/resource_spec.rb b/spec/desk_api/resource_spec.rb index d4f5344..115db16 100644 --- a/spec/desk_api/resource_spec.rb +++ b/spec/desk_api/resource_spec.rb @@ -138,4 +138,72 @@ lambda { user.delete }.should raise_error(DeskApi::Error::MethodNotSupported) end end + + describe 'embeddable' do + it 'has resources defined' do + DeskApi::Resource::Case.embeddable?(:assigned_user).should be_true + DeskApi::Resource::Case.embeddable?(:message).should be_false + end + + it 'allows to declare embedds' do + lambda { subject.cases.embed(:assigned_user) }.should_not raise_error + lambda { subject.cases.embed(:message) }.should raise_error(DeskApi::Error::NotEmbeddable) + end + + it 'changes the url' do + subject.cases.embed(:assigned_user).get_href.should eq('/api/v2/cases?embed=assigned_user') + end + + context 'if you use embed' do + before do + VCR.turn_off! ignore_cassettes: true + + @stubs ||= Faraday::Adapter::Test::Stubs.new + @client ||= DeskApi::Client.new(DeskApi::CONFIG).tap do |client| + client.middleware = Proc.new do |builder| + builder.response :mashify + builder.response :dates + builder.response :json, content_type: /application\/json/ + builder.adapter :test, @stubs + end + end + end + + after do + VCR.turn_on! + end + + it 'does not load the resource again' do + times_called = 0 + @stubs.get('/api/v2/cases?embed=assigned_user') do + times_called += 1 + [ + 200, + { 'content-type' => 'application/json' }, + File.open(File.join(RSpec.configuration.root_path, 'stubs', 'cases_embed_assigned_user.json')).read + ] + end + + first_case = @client.cases.embed(:assigned_user).first + first_case.assigned_user.name.should eq('Thomas Stachl') + first_case.assigned_user.instance_variable_get(:@loaded).should be_true + times_called.should eq(1) + end + + it 'can be used in finder' do + @stubs.get('/api/v2/cases/3011?embed=customer') do + [ + 200, + { 'content-type' => 'application/json' }, + File.open(File.join(RSpec.configuration.root_path, 'stubs', 'case_embed_customer.json')).read + ] + end + + customer = @client.cases.find(3011, embed: :customer).customer + customer.first_name.should eq('Thomas') + customer = @client.cases.find(3011, embed: [:customer]).customer + customer.first_name.should eq('Thomas') + end + end + end end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index e2040cb..af39379 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -44,4 +44,5 @@ module DeskApi RSpec.configure do |config| config.treat_symbols_as_metadata_keys_with_true_values = true + config.add_setting :root_path, default: File.dirname(__FILE__) end \ No newline at end of file diff --git a/spec/stubs/case_embed_customer.json b/spec/stubs/case_embed_customer.json new file mode 100644 index 0000000..77927e2 --- /dev/null +++ b/spec/stubs/case_embed_customer.json @@ -0,0 +1,115 @@ +{ + "external_id": null, + "subject": "", + "priority": 9, + "locked_until": null, + "description": "", + "status": "open", + "type": "phone", + "labels": [], + "language": "en", + "active_at": "2013-09-07T19:38:58Z", + "created_at": "2013-05-09T17:02:16Z", + "updated_at": "2013-09-07T19:39:07Z", + "received_at": "2013-05-09T17:02:16Z", + "custom_fields": { + "my_new_custom_field": "", + "my_new_number_field": "0", + "my_new_date_field": "", + "my_new_boolean_field": "0", + "my_new_list_field": "Option 1" + }, + "_links": { + "self": { + "href": "/api/v2/cases/3011", + "class": "case" + }, + "message": { + "href": "/api/v2/cases/3011/message", + "class": "phone" + }, + "customer": { + "href": "/api/v2/customers/37823480", + "class": "customer" + }, + "assigned_user": { + "href": "/api/v2/users/16096734", + "class": "user" + }, + "assigned_group": { + "href": "/api/v2/groups/171213", + "class": "group" + }, + "locked_by": null, + "replies": { + "href": "/api/v2/cases/3011/replies", + "class": "reply" + }, + "notes": { + "href": "/api/v2/cases/3011/notes", + "class": "note" + }, + "attachments": { + "href": "/api/v2/cases/3011/attachments", + "class": "attachment" + } + }, + "_embedded": { + "customer": { + "first_name": "Thomas", + "last_name": "Stachl", + "company": "stachl.me", + "title": "Master of Script Artistry", + "external_id": null, + "background": "Some Background information.", + "language": "de", + "locked_until": null, + "created_at": "2012-07-04T14:33:39Z", + "updated_at": "2013-07-15T18:10:21Z", + "custom_fields": { + "my_custom_field": "", + "my_number_field": "0", + "my_boolean_field": "0", + "my_date_field": "", + "my_list_field": "Option 1" + }, + "emails": [ + { + "type": "home", + "value": "thomas@stachl.me" + }, + { + "type": "home", + "value": "tstachl@salesforce.com" + } + ], + "phone_numbers": [ + { + "type": "mobile", + "value": "4156060761" + } + ], + "addresses": [ + { + "type": "home", + "value": "600 William Street #526\nOakland, CA 94612" + } + ], + "_links": { + "self": { + "href": "/api/v2/customers/37823480", + "class": "customer" + }, + "locked_by": null, + "company": { + "href": "/api/v2/companies/373760", + "class": "company" + }, + "cases": { + "href": "/api/v2/customers/37823480/cases", + "class": "case" + } + } + } + } +} \ No newline at end of file diff --git a/spec/stubs/cases_embed_assigned_user.json b/spec/stubs/cases_embed_assigned_user.json new file mode 100644 index 0000000..37ccd42 --- /dev/null +++ b/spec/stubs/cases_embed_assigned_user.json @@ -0,0 +1,105 @@ +{ + "total_entries": 329, + "_links": { + "self": { + "href": "/api/v2/cases?page=1&per_page=1", + "class": "page" + }, + "first": { + "href": "/api/v2/cases?page=1&per_page=1", + "class": "page" + }, + "last": { + "href": "/api/v2/cases?page=329&per_page=1", + "class": "page" + }, + "previous": null, + "next": { + "href": "/api/v2/cases?page=2&per_page=1", + "class": "page" + } + }, + "_embedded": { + "entries": [ + { + "external_id": null, + "subject": "", + "priority": 9, + "locked_until": null, + "description": "", + "status": "open", + "type": "phone", + "labels": [], + "language": "en", + "active_at": "2013-09-07T19:38:58Z", + "created_at": "2013-05-09T17:02:16Z", + "updated_at": "2013-09-07T19:39:07Z", + "received_at": "2013-05-09T17:02:16Z", + "custom_fields": { + "my_new_custom_field": "", + "my_new_number_field": "0", + "my_new_date_field": "", + "my_new_boolean_field": "0", + "my_new_list_field": "Option 1" + }, + "_links": { + "self": { + "href": "/api/v2/cases/3011", + "class": "case" + }, + "message": { + "href": "/api/v2/cases/3011/message", + "class": "phone" + }, + "customer": { + "href": "/api/v2/customers/37823480", + "class": "customer" + }, + "assigned_user": { + "href": "/api/v2/users/16096734", + "class": "user" + }, + "assigned_group": { + "href": "/api/v2/groups/171213", + "class": "group" + }, + "locked_by": null, + "replies": { + "href": "/api/v2/cases/3011/replies", + "class": "reply" + }, + "notes": { + "href": "/api/v2/cases/3011/notes", + "class": "note" + }, + "attachments": { + "href": "/api/v2/cases/3011/attachments", + "class": "attachment" + } + }, + "_embedded": { + "assigned_user": { + "name": "Thomas Stachl", + "public_name": "Thomas Stachl", + "email": "tstachl@salesforce.com", + "level": "siteadmin_billing", + "_links": { + "self": { + "href": "/api/v2/users/16096734", + "class": "user" + }, + "preferences": { + "href": "/api/v2/users/16096734/preferences", + "class": "user_preference" + }, + "searches": { + "href": "/api/v2/users/16096734/searches", + "class": "search" + } + } + } + } + } + ] + } +} \ No newline at end of file From 7d6072e7655ccc11e7bda5d184093ffbb0f2d5a2 Mon Sep 17 00:00:00 2001 From: Thomas Stachl Date: Sat, 7 Sep 2013 15:02:18 -0700 Subject: [PATCH 3/3] updated README with side loading, new finder --- README.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 335210f..23eb73d 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,8 @@ The API supports RESTful resources and so does this wrapper. Those resources are found_case = DeskApi.users.first.by_url '/api/v2/cases/1' # find a case by case number +found_case = DeskApi.cases.find 1 +# the old #by_id still works found_case = DeskApi.cases.by_id 1 ``` @@ -108,6 +110,27 @@ end DeskApi.cases.page == 1 ``` +### Side loading + +APIv2 has a lot of great new features but the one I'm most excited about is side loading or embedding resources. You basically request one resource and tell the API to embed sub resources, eg. you need cases but also want to have the `assigned_user` - instead of requesting all cases and the `assigned_user` for each of those cases (30 cases = 31 API requests) you can now embed `assigned_user` into your cases list view (1 API REQUEST!!!!). + +Of course we had to bring this awesomeness into the API wrapper as soon as possible, so here you go: + +```ruby +# fetch cases with their respective customers +cases = DeskApi.cases.embed(:customer) +customer = cases.first.customer + +# you can use this feature in finders too +my_case = DeskApi.cases.find(1, embed: :customer) +# OR +my_case = DeskApi.cases.find(1, embed: [:customer, :assigned_user, :assigned_group]) + +customer = my_case.customer +assigned_user = my_case.assigned_user +assigned_group = my_case.assigned_group +``` + ### Create, Update and Delete Of course we support creating, updating and deleting resources but not all resources can be deleted or updated or created, if that's the case for the resource you're trying to update, it'll throw a `DeskApi::Error::MethodNotSupported` error. The specific method won't be defined on the resource either `DeskApi.cases.first.respond_to?(:delete) == false`. @@ -191,7 +214,7 @@ Please also have a look at all [desk.com API errors](http://dev.desk.com/API/usi (The MIT License) -Copyright (c) 2013 Thomas Stachl <tom@desk.com> +Copyright (c) 2013 Thomas Stachl <thomas@desk.com> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: