Skip to content
This repository has been archived by the owner on Jun 23, 2020. It is now read-only.

Commit

Permalink
merge side loading into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
Thomas Stachl committed Sep 7, 2013
2 parents 03e5c7d + 7d6072e commit 9821eac
Show file tree
Hide file tree
Showing 19 changed files with 505 additions and 58 deletions.
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```

Expand Down Expand Up @@ -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`.
Expand Down Expand Up @@ -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:

Expand Down
47 changes: 47 additions & 0 deletions lib/desk_api/action/embeddable.rb
Original file line number Diff line number Diff line change
@@ -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
12 changes: 0 additions & 12 deletions lib/desk_api/action/embedded.rb

This file was deleted.

8 changes: 8 additions & 0 deletions lib/desk_api/error/not_embeddable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
require 'desk_api/error'

module DeskApi
class Error
class NotEmbeddable < DeskApi::Error
end
end
end
31 changes: 28 additions & 3 deletions lib/desk_api/resource.rb
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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, {}
Expand All @@ -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
Expand All @@ -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
2 changes: 2 additions & 0 deletions lib/desk_api/resource/case.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
7 changes: 7 additions & 0 deletions lib/desk_api/resource/filter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module DeskApi
class Resource
class Filter < DeskApi::Resource
embeddable :user, :group
end
end
end
7 changes: 7 additions & 0 deletions lib/desk_api/resource/inbound_mailbox.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module DeskApi
class Resource
class InboundMailbox < DeskApi::Resource
embeddable :default_group
end
end
end
2 changes: 2 additions & 0 deletions lib/desk_api/resource/job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ module DeskApi
class Resource
class Job < DeskApi::Resource
include DeskApi::Action::Create

embeddable :user
end
end
end
37 changes: 10 additions & 27 deletions lib/desk_api/resource/page.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ module DeskApi
class Resource
class Page < DeskApi::Resource
include Enumerable
include DeskApi::Action::Embedded

[
:all?, :any?,
Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions lib/desk_api/resource/reply.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
54 changes: 54 additions & 0 deletions spec/cassettes/DeskApi_Resource_Page/_find/has_an_alias_by_id.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 9821eac

Please sign in to comment.