Class: Databasedotcom::Client
- Inherits:
-
Object
- Object
- Databasedotcom::Client
- Defined in:
- lib/databasedotcom/client.rb
Overview
Interface for operating the Force.com REST API
Instance Attribute Summary collapse
-
#ca_file ⇒ Object
The CA file configured for this instance, if any.
-
#client_id ⇒ Object
The client id (aka “Consumer Key”) to use for OAuth2 authentication.
-
#client_secret ⇒ Object
The client secret (aka “Consumer Secret” to use for OAuth2 authentication).
-
#debugging ⇒ Object
If true, print API debugging information to stdout.
-
#host ⇒ Object
The host to use for OAuth2 authentication.
-
#instance_url ⇒ Object
The base URL to the authenticated user’s SalesForce instance.
-
#oauth_token ⇒ Object
The OAuth access token in use by the client.
-
#org_id ⇒ Object
readonly
The SalesForce organization id for the authenticated user’s Salesforce instance.
-
#password ⇒ Object
The SalesForce password.
-
#refresh_token ⇒ Object
The OAuth refresh token in use by the client.
-
#sobject_module ⇒ Object
A Module in which to materialize Sobject classes.
-
#user_id ⇒ Object
readonly
The SalesForce user id of the authenticated user.
-
#username ⇒ Object
The SalesForce username.
-
#verify_mode ⇒ Object
The SSL verify mode configured for this instance, if any.
-
#version ⇒ Object
The API version the client is using.
Instance Method Summary collapse
-
#authenticate(options = nil) ⇒ Object
Authenticate to the Force.com API.
-
#create(class_or_classname, object_attrs) ⇒ Object
Returns a new instance of class_or_classname (which can be passed in as either a String or a Class) with the specified attributes.
-
#delete(class_or_classname, record_id) ⇒ Object
Deletes the record of type class_or_classname with id of record_id.
-
#describe_sobject(class_name) ⇒ Object
Returns a description of the Sobject specified by class_name.
-
#describe_sobjects ⇒ Object
Returns an Array of Hashes listing the properties for every type of Sobject in the database.
-
#find(class_or_classname, record_id) ⇒ Object
Returns an instance of the Sobject specified by class_or_classname (which can be either a String or a Class) populated with the values of the Force.com record specified by record_id.
-
#http_delete(path, parameters = {}, headers = {}) ⇒ Object
Performs an HTTP DELETE request to the specified path (relative to self.instance_url).
-
#http_get(path, parameters = {}, headers = {}) ⇒ Object
Performs an HTTP GET request to the specified path (relative to self.instance_url).
-
#http_multipart_post(path, parts, parameters = {}, headers = {}) ⇒ Object
Performs an HTTP POST request to the specified path (relative to self.instance_url), using Content-Type multiplart/form-data.
-
#http_patch(path, data = nil, parameters = {}, headers = {}) ⇒ Object
Performs an HTTP PATCH request to the specified path (relative to self.instance_url).
-
#http_post(path, data = nil, parameters = {}, headers = {}) ⇒ Object
Performs an HTTP POST request to the specified path (relative to self.instance_url).
-
#initialize(options = {}) ⇒ Client
constructor
Returns a new client object.
-
#list_sobjects ⇒ Object
Returns an Array of Strings listing the class names for every type of Sobject in the database.
-
#materialize(classnames) ⇒ Object
Dynamically defines classes for Force.com class names.
-
#next_page(path) ⇒ Object
Used by Collection objects.
-
#previous_page(path) ⇒ Object
Used by Collection objects.
-
#query(soql_expr) ⇒ Object
Returns a Collection of Sobjects of the class specified in the soql_expr, which is a valid SOQL expression.
-
#recent ⇒ Object
Returns a Collection of recently touched items.
-
#search(sosl_expr) ⇒ Object
Returns a Collection of Sobject instances form the results of the SOSL search.
-
#trending_topics ⇒ Object
Returns an array of trending topic names.
-
#update(class_or_classname, record_id, new_attrs) ⇒ Object
Updates the attributes of the record of type class_or_classname and specified by record_id with the values of new_attrs in the Force.com database.
-
#upsert(class_or_classname, field, value, attrs) ⇒ Object
Attempts to find the record on Force.com of type class_or_classname with attribute field set as value.
Constructor Details
#initialize(options = {}) ⇒ Client
Returns a new client object. options can be one of the following
-
A String containing the name of a YAML file formatted like:
--- client_id: <your_salesforce_client_id> client_secret: <your_salesforce_client_secret> host: login.salesforce.com debugging: true version: 23.0 sobject_module: My::Module ca_file: some/ca/file.cert verify_mode: OpenSSL::SSL::VERIFY_PEER
-
A Hash containing the following keys:
client_id client_secret host debugging version sobject_module ca_file verify_mode
If the environment variables DATABASEDOTCOM_CLIENT_ID, DATABASEDOTCOM_CLIENT_SECRET, DATABASEDOTCOM_HOST, DATABASEDOTCOM_DEBUGGING, DATABASEDOTCOM_VERSION, DATABASEDOTCOM_SOBJECT_MODULE, DATABASEDOTCOM_CA_FILE, and/or DATABASEDOTCOM_VERIFY_MODE are present, they override any other values provided
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/databasedotcom/client.rb', line 64 def initialize( = {}) if .is_a?(String) @options = YAML.load_file() @options["verify_mode"] = @options["verify_mode"].constantize if @options["verify_mode"] && @options["verify_mode"].is_a?(String) else @options = end @options.symbolize_keys! if ENV['DATABASE_COM_URL'] url = URI.parse(ENV['DATABASE_COM_URL']) = Hash[url.query.split("&").map{|q| q.split("=")}].symbolize_keys! self.host = url.host self.client_id = [:oauth_key] self.client_secret = [:oauth_secret] self.username = [:user] self.password = [:password] else self.client_id = ENV['DATABASEDOTCOM_CLIENT_ID'] || @options[:client_id] self.client_secret = ENV['DATABASEDOTCOM_CLIENT_SECRET'] || @options[:client_secret] self.host = ENV['DATABASEDOTCOM_HOST'] || @options[:host] || "login.salesforce.com" end self.debugging = ENV['DATABASEDOTCOM_DEBUGGING'] || @options[:debugging] self.version = ENV['DATABASEDOTCOM_VERSION'] || @options[:version] self.version = self.version.to_s if self.version self.sobject_module = ENV['DATABASEDOTCOM_SOBJECT_MODULE'] || @options[:sobject_module] self.ca_file = ENV['DATABASEDOTCOM_CA_FILE'] || @options[:ca_file] self.verify_mode = ENV['DATABASEDOTCOM_VERIFY_MODE'] || @options[:verify_mode] self.verify_mode = self.verify_mode.to_i if self.verify_mode end |
Instance Attribute Details
#ca_file ⇒ Object
The CA file configured for this instance, if any
36 37 38 |
# File 'lib/databasedotcom/client.rb', line 36 def ca_file @ca_file end |
#client_id ⇒ Object
The client id (aka “Consumer Key”) to use for OAuth2 authentication
10 11 12 |
# File 'lib/databasedotcom/client.rb', line 10 def client_id @client_id end |
#client_secret ⇒ Object
The client secret (aka “Consumer Secret” to use for OAuth2 authentication)
12 13 14 |
# File 'lib/databasedotcom/client.rb', line 12 def client_secret @client_secret end |
#debugging ⇒ Object
If true, print API debugging information to stdout. Defaults to false.
20 21 22 |
# File 'lib/databasedotcom/client.rb', line 20 def debugging @debugging end |
#host ⇒ Object
The host to use for OAuth2 authentication. Defaults to login.salesforce.com
22 23 24 |
# File 'lib/databasedotcom/client.rb', line 22 def host @host end |
#instance_url ⇒ Object
The base URL to the authenticated user’s SalesForce instance
18 19 20 |
# File 'lib/databasedotcom/client.rb', line 18 def instance_url @instance_url end |
#oauth_token ⇒ Object
The OAuth access token in use by the client
14 15 16 |
# File 'lib/databasedotcom/client.rb', line 14 def oauth_token @oauth_token end |
#org_id ⇒ Object (readonly)
The SalesForce organization id for the authenticated user’s Salesforce instance
34 35 36 |
# File 'lib/databasedotcom/client.rb', line 34 def org_id @org_id end |
#password ⇒ Object
The SalesForce password
32 33 34 |
# File 'lib/databasedotcom/client.rb', line 32 def password @password end |
#refresh_token ⇒ Object
The OAuth refresh token in use by the client
16 17 18 |
# File 'lib/databasedotcom/client.rb', line 16 def refresh_token @refresh_token end |
#sobject_module ⇒ Object
A Module in which to materialize Sobject classes. Defaults to the global module (Object)
26 27 28 |
# File 'lib/databasedotcom/client.rb', line 26 def sobject_module @sobject_module end |
#user_id ⇒ Object (readonly)
The SalesForce user id of the authenticated user
28 29 30 |
# File 'lib/databasedotcom/client.rb', line 28 def user_id @user_id end |
#username ⇒ Object
The SalesForce username
30 31 32 |
# File 'lib/databasedotcom/client.rb', line 30 def username @username end |
#verify_mode ⇒ Object
The SSL verify mode configured for this instance, if any
38 39 40 |
# File 'lib/databasedotcom/client.rb', line 38 def verify_mode @verify_mode end |
#version ⇒ Object
The API version the client is using. Defaults to 23.0
24 25 26 |
# File 'lib/databasedotcom/client.rb', line 24 def version @version end |
Instance Method Details
#authenticate(options = nil) ⇒ Object
Authenticate to the Force.com API. options is a Hash, interpreted as follows:
-
If options contains the keys
:username
and:password
, those credentials are used to authenticate. In this case, the value of:password
may need to include a concatenated security token, if required by your Salesforce org -
If options contains the key
:provider
, it is assumed to be the hash returned by Omniauth from a successful web-based OAuth2 authentication -
If options contains the keys
:token
and:instance_url
, those are assumed to be a valid OAuth2 token and instance URL for a Salesforce account, obtained from an external source. options may also optionally contain the key:refresh_token
Raises SalesForceError if an error occurs
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/databasedotcom/client.rb', line 103 def authenticate( = nil) if user_and_pass?() req = https_request(self.host) user = self.username || [:username] pass = self.password || [:password] path = encode_path_with_params('/services/oauth2/token', :grant_type => 'password', :client_id => self.client_id, :client_secret => self.client_secret, :username => user, :password => pass) log_request("https://#{self.host}/#{path}") result = req.post(path, "") log_response(result) raise SalesForceError.new(result) unless result.is_a?(Net::HTTPOK) self.username = user self.password = pass parse_auth_response(result.body) elsif .is_a?(Hash) if .has_key?("provider") parse_user_id_and_org_id_from_identity_url(["uid"]) self.instance_url = ["credentials"]["instance_url"] self.oauth_token = ["credentials"]["token"] self.refresh_token = ["credentials"]["refresh_token"] else raise ArgumentError unless .has_key?(:token) && .has_key?(:instance_url) self.instance_url = [:instance_url] self.oauth_token = [:token] self.refresh_token = [:refresh_token] end end self.version = "22.0" unless self.version self.oauth_token end |
#create(class_or_classname, object_attrs) ⇒ Object
Returns a new instance of class_or_classname (which can be passed in as either a String or a Class) with the specified attributes.
client.create("Car", {"Color" => "Blue", "Year" => "2011"}) #=> #<Car @Id="recordid", @Color="Blue", @Year="2011">
231 232 233 234 235 236 237 238 239 240 241 242 |
# File 'lib/databasedotcom/client.rb', line 231 def create(class_or_classname, object_attrs) class_or_classname = find_or_materialize(class_or_classname) json_for_assignment = coerced_json(object_attrs, class_or_classname) result = http_post("/services/data/v#{self.version}/sobjects/#{class_or_classname.sobject_name}", json_for_assignment) new_object = class_or_classname.new JSON.parse(json_for_assignment).each do |property, value| set_value(new_object, property, value, class_or_classname.type_map[property][:type]) end id = JSON.parse(result.body)["id"] set_value(new_object, "Id", id, "id") new_object end |
#delete(class_or_classname, record_id) ⇒ Object
Deletes the record of type class_or_classname with id of record_id. class_or_classname can be a String or a Class.
client.delete(Car, "rid")
266 267 268 269 |
# File 'lib/databasedotcom/client.rb', line 266 def delete(class_or_classname, record_id) clazz = find_or_materialize(class_or_classname) http_delete("/services/data/v#{self.version}/sobjects/#{clazz.sobject_name}/#{record_id}") end |
#describe_sobject(class_name) ⇒ Object
Returns a description of the Sobject specified by class_name. The description includes all fields and their properties for the Sobject.
180 181 182 183 |
# File 'lib/databasedotcom/client.rb', line 180 def describe_sobject(class_name) result = http_get("/services/data/v#{self.version}/sobjects/#{class_name}/describe") JSON.parse(result.body) end |
#describe_sobjects ⇒ Object
Returns an Array of Hashes listing the properties for every type of Sobject in the database. Raises SalesForceError if an error occurs.
174 175 176 177 |
# File 'lib/databasedotcom/client.rb', line 174 def describe_sobjects result = http_get("/services/data/v#{self.version}/sobjects") JSON.parse(result.body)["sobjects"] end |
#find(class_or_classname, record_id) ⇒ Object
Returns an instance of the Sobject specified by class_or_classname (which can be either a String or a Class) populated with the values of the Force.com record specified by record_id. If given a Class that is not defined, it will attempt to materialize the class on demand.
client.find(Account, "recordid") #=> #<Account @Id="recordid", ...>
189 190 191 192 193 194 195 196 197 198 |
# File 'lib/databasedotcom/client.rb', line 189 def find(class_or_classname, record_id) class_or_classname = find_or_materialize(class_or_classname) result = http_get("/services/data/v#{self.version}/sobjects/#{class_or_classname.sobject_name}/#{record_id}") response = JSON.parse(result.body) new_record = class_or_classname.new class_or_classname.description["fields"].each do |field| set_value(new_record, field["name"], response[key_from_label(field["label"])] || response[field["name"]], field["type"]) end new_record end |
#http_delete(path, parameters = {}, headers = {}) ⇒ Object
Performs an HTTP DELETE request to the specified path (relative to self.instance_url). Query parameters are included from parameters. The required Authorization
header is automatically included, as are any additional headers specified in headers. Returns the HTTPResult if it is of type HTTPSuccess- raises SalesForceError otherwise.
297 298 299 300 301 |
# File 'lib/databasedotcom/client.rb', line 297 def http_delete(path, parameters={}, headers={}) with_encoded_path_and_checked_response(path, parameters, {:expected_result_class => Net::HTTPNoContent}) do |encoded_path| https_request.delete(encoded_path, {"Authorization" => "OAuth #{self.oauth_token}"}.merge(headers)) end end |
#http_get(path, parameters = {}, headers = {}) ⇒ Object
Performs an HTTP GET request to the specified path (relative to self.instance_url). Query parameters are included from parameters. The required Authorization
header is automatically included, as are any additional headers specified in headers. Returns the HTTPResult if it is of type HTTPSuccess- raises SalesForceError otherwise.
287 288 289 290 291 |
# File 'lib/databasedotcom/client.rb', line 287 def http_get(path, parameters={}, headers={}) with_encoded_path_and_checked_response(path, parameters) do |encoded_path| https_request.get(encoded_path, {"Authorization" => "OAuth #{self.oauth_token}"}.merge(headers)) end end |
#http_multipart_post(path, parts, parameters = {}, headers = {}) ⇒ Object
Performs an HTTP POST request to the specified path (relative to self.instance_url), using Content-Type multiplart/form-data. The parts of the body of the request are taken from parts_. Query parameters are included from parameters. The required Authorization
header is automatically included, as are any additional headers specified in headers. Returns the HTTPResult if it is of type HTTPSuccess- raises SalesForceError otherwise.
325 326 327 328 329 |
# File 'lib/databasedotcom/client.rb', line 325 def http_multipart_post(path, parts, parameters={}, headers={}) with_encoded_path_and_checked_response(path, parameters) do |encoded_path| https_request.request(Net::HTTP::Post::Multipart.new(encoded_path, parts, {"Authorization" => "OAuth #{self.oauth_token}"}.merge(headers))) end end |
#http_patch(path, data = nil, parameters = {}, headers = {}) ⇒ Object
Performs an HTTP PATCH request to the specified path (relative to self.instance_url). The body of the request is taken from data. Query parameters are included from parameters. The required Authorization
header is automatically included, as are any additional headers specified in headers. Returns the HTTPResult if it is of type HTTPSuccess- raises SalesForceError otherwise.
315 316 317 318 319 |
# File 'lib/databasedotcom/client.rb', line 315 def http_patch(path, data=nil, parameters={}, headers={}) with_encoded_path_and_checked_response(path, parameters, {:data => data}) do |encoded_path| https_request.send_request("PATCH", encoded_path, data, {"Content-Type" => data ? "application/json" : "text/plain", "Authorization" => "OAuth #{self.oauth_token}"}.merge(headers)) end end |
#http_post(path, data = nil, parameters = {}, headers = {}) ⇒ Object
Performs an HTTP POST request to the specified path (relative to self.instance_url). The body of the request is taken from data. Query parameters are included from parameters. The required Authorization
header is automatically included, as are any additional headers specified in headers. Returns the HTTPResult if it is of type HTTPSuccess- raises SalesForceError otherwise.
306 307 308 309 310 |
# File 'lib/databasedotcom/client.rb', line 306 def http_post(path, data=nil, parameters={}, headers={}) with_encoded_path_and_checked_response(path, parameters, {:data => data}) do |encoded_path| https_request.post(encoded_path, data, {"Content-Type" => data ? "application/json" : "text/plain", "Authorization" => "OAuth #{self.oauth_token}"}.merge(headers)) end end |
#list_sobjects ⇒ Object
Returns an Array of Strings listing the class names for every type of Sobject in the database. Raises SalesForceError if an error occurs.
141 142 143 144 145 146 147 148 |
# File 'lib/databasedotcom/client.rb', line 141 def list_sobjects result = http_get("/services/data/v#{self.version}/sobjects") if result.is_a?(Net::HTTPOK) JSON.parse(result.body)["sobjects"].collect { |sobject| sobject["name"] } elsif result.is_a?(Net::HTTPBadRequest) raise SalesForceError.new(result) end end |
#materialize(classnames) ⇒ Object
Dynamically defines classes for Force.com class names. classnames can be a single String or an Array of Strings. Returns the class or Array of classes defined.
client.materialize("Contact") #=> Contact
client.materialize(%w(Contact Company)) #=> [Contact, Company]
The classes defined by materialize derive from Sobject, and have getters and setters defined for all the attributes defined by the associated Force.com Sobject.
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/databasedotcom/client.rb', line 156 def materialize(classnames) classes = (classnames.is_a?(Array) ? classnames : [classnames]).collect do |clazz| original_classname = clazz clazz = original_classname[0,1].capitalize + original_classname[1..-1] unless const_defined_in_module(module_namespace, clazz) new_class = module_namespace.const_set(clazz, Class.new(Databasedotcom::Sobject::Sobject)) new_class.client = self new_class.materialize(original_classname) new_class else module_namespace.const_get(clazz) end end classes.length == 1 ? classes.first : classes end |
#next_page(path) ⇒ Object
Used by Collection objects. Returns a Collection of Sobjects from the specified URL path that represents the next page of paginated results.
217 218 219 220 |
# File 'lib/databasedotcom/client.rb', line 217 def next_page(path) result = http_get(path) collection_from(result.body) end |
#previous_page(path) ⇒ Object
Used by Collection objects. Returns a Collection of Sobjects from the specified URL path that represents the previous page of paginated results.
223 224 225 226 |
# File 'lib/databasedotcom/client.rb', line 223 def previous_page(path) result = http_get(path) collection_from(result.body) end |
#query(soql_expr) ⇒ Object
Returns a Collection of Sobjects of the class specified in the soql_expr, which is a valid SOQL expression. The objects will only be populated with the values of attributes specified in the query.
client.query("SELECT Name FROM Account") #=> [#<Account @Id=nil, @Name="Foo", ...>, #<Account @Id=nil, @Name="Bar", ...> ...]
203 204 205 206 |
# File 'lib/databasedotcom/client.rb', line 203 def query(soql_expr) result = http_get("/services/data/v#{self.version}/query", :q => soql_expr) collection_from(result.body) end |
#recent ⇒ Object
Returns a Collection of recently touched items. The Collection contains Sobject instances that are fully populated with their correct values.
272 273 274 275 |
# File 'lib/databasedotcom/client.rb', line 272 def recent result = http_get("/services/data/v#{self.version}/recent") collection_from(result.body) end |
#search(sosl_expr) ⇒ Object
Returns a Collection of Sobject instances form the results of the SOSL search.
client.search("FIND {bar}") #=> [#<Account @Name="foobar", ...>, #<Account @Name="barfoo", ...> ...]
211 212 213 214 |
# File 'lib/databasedotcom/client.rb', line 211 def search(sosl_expr) result = http_get("/services/data/v#{self.version}/search", :q => sosl_expr) collection_from(result.body) end |
#trending_topics ⇒ Object
Returns an array of trending topic names.
278 279 280 281 282 |
# File 'lib/databasedotcom/client.rb', line 278 def trending_topics result = http_get("/services/data/v#{self.version}/chatter/topics/trending") result = JSON.parse(result.body) result["topics"].collect { |topic| topic["name"] } end |
#update(class_or_classname, record_id, new_attrs) ⇒ Object
Updates the attributes of the record of type class_or_classname and specified by record_id with the values of new_attrs in the Force.com database. new_attrs is a hash of attribute => value
client.update("Car", "rid", {"Color" => "Red"})
247 248 249 250 251 |
# File 'lib/databasedotcom/client.rb', line 247 def update(class_or_classname, record_id, new_attrs) class_or_classname = find_or_materialize(class_or_classname) json_for_update = coerced_json(new_attrs, class_or_classname) http_patch("/services/data/v#{self.version}/sobjects/#{class_or_classname.sobject_name}/#{record_id}", json_for_update) end |
#upsert(class_or_classname, field, value, attrs) ⇒ Object
Attempts to find the record on Force.com of type class_or_classname with attribute field set as value. If found, it will update the record with the attrs hash. If not found, it will create a new record with attrs.
client.upsert(Car, "Color", "Blue", {"Year" => "2012"})
257 258 259 260 261 |
# File 'lib/databasedotcom/client.rb', line 257 def upsert(class_or_classname, field, value, attrs) clazz = find_or_materialize(class_or_classname) json_for_update = coerced_json(attrs, clazz) http_patch("/services/data/v#{self.version}/sobjects/#{clazz.sobject_name}/#{field}/#{value}", json_for_update) end |