DeskApi a client for API v2
An official Desk API Client
DeskApi takes the capabilities of the Desk.com API and wraps them up in a Ruby
client so that it's easy-as-pie to get working with your support site's API.
Desk.com publishes a change log monthly, which you can keep up with at
dev.desk.com/API/changelog.
We do our best to keep DeskApi, but please don't hesitate to open an
issue or send a
pull request
if you find a bug or would like to new functionality added.
Getting Started
Installation
Easy!
gem install desk_api
Configuration
Authentication Mechanism
The Desk.com API allows you to access data using two authentication mechanisms:
Basic Authentication
- Username
- Password
- Subdomain or Endpoint
OAuth 1.0a
- Consumer Key
- Consumer Secret
- Access Token
- Access Token Secret
- Subdomain or Endpoint
Trust is our #1 value
Whatever option or method you choose, please make sure to never put your
credentials in your source code. This makes them available to everyone
with read access to your source, it makes your code harder to maintain and
is just overall a bad idea. There are many alternatives, including configuration
files, environmental variables, ...
First Environmental Variables
DeskApi
is automatically configured if you choose to use environmental
variables. There are 8 possible variables but you don't have to set all of them.
Based on the authentication mechanism you prefer you'll only have to specify:
export DESK_USERNAME=thomas@example.com
export DESK_PASSWORD=somepassword
export DESK_CONSUMER_KEY=CONSUMER_KEY
export DESK_CONSUMER_SECRET=CONSUMER_SECRET
export DESK_TOKEN=TOKEN
export DESK_TOKEN_SECRET=TOKEN_SECRET
export DESK_SUBDOMAIN=devel
export DESK_ENDPOINT=https://devel.desk.com
Second Configuration Option
Configure DeskApi
itself to send/receive requests by calling the configure
method to set up your authentication credentials:
DeskApi.configure do |config|
config.username = 'thomas@example.com'
config.password = 'somepassword'
config.token = 'TOKEN'
config.token_secret = 'TOKEN_SECRET'
config.consumer_key = 'CONSUMER_KEY'
config.consumer_secret = 'CONSUMER_SECRET'
config.endpoint = 'https://devel.desk.com'
end
DeskApi.get '/api/v2/topics'
DeskApi.post '/api/v2/topics', name: 'My new Topic', allow_questions: true
DeskApi.patch '/api/v2/topics/1', name: 'Changed the Topic Name'
DeskApi.delete '/api/v2/topics/1'
Third Configuration Option
Initialize a new DeskApi::Client
to send/receive requests
This example shows you how to initialize a new client and the four main request
methods supported by the Desk.com API (GET
, POST
, PATCH
and DELETE
).
client = DeskApi::Client.new username: 'thomas@example.com', password: 'somepassword', endpoint: 'https://devel.desk.com'
client = DeskApi::Client.new({
token: 'TOKEN',
token_secret: 'TOKEN_SECRET',
consumer_key: 'CONSUMER_KEY',
consumer_secret: 'CONSUMER_SECRET',
endpoint: 'https://devel.desk.com'
})
response = client.get '/api/v2/topics'
response = client.post '/api/v2/topics', name: 'My new Topic', allow_questions: true
response = client.patch '/api/v2/topics/1', name: 'Changed the Topic Name'
response = client.delete '/api/v2/topics/1'
Resources
Resources are automatically discovered by the DeskApi. When requesting a
resource from DeskAPI, the client sends the request and returns a
DeskApi::Resource
. If the client receives an error back from the API a
DeskApi::Error
is raised.
Create Read Update Delete
One of the most important features; 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::MethodNotAllowed
error. For ease of use and because we wanted
to build as less business logic into the wrapper as possible, all of the methods
are defined on each DeskApi::Resource
and will be sent to desk.com. However
the API might respond with an error if you do things that aren't supported.
new_article = DeskApi.articles.create({
subject: 'Some Subject',
body: 'Some Body',
_links: {
topic: DeskApi.topics.first.get_self
}
})
updated_article = new_article.update subject: 'Updated Subject'
if updated_article.delete == true
end
begin
DeskApi.cases.first.delete
rescue DeskApi::Error::MethodNotAllowed => e
end
Getters & Setters
As you have seen in prior examples for each field on the resource we create a
getter and setter.
customer = DeskApi.customers.find(1)
puts customer.first_name
puts customer.last_name
puts customer.title
customer.first_name = 'John'
customer.last_name = 'Doe'
updated_customer = customer.update title: 'Master of the Universe'
begin
user = DeskApi.users.first
user.update name: 'Not updatable'
rescue DeskApi::Error::MethodNotAllowed
end
Find
The method by_url
can be called on the client, for backwards compatibility we
haven't yet removed it from the DeskApi::Resource
but it will be removed once
we release v1 of this client. by_url
will return a lazy loaded instance of the
resource.
first_reply = DeskApi.by_url '/api/v2/cases/1/replies/1'
Since the update to v0.5 of the API wrapper the find
method can now be called
on all DeskApi::Resource
instances. Gotcha: It will rebuild the base path
based on the resource/collection it is called on. So if you call it on the cases
collection DeskApi.cases.find 1
the path will look like this:
/api/v2/cases/:id
.
Method | Path |
---|
DeskApi.cases.find(1) | /api/v2/cases/1 |
DeskApi.cases.entries.find(1) | /api/v2/cases/1 |
DeskApi.cases.search(subject: 'Test').find(1) | /api/v2/cases/1 |
DeskApi.cases.search(subject: 'Test').entries.find(1) | /api/v2/cases/1 |
DeskApi.cases.entries.first.replies.find(1) | /api/v2/cases/1/replies/1 |
DeskApi.cases.entries.first.replies.entries.first.find(1) | /api/v2/cases/1/replies/1 |
As mentioned above you can also navigate between resources and pages of
collections.
cases = DeskApi.cases
cases.entries.each do |my_case|
end
next_page = cases.next
next_page.entries.each do |my_case|
end
previous_page = next_page.previous
last_page = previous_page.last
first_page = last_page.first
all
and each_page
As a recent addition we made it even easier to navigate through all the pages.
DeskApi.cases.all do |current_case, current_page_number|
end
DeskApi.cases.each_page do |current_page, current_page_number|
end
Both methods use the max per_page
for the API endpoint for that particular
resource.
List params
Some lists allow for additional params like cases.
This allows you to filter the cases endpoint by using a company_id
,
customer_id
or filter_id
list param.
companys_cases = DeskApi.cases(company_id: 1)
customers_cases = DeskApi.cases(customer_id: 1)
filters_cases = DeskApi.cases(filter_id: 1)
Sorting
There is a maximum page
limit on some Desk.com API endpoints. As of right now
(May 2014) the limit is 500 for all endpoints that are limited, but please
consult the #list documentation for each resource:
To work around page limits, you can specify sort_field
and sort_direction
sorted_cases = DeskApi.cases(sort_field: :updated_at, sort_direction: :desc)
Links
Once a DeskApi::Resource
has loaded, its
linked resources
can be retrieved by calling the linked resource as a method of the
DeskApi::Resource
, e.g.,
ticket = DeskApi.cases.entries.first
assigned_user = ticket.assigned_user
customer = ticket.customer
company = customer.company
user_name = DeskApi.
cases.
entries.
select { |my_case| my_case.type == 'email' }.
first.
replies.
entries.select { |reply| reply.direction == 'out' }.
first.
sent_by.
name
Lazy loading
Resources are lazy loaded. This means that requests are only sent when you
request data from the resource. This helps a lot with flying under the Desk.com
API rate limit. E.g.,
DeskApi.cases.page(10).per_page(50).entries.each do |my_case|
end
DeskApi.cases.page == 1
Embedding
Some endpoints support embedding
related resources. E.g., when getting a list of cases from /api/v2/cases
you
can embed the customer on each case by adding embed=
to the query
string: /api/v2/cases?embed=customer
The client supports this: tickets_and_customers = DeskApi.cases.embed(:customer)
Taking advantage of .embed
is a great way to be conscious of the rate limit
and minimize necessary HTTP requests.
Not using embedded resources
tickets = DeskApi.cases.per_page(100).entries
tickets.each do |ticket|
puts ticket.customer.first_name
end
Using embedded resources
tickets = DeskApi.cases.per_page(100).embed(:customer).entries
tickets.each do |ticket|
puts ticket.customer.first_name
end
Using embedded resources in find
my_case = DeskApi.cases.find(1, embed: :customer)
my_case = DeskApi.cases.find(1, embed: [:customer, :assigned_user, :assigned_group, :message])
customer = my_case.customer
assigned_user = my_case.assigned_user
assigned_group = my_case.assigned_group
Downloading Attachments
Attachment resources can be downloaded directly, a Tempfile
is returned that can either be read or moved to the final location.
ticket = DeskApi.cases.find(123)
attachment = ticket.attachments.entries.first
file = attachment.download
content = file.read
File.open('/path/to/my/storage', 'w') do |f|
f.write(content)
end
API Errors
Sometimes the API is going to return errors, eg. Validation Error. In these
cases we wrap the API error into a DeskApi::Error
. Here are the common errors:
DeskApi::Error::BadRequest
DeskApi::Error::Unauthorized
DeskApi::Error::Forbidden
DeskApi::Error::NotFound
DeskApi::Error::MethodNotAllowed
DeskApi::Error::NotAcceptable
DeskApi::Error::Conflict
DeskApi::Error::UnsupportedMediaType
DeskApi::Error::UnprocessableEntity
DeskApi::Error::TooManyRequests
Please also have a look at all
desk.com API errors and
their respective meanings.
License
Copyright (c) 2013-2016, Salesforce.com, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
-
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
-
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
Neither the name of Salesforce.com nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.