restforce 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of restforce might be problematic. Click here for more details.
- data/.gitignore +17 -0
- data/.rspec +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +161 -0
- data/Rakefile +10 -0
- data/lib/restforce.rb +18 -0
- data/lib/restforce/client.rb +287 -0
- data/lib/restforce/collection.rb +23 -0
- data/lib/restforce/config.rb +68 -0
- data/lib/restforce/mash.rb +61 -0
- data/lib/restforce/middleware.rb +30 -0
- data/lib/restforce/middleware/authentication.rb +32 -0
- data/lib/restforce/middleware/authentication/oauth.rb +22 -0
- data/lib/restforce/middleware/authentication/password.rb +27 -0
- data/lib/restforce/middleware/authorization.rb +19 -0
- data/lib/restforce/middleware/instance_url.rb +27 -0
- data/lib/restforce/middleware/mashify.rb +18 -0
- data/lib/restforce/middleware/raise_error.rb +18 -0
- data/lib/restforce/sobject.rb +41 -0
- data/lib/restforce/version.rb +3 -0
- data/restforce.gemspec +28 -0
- data/spec/fixtures/auth_error_response.json +1 -0
- data/spec/fixtures/auth_success_response.json +1 -0
- data/spec/fixtures/expired_session_response.json +1 -0
- data/spec/fixtures/reauth_success_response.json +1 -0
- data/spec/fixtures/refresh_error_response.json +1 -0
- data/spec/fixtures/refresh_success_response.json +7 -0
- data/spec/fixtures/services_data_success_response.json +12 -0
- data/spec/fixtures/sobject/create_success_response.json +5 -0
- data/spec/fixtures/sobject/delete_error_response.json +1 -0
- data/spec/fixtures/sobject/describe_sobjects_success_response.json +31 -0
- data/spec/fixtures/sobject/list_sobjects_success_response.json +31 -0
- data/spec/fixtures/sobject/org_query_response.json +11 -0
- data/spec/fixtures/sobject/query_aggregate_success_response.json +23 -0
- data/spec/fixtures/sobject/query_empty_response.json +5 -0
- data/spec/fixtures/sobject/query_error_response.json +4 -0
- data/spec/fixtures/sobject/query_paginated_first_page_response.json +12 -0
- data/spec/fixtures/sobject/query_paginated_last_page_response.json +11 -0
- data/spec/fixtures/sobject/query_success_response.json +36 -0
- data/spec/fixtures/sobject/recent_success_response.json +18 -0
- data/spec/fixtures/sobject/search_error_response.json +4 -0
- data/spec/fixtures/sobject/search_success_response.json +16 -0
- data/spec/fixtures/sobject/sobject_describe_error_response.json +4 -0
- data/spec/fixtures/sobject/sobject_describe_success_response.json +1304 -0
- data/spec/fixtures/sobject/sobject_find_error_response.json +4 -0
- data/spec/fixtures/sobject/sobject_find_success_response.json +29 -0
- data/spec/fixtures/sobject/upsert_created_success_response.json +2 -0
- data/spec/fixtures/sobject/upsert_error_response.json +1 -0
- data/spec/fixtures/sobject/upsert_multiple_error_response.json +1 -0
- data/spec/fixtures/sobject/upsert_updated_success_response.json +0 -0
- data/spec/fixtures/sobject/write_error_response.json +6 -0
- data/spec/lib/client_spec.rb +214 -0
- data/spec/lib/collection_spec.rb +50 -0
- data/spec/lib/config_spec.rb +70 -0
- data/spec/lib/middleware/authentication/oauth_spec.rb +30 -0
- data/spec/lib/middleware/authentication/password_spec.rb +37 -0
- data/spec/lib/middleware/authentication_spec.rb +67 -0
- data/spec/lib/middleware/authorization_spec.rb +17 -0
- data/spec/lib/middleware/instance_url_spec.rb +48 -0
- data/spec/lib/middleware/mashify_spec.rb +28 -0
- data/spec/lib/middleware/raise_error_spec.rb +27 -0
- data/spec/lib/sobject_spec.rb +93 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/support/basic_client.rb +35 -0
- data/spec/support/fixture_helpers.rb +20 -0
- data/spec/support/middleware.rb +33 -0
- metadata +257 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Eric J. Holmes
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
# Restforce [![travis-ci](https://secure.travis-ci.org/ejholmes/restforce.png)](https://secure.travis-ci.org/ejholmes/restforce)
|
2
|
+
|
3
|
+
Restforce is a ruby gem for the [Salesforce REST api](http://www.salesforce.com/us/developer/docs/api_rest/index.htm).
|
4
|
+
It's meant to be a lighter weight alternative to the [databasedotcom gem](https://github.com/heroku/databasedotcom).
|
5
|
+
|
6
|
+
It attempts to solve a couple of key issues that the databasedotcom gem has been unable to solve:
|
7
|
+
|
8
|
+
* Support for interacting with multiple users from different orgs.
|
9
|
+
* Support for parent-to-child relationships.
|
10
|
+
* Support for aggregate queries.
|
11
|
+
* Remove the need to materialize constants.
|
12
|
+
* Support for the Streaming API
|
13
|
+
* A clean and modular architecture using [Faraday middleware](https://github.com/technoweenie/faraday)
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
Add this line to your application's Gemfile:
|
18
|
+
|
19
|
+
gem 'restforce
|
20
|
+
|
21
|
+
And then execute:
|
22
|
+
|
23
|
+
$ bundle
|
24
|
+
|
25
|
+
Or install it yourself as:
|
26
|
+
|
27
|
+
$ gem install restforce
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
Restforce is designed with flexibility and ease of use in mind. By default, all api calls will
|
32
|
+
return [Hashie::Mash](https://github.com/intridea/hashie/tree/v1.2.0) objects,
|
33
|
+
so you can do things like `client.query('select Id, (select Name from Children__r) from Account').Children__r.first.Name`.
|
34
|
+
|
35
|
+
### Initialization
|
36
|
+
|
37
|
+
Which authentication method you use really depends on your use case. If you're
|
38
|
+
building an application where many users from different orgs are authenticated
|
39
|
+
through oauth and you need to interact with data in their org on their behalf,
|
40
|
+
you should use the OAuth token authentication method.
|
41
|
+
|
42
|
+
If you're using the gem to interact with a single org (maybe you're building some
|
43
|
+
salesforce integration internally?) then you should use the username/password
|
44
|
+
authentication method.
|
45
|
+
|
46
|
+
If you have an access token and an instance url obtained through oauth:
|
47
|
+
|
48
|
+
#### OAuth token authentication
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
client = Restforce::Client.new :oauth_token => 'oauth token',
|
52
|
+
:instance_url => 'instance url'
|
53
|
+
```
|
54
|
+
|
55
|
+
Although the above will work, you'll probably want to take advantage of the
|
56
|
+
(re)authentication middleware by specifying a refresh token, client id and client secret:
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
client = Restforce::Client.new :oauth_token => 'oauth token',
|
60
|
+
:refresh_token => 'refresh token',
|
61
|
+
:instance_url => 'instance url',
|
62
|
+
:client_id => 'client_id',
|
63
|
+
:client_secret => 'client_secret'
|
64
|
+
```
|
65
|
+
|
66
|
+
#### Username/Password authentication
|
67
|
+
|
68
|
+
If you prefer to use a username and password to authenticate:
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
client = Restforce::Client.new :username => 'foo',
|
72
|
+
:password => 'bar',
|
73
|
+
:security_token => 'security token'
|
74
|
+
:client_id => 'client_id',
|
75
|
+
:client_secret => 'client_secret'
|
76
|
+
```
|
77
|
+
|
78
|
+
#### Sandbox Orgs
|
79
|
+
|
80
|
+
You can connect to sandbox orgs by specifying a host. The default host is
|
81
|
+
'login.salesforce.com':
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
client = Restforce::Client.new :host => 'test.salesforce.com'
|
85
|
+
```
|
86
|
+
|
87
|
+
#### Global configuration
|
88
|
+
|
89
|
+
You can set any of the options passed into Restforce::Client.new globally:
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
Restforce.configure do |config|
|
93
|
+
config.client_id = ENV['SALESFORCE_CLIENT_ID']
|
94
|
+
config.client_secret = ENV['SALESFORCE_CLIENT_SECRET']
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
### Query
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
accounts = client.query("select Id, Something__c from Account where Id = 'someid'")
|
102
|
+
# => #<Restforce::Collection >
|
103
|
+
|
104
|
+
account = records.first
|
105
|
+
# => #<Restforce::SObject >
|
106
|
+
|
107
|
+
account.Id
|
108
|
+
# => "someid"
|
109
|
+
|
110
|
+
account.Name = 'Foobar'
|
111
|
+
account.save
|
112
|
+
# => true
|
113
|
+
|
114
|
+
account.destroy
|
115
|
+
# => true
|
116
|
+
```
|
117
|
+
|
118
|
+
### Search
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
# Find all occurrences of 'bar'
|
122
|
+
client.search('FIND {bar}')
|
123
|
+
# => #<Restforce::Collection >
|
124
|
+
|
125
|
+
# Find accounts match the term 'genepoint' and return the Name field
|
126
|
+
client.search('FIND {genepoint} RETURNING Account (Name)').map(&:Name)
|
127
|
+
# => ['GenePoint']
|
128
|
+
```
|
129
|
+
|
130
|
+
### Create
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
# Add a new account
|
134
|
+
client.create('Account', Name: 'Foobar Inc.')
|
135
|
+
# => '0016000000MRatd'
|
136
|
+
```
|
137
|
+
|
138
|
+
### Update
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
# Update the Account with Id '0016000000MRatd'
|
142
|
+
client.update('Account', Id: '0016000000MRatd', Name: 'Whizbang Corp')
|
143
|
+
# => true
|
144
|
+
```
|
145
|
+
|
146
|
+
### Destroy
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
# Delete the Account with Id '0016000000MRatd'
|
150
|
+
client.destroy('Account', '0016000000MRatd')
|
151
|
+
# => true
|
152
|
+
```
|
153
|
+
|
154
|
+
|
155
|
+
## Contributing
|
156
|
+
|
157
|
+
1. Fork it
|
158
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
159
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
160
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
161
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/lib/restforce.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday_middleware'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
require 'restforce/version'
|
6
|
+
require 'restforce/config'
|
7
|
+
require 'restforce/mash'
|
8
|
+
require 'restforce/collection'
|
9
|
+
require 'restforce/sobject'
|
10
|
+
require 'restforce/client'
|
11
|
+
|
12
|
+
require 'restforce/middleware'
|
13
|
+
|
14
|
+
module Restforce
|
15
|
+
class AuthenticationError < StandardError; end
|
16
|
+
class UnauthorizedError < StandardError; end
|
17
|
+
class InstanceURLError < StandardError; end
|
18
|
+
end
|
@@ -0,0 +1,287 @@
|
|
1
|
+
module Restforce
|
2
|
+
class Client
|
3
|
+
# Public: Creates a new client instance
|
4
|
+
#
|
5
|
+
# options - A hash of options to be passed in (default: {}).
|
6
|
+
# :username - The String username to use (required for password authentication).
|
7
|
+
# :password - The String password to use (required for password authentication).
|
8
|
+
# :security_token - The String security token to use
|
9
|
+
# (required for password authentication).
|
10
|
+
#
|
11
|
+
# :oauth_token - The String oauth access token to authenticate api
|
12
|
+
# calls (required unless password
|
13
|
+
# authentication is used).
|
14
|
+
# :refresh_token - The String refresh token to obtain fresh
|
15
|
+
# oauth access tokens (required if oauth
|
16
|
+
# authentication is used).
|
17
|
+
# :instance_url - The String base url for all api requests
|
18
|
+
# (required if oauth authentication is used).
|
19
|
+
#
|
20
|
+
# :client_id - The oauth client id to use. Needed for both
|
21
|
+
# password and oauth authentication
|
22
|
+
# :client_secret - The oauth client secret to use.
|
23
|
+
#
|
24
|
+
# :host - The String hostname to use during
|
25
|
+
# authentication requests (default: 'login.salesforce.com').
|
26
|
+
#
|
27
|
+
# :api_version - The String REST api version to use (default: '24.0')
|
28
|
+
#
|
29
|
+
# Examples
|
30
|
+
#
|
31
|
+
# # Initialize a new client using password authentication:
|
32
|
+
# Restforce::Client.new :username => 'user',
|
33
|
+
# :password => 'pass',
|
34
|
+
# :security_token => 'security token',
|
35
|
+
# :client_id => 'client id',
|
36
|
+
# :client_secret => 'client secret'
|
37
|
+
# # => #<Restforce::Client:0x007f934aa2dc28 @options={ ... }>
|
38
|
+
#
|
39
|
+
# # Initialize a new client using oauth authentication:
|
40
|
+
# Restforce::Client.new :oauth_token => 'access token',
|
41
|
+
# :refresh_token => 'refresh token',
|
42
|
+
# :instance_url => 'https://na1.salesforce.com',
|
43
|
+
# :client_id => 'client id',
|
44
|
+
# :client_secret => 'client secret'
|
45
|
+
# # => #<Restforce::Client:0x007f934aaaa0e8 @options={ ... }>
|
46
|
+
#
|
47
|
+
# # Initialize a new client with using any authentication middleware:
|
48
|
+
# Restforce::Client.new :oauth_token => 'access token',
|
49
|
+
# :instance_url => 'https://na1.salesforce.com'
|
50
|
+
# # => #<Restforce::Client:0x007f934aab9980 @options={ ... }>
|
51
|
+
def initialize(options = {})
|
52
|
+
raise 'Please specify a hash of options' unless options.is_a?(Hash)
|
53
|
+
@options = {}.tap do |options|
|
54
|
+
[:username, :password, :security_token, :client_id, :client_secret, :host,
|
55
|
+
:api_version, :oauth_token, :refresh_token, :instance_url].each do |option|
|
56
|
+
options[option] = Restforce.configuration.send option
|
57
|
+
end
|
58
|
+
end
|
59
|
+
@options.merge!(options)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Public: Get the global describe for all sobjects.
|
63
|
+
#
|
64
|
+
# Returns the Hash representation of the describe call.
|
65
|
+
def describe_sobjects
|
66
|
+
response = api_get 'sobjects'
|
67
|
+
response.body['sobjects']
|
68
|
+
end
|
69
|
+
|
70
|
+
# Public: Get the names of all sobjects on the org.
|
71
|
+
#
|
72
|
+
# Examples
|
73
|
+
#
|
74
|
+
# # get the names of all sobjects on the org
|
75
|
+
# client.list_sobjects
|
76
|
+
# # => ['Account', 'Lead', ... ]
|
77
|
+
#
|
78
|
+
# Returns an Array of String names for each SObject.
|
79
|
+
def list_sobjects
|
80
|
+
describe_sobjects.collect { |sobject| sobject['name'] }
|
81
|
+
end
|
82
|
+
|
83
|
+
# Public: Returns a detailed describe result for the specified sobject
|
84
|
+
#
|
85
|
+
# sobject - Stringish name of the sobject (default: nil).
|
86
|
+
#
|
87
|
+
# Examples
|
88
|
+
#
|
89
|
+
# # get the describe for the Account object
|
90
|
+
# client.describe('Account')
|
91
|
+
# # => { ... }
|
92
|
+
#
|
93
|
+
# Returns the Hash representation of the describe call.
|
94
|
+
def describe(sobject)
|
95
|
+
response = api_get "sobject/#{sobject.to_s}/describe"
|
96
|
+
response.body
|
97
|
+
end
|
98
|
+
|
99
|
+
# Public: Get the current organization's Id.
|
100
|
+
#
|
101
|
+
# Examples
|
102
|
+
#
|
103
|
+
# client.org_id
|
104
|
+
# # => '00Dx0000000BV7z'
|
105
|
+
#
|
106
|
+
# Returns the String organization Id
|
107
|
+
def org_id
|
108
|
+
query('select id from Organization').first['Id']
|
109
|
+
end
|
110
|
+
|
111
|
+
# Public: Executs a SOQL query and returns the result.
|
112
|
+
#
|
113
|
+
# Examples
|
114
|
+
#
|
115
|
+
# # Find the names of all Accounts
|
116
|
+
# client.query('select Name from Account').map(&:Name)
|
117
|
+
# # => ['Foo Bar Inc.', 'Whizbang Corp']
|
118
|
+
#
|
119
|
+
# Returns a Restforce::Collection if Restforce.configuration.mashify is true.
|
120
|
+
# Returns an Array of Hash for each record in the result if Restforce.configuration.mashify is false.
|
121
|
+
def query(query)
|
122
|
+
response = api_get 'query', q: query
|
123
|
+
mashify? ? response.body : response.body['records']
|
124
|
+
end
|
125
|
+
|
126
|
+
# Public: Perform a SOSL search
|
127
|
+
#
|
128
|
+
# Examples
|
129
|
+
#
|
130
|
+
# # Find all occurrences of 'bar'
|
131
|
+
# client.search('FIND {bar}')
|
132
|
+
# # => #<Restforce::Collection >
|
133
|
+
#
|
134
|
+
# # Find accounts match the term 'genepoint' and return the Name field
|
135
|
+
# client.search('FIND {genepoint} RETURNING Account (Name)').map(&:Name)
|
136
|
+
# # => ['GenePoint']
|
137
|
+
#
|
138
|
+
# Returns a Restforce::Collection if Restforce.configuration.mashify is true.
|
139
|
+
# Returns an Array of Hash for each record in the result if Restforce.configuration.mashify is false.
|
140
|
+
def search(term)
|
141
|
+
response = api_get 'search', q: term
|
142
|
+
response.body
|
143
|
+
end
|
144
|
+
|
145
|
+
# Public: Insert a new record.
|
146
|
+
#
|
147
|
+
# Examples
|
148
|
+
#
|
149
|
+
# # Add a new account
|
150
|
+
# client.create('Account', Name: 'Foobar Inc.')
|
151
|
+
# # => '0016000000MRatd'
|
152
|
+
#
|
153
|
+
# Returns the String Id of the newly created sobject.
|
154
|
+
def create(sobject, attrs)
|
155
|
+
response = api_post "sobjects/#{sobject}", attrs
|
156
|
+
response.body['id']
|
157
|
+
end
|
158
|
+
|
159
|
+
# Public: Update a record.
|
160
|
+
#
|
161
|
+
# Examples
|
162
|
+
#
|
163
|
+
# # Update the Account with Id '0016000000MRatd'
|
164
|
+
# client.update('Account', Id: '0016000000MRatd', Name: 'Whizbang Corp')
|
165
|
+
#
|
166
|
+
# Returns true if the sobject was successfully update, false otherwise.
|
167
|
+
def update(sobject, attrs)
|
168
|
+
id = attrs.has_key?(:Id) ? attrs.delete(:Id) : attrs.delete('Id')
|
169
|
+
response = api_patch "sobjects/#{sobject}/#{id}", attrs
|
170
|
+
true
|
171
|
+
end
|
172
|
+
|
173
|
+
# Public: Delete a record.
|
174
|
+
#
|
175
|
+
# Examples
|
176
|
+
#
|
177
|
+
# # Delete the Account with Id '0016000000MRatd'
|
178
|
+
# client.delete('Account', '0016000000MRatd')
|
179
|
+
#
|
180
|
+
# Returns true if the sobject was successfully deleted, false otherwise.
|
181
|
+
def destroy(sobject, id)
|
182
|
+
response = api_delete "sobjects/#{sobject}/#{id}"
|
183
|
+
true
|
184
|
+
end
|
185
|
+
|
186
|
+
# Public: Helper methods for performing arbitrary actions against the API using
|
187
|
+
# various HTTP verbs.
|
188
|
+
#
|
189
|
+
# Examples
|
190
|
+
#
|
191
|
+
# # Perform a get request
|
192
|
+
# client.get '/services/data/v24.0/sobjects'
|
193
|
+
# client.api_get 'sobjects'
|
194
|
+
#
|
195
|
+
# # Perform a post request
|
196
|
+
# client.post '/services/data/v24.0/sobjects/Account', { ... }
|
197
|
+
# client.api_post 'sobjects/Account', { ... }
|
198
|
+
#
|
199
|
+
# # Perform a put request
|
200
|
+
# client.put '/services/data/v24.0/sobjects/Account/001D000000INjVe', { ... }
|
201
|
+
# client.api_put 'sobjects/Account/001D000000INjVe', { ... }
|
202
|
+
#
|
203
|
+
# # Perform a delete request
|
204
|
+
# client.delete '/services/data/v24.0/sobjects/Account/001D000000INjVe'
|
205
|
+
# client.api_delete 'sobjects/Account/001D000000INjVe'
|
206
|
+
#
|
207
|
+
# Returns the Faraday::Response.
|
208
|
+
[:get, :post, :put, :delete, :patch].each do |method|
|
209
|
+
define_method method do |*args|
|
210
|
+
begin
|
211
|
+
connection.send(method, *args)
|
212
|
+
rescue Restforce::InstanceURLError
|
213
|
+
connection.url_prefix = @options[:instance_url]
|
214
|
+
connection.send(method, *args)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
define_method :"api_#{method}" do |*args|
|
219
|
+
args[0] = api_path(args[0])
|
220
|
+
send(method, *args)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
private
|
225
|
+
|
226
|
+
# Internal: Returns a path to an api endpoint
|
227
|
+
#
|
228
|
+
# Examples
|
229
|
+
#
|
230
|
+
# api_path('sobjects')
|
231
|
+
# # => '/services/data/v24.0/sobjects'
|
232
|
+
def api_path(path)
|
233
|
+
"/services/data/v#{@options[:api_version]}/#{path}"
|
234
|
+
end
|
235
|
+
|
236
|
+
# Internal: Internal faraday connection where all requests go through
|
237
|
+
def connection
|
238
|
+
@connection ||= Faraday.new do |builder|
|
239
|
+
builder.use Restforce::Middleware::Mashify, self, @options
|
240
|
+
builder.request :json
|
241
|
+
builder.use authentication_middleware, self, @options if authentication_middleware
|
242
|
+
builder.use Restforce::Middleware::Authorization, self, @options
|
243
|
+
builder.use Restforce::Middleware::InstanceURL, self, @options
|
244
|
+
builder.use Restforce::Middleware::RaiseError
|
245
|
+
builder.response :logger, Restforce.configuration.logger if Restforce.log?
|
246
|
+
builder.response :json
|
247
|
+
builder.adapter Faraday.default_adapter
|
248
|
+
end
|
249
|
+
@connection.headers['Content-Type'] = 'application/json'
|
250
|
+
@connection
|
251
|
+
end
|
252
|
+
|
253
|
+
# Internal: Determines what middleware will be used based on the options provided
|
254
|
+
def authentication_middleware
|
255
|
+
if username_password?
|
256
|
+
Restforce::Middleware::Authentication::Password
|
257
|
+
elsif oauth_refresh?
|
258
|
+
Restforce::Middleware::Authentication::OAuth
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
# Internal: Returns true if username/password (autonomous) flow should be used for
|
263
|
+
# authentication.
|
264
|
+
def username_password?
|
265
|
+
@options[:username] &&
|
266
|
+
@options[:password] &&
|
267
|
+
@options[:security_token] &&
|
268
|
+
@options[:client_id] &&
|
269
|
+
@options[:client_secret]
|
270
|
+
end
|
271
|
+
|
272
|
+
# Internal: Returns true if oauth token refresh flow should be used for
|
273
|
+
# authentication.
|
274
|
+
def oauth_refresh?
|
275
|
+
@options[:oauth_token] &&
|
276
|
+
@options[:refresh_token] &&
|
277
|
+
@options[:client_id] &&
|
278
|
+
@options[:client_secret]
|
279
|
+
end
|
280
|
+
|
281
|
+
# Internal: Returns true if the middlware stack includes the
|
282
|
+
# Restforce::Middleware::Mashify middleware.
|
283
|
+
def mashify?
|
284
|
+
connection.builder.handlers.find { |handler| handler == Restforce::Middleware::Mashify }
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|