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.
-
#proxy ⇒ Object
The HTTP proxy host to connect through, if any.
-
#proxy_password ⇒ Object
The password to use when connecting through an HTTP proxy, if any.
-
#proxy_username ⇒ Object
The username to use when connecting through an HTTP proxy, if any.
-
#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 proxy: http://web-proxy.example.com proxy_username: someuser proxy_password: password - A Hash containing the following keys: client_id client_secret host debugging version sobject_module ca_file verify_mode proxy proxy_username proxy_password If the environment variables DATABASEDOTCOM_CLIENT_ID, DATABASEDOTCOM_CLIENT_SECRET, DATABASEDOTCOM_HOST, DATABASEDOTCOM_DEBUGGING, DATABASEDOTCOM_VERSION, DATABASEDOTCOM_SOBJECT_MODULE, DATABASEDOTCOM_CA_FILE, DATABASEDOTCOM_VERIFY_MODE and/or HTTP_PROXY are present, they override any other values provided
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/databasedotcom/client.rb', line 76 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 self.proxy = ENV['HTTP_PROXY'] || @options[:proxy] self.proxy_username = @options[:proxy_username] self.proxy_password = @options[:proxy_password] 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 |
#proxy ⇒ Object
The HTTP proxy host to connect through, if any
40 41 42 |
# File 'lib/databasedotcom/client.rb', line 40 def proxy @proxy end |
#proxy_password ⇒ Object
The password to use when connecting through an HTTP proxy, if any
44 45 46 |
# File 'lib/databasedotcom/client.rb', line 44 def proxy_password @proxy_password end |
#proxy_username ⇒ Object
The username to use when connecting through an HTTP proxy, if any
42 43 44 |
# File 'lib/databasedotcom/client.rb', line 42 def proxy_username @proxy_username 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
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/databasedotcom/client.rb', line 118 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">
246 247 248 249 250 251 252 253 254 255 256 257 |
# File 'lib/databasedotcom/client.rb', line 246 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")
281 282 283 284 |
# File 'lib/databasedotcom/client.rb', line 281 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.
195 196 197 198 |
# File 'lib/databasedotcom/client.rb', line 195 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.
189 190 191 192 |
# File 'lib/databasedotcom/client.rb', line 189 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", ...>
204 205 206 207 208 209 210 211 212 213 |
# File 'lib/databasedotcom/client.rb', line 204 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.
312 313 314 315 316 |
# File 'lib/databasedotcom/client.rb', line 312 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.
302 303 304 305 306 |
# File 'lib/databasedotcom/client.rb', line 302 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.
340 341 342 343 344 |
# File 'lib/databasedotcom/client.rb', line 340 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.
330 331 332 333 334 |
# File 'lib/databasedotcom/client.rb', line 330 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.
321 322 323 324 325 |
# File 'lib/databasedotcom/client.rb', line 321 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.
156 157 158 159 160 161 162 163 |
# File 'lib/databasedotcom/client.rb', line 156 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.
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/databasedotcom/client.rb', line 171 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.
232 233 234 235 |
# File 'lib/databasedotcom/client.rb', line 232 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.
238 239 240 241 |
# File 'lib/databasedotcom/client.rb', line 238 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", ...> ...]
218 219 220 221 |
# File 'lib/databasedotcom/client.rb', line 218 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.
287 288 289 290 |
# File 'lib/databasedotcom/client.rb', line 287 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", ...> ...]
226 227 228 229 |
# File 'lib/databasedotcom/client.rb', line 226 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.
293 294 295 296 297 |
# File 'lib/databasedotcom/client.rb', line 293 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"})
262 263 264 265 266 |
# File 'lib/databasedotcom/client.rb', line 262 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"})
272 273 274 275 276 |
# File 'lib/databasedotcom/client.rb', line 272 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 |