restforce 3.0.1 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.circleci/config.yml +9 -9
- data/.rubocop.yml +10 -12
- data/.rubocop_todo.yml +128 -81
- data/CHANGELOG.md +30 -1
- data/Gemfile +2 -1
- data/README.md +124 -12
- data/lib/restforce.rb +22 -1
- data/lib/restforce/abstract_client.rb +1 -0
- data/lib/restforce/attachment.rb +1 -0
- data/lib/restforce/concerns/api.rb +9 -6
- data/lib/restforce/concerns/authentication.rb +10 -0
- data/lib/restforce/concerns/base.rb +2 -0
- data/lib/restforce/concerns/batch_api.rb +87 -0
- data/lib/restforce/concerns/canvas.rb +1 -0
- data/lib/restforce/concerns/picklists.rb +2 -1
- data/lib/restforce/concerns/streaming.rb +75 -3
- data/lib/restforce/config.rb +4 -0
- data/lib/restforce/document.rb +1 -0
- data/lib/restforce/middleware/authentication.rb +3 -2
- data/lib/restforce/middleware/authentication/jwt_bearer.rb +38 -0
- data/lib/restforce/middleware/multipart.rb +1 -0
- data/lib/restforce/middleware/raise_error.rb +24 -8
- data/lib/restforce/signed_request.rb +1 -0
- data/lib/restforce/sobject.rb +1 -0
- data/lib/restforce/tooling/client.rb +3 -3
- data/lib/restforce/version.rb +1 -1
- data/restforce.gemspec +8 -7
- data/spec/fixtures/test_private.key +27 -0
- data/spec/integration/abstract_client_spec.rb +42 -1
- data/spec/support/fixture_helpers.rb +2 -2
- data/spec/unit/concerns/authentication_spec.rb +35 -0
- data/spec/unit/concerns/batch_api_spec.rb +107 -0
- data/spec/unit/concerns/streaming_spec.rb +144 -4
- data/spec/unit/middleware/authentication/jwt_bearer_spec.rb +62 -0
- data/spec/unit/middleware/raise_error_spec.rb +32 -11
- metadata +53 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d1eb25f3f88951d1770c5850c41a9d673d3b0406a76d0c35e54288d52ee5dc00
|
4
|
+
data.tar.gz: 51af3a7a4a1e701a4f5e8a79c21452ca5417581aa889188e7f5b5e010fb8f39a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eabc94739d7bbdb2e88fcf3b2ff4bfb3c0b4272f74f50d6fef3f549ca559cd52ab212b5fbd6988da0237257aef7d092b4f654e275a797beb28947b268263f07d
|
7
|
+
data.tar.gz: 56ac8e739182f941a45cffe4c8b28364d8b99243128c8c7864820e15e752785af3938c8f99377e3428dcc9a61ac98a72703850675455cc88effe5b68bdca454b
|
data/.circleci/config.yml
CHANGED
@@ -34,23 +34,23 @@ references:
|
|
34
34
|
destination: test-results
|
35
35
|
|
36
36
|
jobs:
|
37
|
-
build-
|
37
|
+
build-ruby265:
|
38
38
|
docker:
|
39
|
-
- image: circleci/ruby:2.5
|
39
|
+
- image: circleci/ruby:2.6.5
|
40
40
|
steps: *steps
|
41
|
-
build-
|
41
|
+
build-ruby257:
|
42
42
|
docker:
|
43
|
-
- image: circleci/ruby:2.
|
43
|
+
- image: circleci/ruby:2.5.7
|
44
44
|
steps: *steps
|
45
|
-
build-
|
45
|
+
build-ruby249:
|
46
46
|
docker:
|
47
|
-
- image: circleci/ruby:2.
|
47
|
+
- image: circleci/ruby:2.4.9
|
48
48
|
steps: *steps
|
49
49
|
|
50
50
|
workflows:
|
51
51
|
version: 2
|
52
52
|
tests:
|
53
53
|
jobs:
|
54
|
-
- build-
|
55
|
-
- build-
|
56
|
-
- build-
|
54
|
+
- build-ruby265
|
55
|
+
- build-ruby257
|
56
|
+
- build-ruby249
|
data/.rubocop.yml
CHANGED
@@ -4,46 +4,44 @@ inherit_from: .rubocop_todo.yml
|
|
4
4
|
|
5
5
|
AllCops:
|
6
6
|
DisplayCopNames: true
|
7
|
-
Include:
|
8
|
-
- Rakefile
|
9
7
|
Exclude:
|
10
8
|
- .*/**/*
|
11
9
|
- vendor/**/*
|
12
|
-
TargetRubyVersion: 2.
|
10
|
+
TargetRubyVersion: 2.4
|
13
11
|
|
14
12
|
# Limit lines to 80 characters.
|
15
|
-
LineLength:
|
13
|
+
Metrics/LineLength:
|
16
14
|
Max: 90
|
17
15
|
|
18
|
-
ClassLength:
|
16
|
+
Metrics/ClassLength:
|
19
17
|
Enabled: false
|
20
18
|
|
21
|
-
ModuleLength:
|
19
|
+
Metrics/ModuleLength:
|
22
20
|
Enabled: false
|
23
21
|
|
24
22
|
# Avoid methods longer than 30 lines of code
|
25
|
-
MethodLength:
|
23
|
+
Metrics/MethodLength:
|
26
24
|
CountComments: false # count full line comments?
|
27
25
|
Max: 87
|
28
26
|
|
29
27
|
# Avoid single-line methods.
|
30
|
-
SingleLineMethods:
|
28
|
+
Style/SingleLineMethods:
|
31
29
|
AllowIfMethodIsEmpty: true
|
32
30
|
|
33
|
-
StringLiterals:
|
31
|
+
Style/StringLiterals:
|
34
32
|
Enabled: false
|
35
33
|
|
36
|
-
GlobalVars:
|
34
|
+
Style/GlobalVars:
|
37
35
|
Enabled: false # We use them Redis + StatsD (though maybe we shouldn't?)
|
38
36
|
|
39
37
|
# Wants underscores in all large numbers. Pain in the ass for things like
|
40
38
|
# unix timestamps.
|
41
|
-
NumericLiterals:
|
39
|
+
Style/NumericLiterals:
|
42
40
|
Enabled: false
|
43
41
|
|
44
42
|
# Wants you to use the same argument names for every reduce. This seems kinda
|
45
43
|
# naff compared to naming them semantically
|
46
|
-
SingleLineBlockParams:
|
44
|
+
Style/SingleLineBlockParams:
|
47
45
|
Enabled: false
|
48
46
|
|
49
47
|
Style/SignalException:
|
data/.rubocop_todo.yml
CHANGED
@@ -1,117 +1,164 @@
|
|
1
|
-
# This configuration was generated by
|
2
|
-
#
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2019-10-09 21:39:40 +0100 using RuboCop version 0.75.0.
|
3
4
|
# The point is for the user to remove these configuration records
|
4
5
|
# one by one as the offenses are removed from the code base.
|
5
6
|
# Note that changes in the inspected code, or installation of new
|
6
7
|
# versions of RuboCop, may require this file to be generated again.
|
7
8
|
|
8
|
-
# Offense count:
|
9
|
+
# Offense count: 17
|
9
10
|
# Cop supports --auto-correct.
|
11
|
+
# Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle.
|
12
|
+
# SupportedHashRocketStyles: key, separator, table
|
13
|
+
# SupportedColonStyles: key, separator, table
|
14
|
+
# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit
|
15
|
+
Layout/AlignHash:
|
16
|
+
Exclude:
|
17
|
+
- 'lib/restforce/middleware/logger.rb'
|
18
|
+
- 'restforce.gemspec'
|
19
|
+
- 'spec/integration/abstract_client_spec.rb'
|
20
|
+
- 'spec/unit/config_spec.rb'
|
21
|
+
|
22
|
+
# Offense count: 2
|
23
|
+
# Cop supports --auto-correct.
|
24
|
+
# Configuration parameters: EnforcedStyle, IndentationWidth.
|
25
|
+
# SupportedStyles: special_inside_parentheses, consistent, align_braces
|
26
|
+
Layout/IndentFirstHashElement:
|
27
|
+
Exclude:
|
28
|
+
- 'lib/restforce/concerns/connection.rb'
|
29
|
+
|
30
|
+
# Offense count: 1
|
31
|
+
# Cop supports --auto-correct.
|
32
|
+
# Configuration parameters: AllowForAlignment.
|
33
|
+
Layout/SpaceAroundOperators:
|
34
|
+
Exclude:
|
35
|
+
- 'lib/restforce.rb'
|
36
|
+
|
37
|
+
# Offense count: 8
|
38
|
+
# Cop supports --auto-correct.
|
39
|
+
# Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments.
|
10
40
|
Lint/UnusedBlockArgument:
|
11
|
-
|
41
|
+
Exclude:
|
42
|
+
- 'lib/restforce/concerns/api.rb'
|
43
|
+
- 'lib/restforce/concerns/batch_api.rb'
|
44
|
+
- 'lib/restforce/middleware/multipart.rb'
|
45
|
+
- 'spec/unit/config_spec.rb'
|
12
46
|
|
13
|
-
# Offense count:
|
47
|
+
# Offense count: 9
|
14
48
|
Metrics/AbcSize:
|
15
|
-
Max:
|
49
|
+
Max: 38
|
16
50
|
|
17
|
-
# Offense count:
|
51
|
+
# Offense count: 1
|
18
52
|
Metrics/CyclomaticComplexity:
|
19
|
-
Max:
|
53
|
+
Max: 8
|
20
54
|
|
21
|
-
# Offense count:
|
55
|
+
# Offense count: 1
|
22
56
|
Metrics/PerceivedComplexity:
|
23
|
-
Max:
|
57
|
+
Max: 9
|
24
58
|
|
25
|
-
# Offense count:
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
59
|
+
# Offense count: 5
|
60
|
+
# Configuration parameters: EnforcedStyleForLeadingUnderscores.
|
61
|
+
# SupportedStylesForLeadingUnderscores: disallowed, required, optional
|
62
|
+
Naming/MemoizedInstanceVariableName:
|
63
|
+
Exclude:
|
64
|
+
- 'lib/restforce/concerns/picklists.rb'
|
65
|
+
- 'lib/restforce/concerns/streaming.rb'
|
66
|
+
|
67
|
+
# Offense count: 2
|
68
|
+
# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist, MethodDefinitionMacros.
|
69
|
+
# NamePrefix: is_, has_, have_
|
70
|
+
# NamePrefixBlacklist: is_, has_, have_
|
71
|
+
# NameWhitelist: is_a?
|
72
|
+
# MethodDefinitionMacros: define_method, define_singleton_method
|
73
|
+
Naming/PredicateName:
|
74
|
+
Exclude:
|
75
|
+
- 'spec/**/*'
|
76
|
+
- 'lib/restforce/collection.rb'
|
77
|
+
- 'lib/restforce/middleware/multipart.rb'
|
34
78
|
|
35
|
-
# Offense count:
|
79
|
+
# Offense count: 12
|
36
80
|
# Cop supports --auto-correct.
|
37
|
-
# Configuration parameters: EnforcedStyle,
|
81
|
+
# Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, IgnoredMethods, AllowBracesOnProceduralOneLiners.
|
82
|
+
# SupportedStyles: line_count_based, semantic, braces_for_chaining, always_braces
|
83
|
+
# ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object
|
84
|
+
# FunctionalMethods: let, let!, subject, watch
|
85
|
+
# IgnoredMethods: lambda, proc, it
|
38
86
|
Style/BlockDelimiters:
|
39
|
-
|
87
|
+
Exclude:
|
88
|
+
- 'lib/restforce/concerns/batch_api.rb'
|
89
|
+
- 'spec/support/event_machine.rb'
|
90
|
+
- 'spec/support/middleware.rb'
|
91
|
+
- 'spec/unit/concerns/base_spec.rb'
|
92
|
+
- 'spec/unit/concerns/batch_api_spec.rb'
|
93
|
+
- 'spec/unit/concerns/caching_spec.rb'
|
94
|
+
- 'spec/unit/concerns/streaming_spec.rb'
|
95
|
+
- 'spec/unit/middleware/authentication_spec.rb'
|
96
|
+
- 'spec/unit/middleware/mashify_spec.rb'
|
40
97
|
|
41
|
-
# Offense count:
|
42
|
-
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
43
|
-
Style/ClassAndModuleChildren:
|
44
|
-
Enabled: false
|
45
|
-
|
46
|
-
# Offense count: 21
|
47
|
-
# Cop supports --auto-correct.
|
48
|
-
Layout/ClosingParenthesisIndentation:
|
49
|
-
Enabled: false
|
50
|
-
|
51
|
-
# Offense count: 13
|
98
|
+
# Offense count: 12
|
52
99
|
# Cop supports --auto-correct.
|
53
|
-
# Configuration parameters:
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
100
|
+
# Configuration parameters: AutoCorrect, EnforcedStyle.
|
101
|
+
# SupportedStyles: nested, compact
|
102
|
+
Style/ClassAndModuleChildren:
|
103
|
+
Exclude:
|
104
|
+
- 'lib/restforce/middleware/authentication.rb'
|
105
|
+
- 'lib/restforce/middleware/authentication/password.rb'
|
106
|
+
- 'lib/restforce/middleware/authentication/token.rb'
|
107
|
+
- 'lib/restforce/middleware/authorization.rb'
|
108
|
+
- 'lib/restforce/middleware/caching.rb'
|
109
|
+
- 'lib/restforce/middleware/custom_headers.rb'
|
110
|
+
- 'lib/restforce/middleware/gzip.rb'
|
111
|
+
- 'lib/restforce/middleware/instance_url.rb'
|
112
|
+
- 'lib/restforce/middleware/logger.rb'
|
113
|
+
- 'lib/restforce/middleware/mashify.rb'
|
114
|
+
- 'lib/restforce/middleware/multipart.rb'
|
115
|
+
- 'lib/restforce/middleware/raise_error.rb'
|
116
|
+
|
117
|
+
# Offense count: 36
|
58
118
|
Style/Documentation:
|
59
119
|
Enabled: false
|
60
120
|
|
61
|
-
# Offense count:
|
121
|
+
# Offense count: 3
|
62
122
|
Style/DoubleNegation:
|
63
|
-
|
123
|
+
Exclude:
|
124
|
+
- 'lib/restforce/concerns/picklists.rb'
|
125
|
+
- 'lib/restforce/middleware/instance_url.rb'
|
64
126
|
|
65
|
-
# Offense count:
|
127
|
+
# Offense count: 1
|
66
128
|
# Configuration parameters: MinBodyLength.
|
67
129
|
Style/GuardClause:
|
68
|
-
|
69
|
-
|
70
|
-
# Offense count: 48
|
71
|
-
# Cop supports --auto-correct.
|
72
|
-
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
73
|
-
Layout/IndentHash:
|
74
|
-
Enabled: false
|
130
|
+
Exclude:
|
131
|
+
- 'lib/restforce/middleware/authentication.rb'
|
75
132
|
|
76
|
-
# Offense count:
|
133
|
+
# Offense count: 25
|
77
134
|
# Cop supports --auto-correct.
|
135
|
+
# Configuration parameters: EnforcedStyle.
|
136
|
+
# SupportedStyles: line_count_dependent, lambda, literal
|
78
137
|
Style/Lambda:
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
138
|
+
Exclude:
|
139
|
+
- 'lib/restforce/config.rb'
|
140
|
+
- 'spec/integration/abstract_client_spec.rb'
|
141
|
+
- 'spec/unit/concerns/base_spec.rb'
|
142
|
+
- 'spec/unit/concerns/streaming_spec.rb'
|
143
|
+
- 'spec/unit/middleware/authentication_spec.rb'
|
144
|
+
- 'spec/unit/middleware/authorization_spec.rb'
|
145
|
+
- 'spec/unit/middleware/custom_headers_spec.rb'
|
146
|
+
- 'spec/unit/middleware/gzip_spec.rb'
|
147
|
+
- 'spec/unit/middleware/instance_url_spec.rb'
|
148
|
+
- 'spec/unit/middleware/logger_spec.rb'
|
149
|
+
- 'spec/unit/sobject_spec.rb'
|
91
150
|
|
92
|
-
# Offense count:
|
93
|
-
# Cop supports --auto-correct.
|
94
|
-
Style/Proc:
|
95
|
-
Enabled: false
|
96
|
-
|
97
|
-
# Offense count: 173
|
151
|
+
# Offense count: 5
|
98
152
|
# Cop supports --auto-correct.
|
99
153
|
Style/RedundantSelf:
|
100
|
-
|
154
|
+
Exclude:
|
155
|
+
- 'lib/restforce/mash.rb'
|
156
|
+
- 'lib/restforce/sobject.rb'
|
101
157
|
|
102
|
-
# Offense count:
|
103
|
-
# Cop supports --auto-correct.
|
104
|
-
Layout/SpaceBeforeFirstArg:
|
105
|
-
Enabled: false
|
106
|
-
|
107
|
-
# Offense count: 3
|
108
|
-
# Cop supports --auto-correct.
|
109
|
-
# Configuration parameters: MultiSpaceAllowedForOperators.
|
110
|
-
Layout/SpaceAroundOperators:
|
111
|
-
Enabled: false
|
112
|
-
|
113
|
-
# Offense count: 5
|
158
|
+
# Offense count: 1
|
114
159
|
# Cop supports --auto-correct.
|
115
160
|
# Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, IgnoreClassMethods, Whitelist.
|
161
|
+
# Whitelist: to_ary, to_a, to_c, to_enum, to_h, to_hash, to_i, to_int, to_io, to_open, to_path, to_proc, to_r, to_regexp, to_str, to_s, to_sym
|
116
162
|
Style/TrivialAccessors:
|
117
|
-
|
163
|
+
Exclude:
|
164
|
+
- 'lib/restforce/middleware.rb'
|
data/CHANGELOG.md
CHANGED
@@ -1,16 +1,45 @@
|
|
1
|
+
## 4.2.0 (Oct 23, 2019)
|
2
|
+
|
3
|
+
* Add support for platform events, CDC, generic events, etc. in the Streaming API (@nathanKramer)
|
4
|
+
|
5
|
+
## 4.1.0 (Oct 20, 2019)
|
6
|
+
|
7
|
+
* Add support for JWT authentication (@nathanKramer, @tagCincy)
|
8
|
+
|
9
|
+
## 4.0.0 (Oct 9, 2019)
|
10
|
+
|
11
|
+
* __Deprecate support for Ruby 2.3__, since [Ruby 2.3 reached its end-of-life](https://www.ruby-lang.org/en/news/2019/03/31/support-of-ruby-2-3-has-ended/) in March 2019. (This is the only breaking change included in this version.)
|
12
|
+
|
13
|
+
## 3.2.0 (Oct 9, 2019)
|
14
|
+
|
15
|
+
* Add support for the Batch API (@gaiottino, @teoulas)
|
16
|
+
* Return specific exceptions for errors that might be returned from Salesforce.com - instead of getting a generic `Faraday::Error::ClientError`, you might get something like a `Restforce::EntityTooLargeError` (@boblail)
|
17
|
+
* Expose the full response in exceptions' messages to make debugging easier (@boblail)
|
18
|
+
* Properly escape IDs with spaces in them when working with existing records (@pushups)
|
19
|
+
|
20
|
+
## 3.1.0 (Aug 16, 2018)
|
21
|
+
|
22
|
+
* Add support for replaying missed messages when using the Salesforce Streaming API (@andreimaxim, @drteeth, @panozzaj)
|
23
|
+
|
1
24
|
## 3.0.1 (Aug 4, 2018)
|
2
25
|
|
3
26
|
* Fix `NoMethodError` when upserting an existing record (@opti)
|
4
27
|
|
5
28
|
## 3.0.0 (Aug 2, 2018)
|
6
29
|
|
7
|
-
* __Deprecate support for Ruby 2.0, 2.1 and 2.2__, since [even Ruby 2.2 reached its end-of-life]
|
30
|
+
* __Deprecate support for Ruby 2.0, 2.1 and 2.2__, since [even Ruby 2.2 reached its end-of-life](https://www.ruby-lang.org/en/news/2018/06/20/support-of-ruby-2-2-has-ended/) in June 2018. (This is the only breaking change included in this version.)
|
8
31
|
* Fix `NoMethodError` when trying to upsert a record using a `Fixnum` as the external ID (@AlexandruCD)
|
9
32
|
* Escape record IDs passed in to the client to identify records to find, delete, etc. (@jmdx)
|
10
33
|
* Stop relying on our middleware for Gzip compression if you're using `httpclient`, since Faraday enables this automatically using `httpclient`'s built-in support (@shivanshgaur)
|
11
34
|
* Fix `get_updated` and `get_deleted` API calls by removing the erroneous leading forward slash from the path (@scottolsen)
|
12
35
|
* Fix unpacking of dependent picklist options (@parkm)
|
13
36
|
|
37
|
+
## 2.5.4 (May 15, 2019)
|
38
|
+
|
39
|
+
See the [`v2`](https://github.com/restforce/restforce/tree/v2) branch for this release.
|
40
|
+
|
41
|
+
* Escape record IDs passed in to the client to identify records to find, delete, etc. (@jmdx, @apanzerj)
|
42
|
+
|
14
43
|
## 2.5.3 (Apr 25, 2017)
|
15
44
|
|
16
45
|
* Raise an error where a custom external ID field name is supplied to `upsert` and `upsert!`, but it is missing from the provided attributes (@velveret)
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -25,7 +25,7 @@ Features include:
|
|
25
25
|
|
26
26
|
Add this line to your application's Gemfile:
|
27
27
|
|
28
|
-
gem 'restforce', '~>
|
28
|
+
gem 'restforce', '~> 4.2.0'
|
29
29
|
|
30
30
|
And then execute:
|
31
31
|
|
@@ -35,7 +35,7 @@ Or install it yourself as:
|
|
35
35
|
|
36
36
|
$ gem install restforce
|
37
37
|
|
38
|
-
__As of [version
|
38
|
+
__As of [version 4.0.0](https://github.com/restforce/restforce/blob/master/CHANGELOG.md#400-oct-9-2019), this gem is only compatible with Ruby 2.4.0 and later.__ You'll need to use version 3.2.0 or earlier if you're running on Ruby 2.3. If you're running on Ruby 2.2, 2.1 or 2.0, use version 2.5.3 or earlier. For Ruby 1.9.3, you'll need to manually specify that you wish to use version 2.4.2.
|
39
39
|
|
40
40
|
This gem is versioned using [Semantic Versioning](http://semver.org/), so you can be confident when updating that there will not be breaking changes outside of a major version (following format MAJOR.MINOR.PATCH, so for instance moving from 3.1.0 to 4.0.0 would be allowed to include incompatible API changes). See the [changelog](https://github.com/restforce/restforce/tree/master/CHANGELOG.md) for details on what has changed in each version.
|
41
41
|
|
@@ -43,7 +43,7 @@ This gem is versioned using [Semantic Versioning](http://semver.org/), so you ca
|
|
43
43
|
|
44
44
|
Restforce is designed with flexibility and ease of use in mind. By default, all API calls will
|
45
45
|
return [Hashie::Mash](https://github.com/intridea/hashie/tree/v1.2.0) objects,
|
46
|
-
so you can do things like `client.query('select Id, (select Name from Children__r) from Account').Children__r.first.Name`.
|
46
|
+
so you can do things like `client.query('select Id, (select Name from Children__r) from Account').first.Children__r.first.Name`.
|
47
47
|
|
48
48
|
### Initialization
|
49
49
|
|
@@ -111,6 +111,21 @@ client = Restforce.new(username: 'foo',
|
|
111
111
|
api_version: '41.0')
|
112
112
|
```
|
113
113
|
|
114
|
+
#### JWT Bearer Token
|
115
|
+
|
116
|
+
If you prefer to use a [JWT Bearer Token](https://developer.salesforce.com/page/Digging_Deeper_into_OAuth_2.0_on_Force.com#Obtaining_an_Access_Token_using_a_JWT_Bearer_Token) to authenticate:
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
client = Restforce.new(username: 'foo',
|
120
|
+
client_id: 'client_id',
|
121
|
+
instance_url: 'instance_url',
|
122
|
+
jwt_key: 'certificate_private_key',
|
123
|
+
api_version: '38.0')
|
124
|
+
```
|
125
|
+
|
126
|
+
The `jwt_key` option is the private key of the certificate uploaded to your Connected App in Salesforce.
|
127
|
+
Choose "use digital signatures" in the Connected App configuration screen to upload your certificate.
|
128
|
+
|
114
129
|
You can also set the username, password, security token, client ID, client
|
115
130
|
secret and API version in environment variables:
|
116
131
|
|
@@ -473,11 +488,11 @@ document = client.query('select Id, Name, Body from Document').first
|
|
473
488
|
File.open(document.Name, 'wb') { |f| f.write(document.Body) }
|
474
489
|
```
|
475
490
|
|
476
|
-
**Note:** The example above is only applicable if your SOQL query returns a single Document record. If more than one record is returned,
|
491
|
+
**Note:** The example above is only applicable if your SOQL query returns a single Document record. If more than one record is returned,
|
477
492
|
the Body field contains an URL to retrieve the BLOB content for the first 2000 records returned. Subsequent records contain the BLOB content
|
478
|
-
in the Body field. This is confusing and hard to debug. See notes in [Issue #301](https://github.com/restforce/restforce/issues/301#issuecomment-298972959) explaining this detail.
|
479
|
-
**Executive Summary:** Don't retrieve the Body field in a SOQL query; instead, use the BLOB retrieval URL documented
|
480
|
-
in [SObject BLOB Retrieve](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_sobject_blob_retrieve.htm)
|
493
|
+
in the Body field. This is confusing and hard to debug. See notes in [Issue #301](https://github.com/restforce/restforce/issues/301#issuecomment-298972959) explaining this detail.
|
494
|
+
**Executive Summary:** Don't retrieve the Body field in a SOQL query; instead, use the BLOB retrieval URL documented
|
495
|
+
in [SObject BLOB Retrieve](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_sobject_blob_retrieve.htm)
|
481
496
|
|
482
497
|
* * *
|
483
498
|
|
@@ -513,8 +528,10 @@ client.get('/services/apexrest/FieldCase', company: 'GenePoint')
|
|
513
528
|
|
514
529
|
### Streaming
|
515
530
|
|
516
|
-
Restforce supports the [Streaming API](
|
517
|
-
pub/sub with Salesforce a trivial task
|
531
|
+
Restforce supports the [Streaming API](https://trailhead.salesforce.com/en/content/learn/modules/api_basics/api_basics_streaming), and makes implementing
|
532
|
+
pub/sub with Salesforce a trivial task.
|
533
|
+
|
534
|
+
Here is an example of creating and subscribing to a `PushTopic`:
|
518
535
|
|
519
536
|
```ruby
|
520
537
|
# Restforce uses faye as the underlying implementation for CometD.
|
@@ -523,7 +540,7 @@ require 'faye'
|
|
523
540
|
# Initialize a client with your username/password/oauth token/etc.
|
524
541
|
client = Restforce.new(username: 'foo',
|
525
542
|
password: 'bar',
|
526
|
-
security_token: 'security token'
|
543
|
+
security_token: 'security token',
|
527
544
|
client_id: 'client_id',
|
528
545
|
client_secret: 'client_secret')
|
529
546
|
|
@@ -538,7 +555,7 @@ client.create!('PushTopic',
|
|
538
555
|
|
539
556
|
EM.run do
|
540
557
|
# Subscribe to the PushTopic.
|
541
|
-
client.
|
558
|
+
client.subscription '/topic/AllAccounts' do |message|
|
542
559
|
puts message.inspect
|
543
560
|
end
|
544
561
|
end
|
@@ -547,7 +564,102 @@ end
|
|
547
564
|
Boom, you're now receiving push notifications when Accounts are
|
548
565
|
created/updated.
|
549
566
|
|
550
|
-
|
567
|
+
#### Replaying Events
|
568
|
+
|
569
|
+
Since API version 37.0, Salesforce stores events for 24 hours and they can be
|
570
|
+
replayed if your application experienced some downtime.
|
571
|
+
|
572
|
+
In order to replay past events, all you need to do is specify the last known
|
573
|
+
event ID when subscribing and you will receive all events that happened since
|
574
|
+
that event ID:
|
575
|
+
|
576
|
+
```ruby
|
577
|
+
EM.run {
|
578
|
+
# Subscribe to the PushTopic.
|
579
|
+
client.subscription '/topic/AllAccounts', replay: 10 do |message|
|
580
|
+
puts message.inspect
|
581
|
+
end
|
582
|
+
}
|
583
|
+
```
|
584
|
+
|
585
|
+
In this specific case you will see events with replay ID 11, 12 and so on.
|
586
|
+
|
587
|
+
There are two magic values for the replay ID accepted by Salesforce:
|
588
|
+
|
589
|
+
* `-2`, for getting all the events that appeared in the last 24 hours
|
590
|
+
* `-1`, for getting only newer events
|
591
|
+
|
592
|
+
**Warning**: Only use a replay ID of a event from the last 24 hours otherwise
|
593
|
+
Salesforce will not send anything, including newer events. If in doubt, use one
|
594
|
+
of the two magic replay IDs mentioned above.
|
595
|
+
|
596
|
+
You might want to store the replay ID in some sort of datastore so you can
|
597
|
+
access it, for example between application restarts. In that case, there is the
|
598
|
+
option of passing a custom replay handler which responds to `[]` and `[]=`.
|
599
|
+
|
600
|
+
Below is a sample replay handler that stores the replay ID for each channel in
|
601
|
+
memory using a Hash, stores a timestamp and has some rudimentary logic that
|
602
|
+
will use one of the magic IDs depending on the value of the timestamp:
|
603
|
+
|
604
|
+
```ruby
|
605
|
+
class SimpleReplayHandler
|
606
|
+
|
607
|
+
MAX_AGE = 86_400 # 24 hours
|
608
|
+
|
609
|
+
INIT_REPLAY_ID = -1
|
610
|
+
DEFAULT_REPLAY_ID = -2
|
611
|
+
|
612
|
+
def initialize
|
613
|
+
@channels = {}
|
614
|
+
@last_modified = nil
|
615
|
+
end
|
616
|
+
|
617
|
+
# This method is called during the initial subscribe phase
|
618
|
+
# in order to send the correct replay ID.
|
619
|
+
def [](channel)
|
620
|
+
if @last_modified.nil?
|
621
|
+
puts "[#{channel}] No timestamp defined, sending magic replay ID #{INIT_REPLAY_ID}"
|
622
|
+
|
623
|
+
INIT_REPLAY_ID
|
624
|
+
elsif old_replay_id?
|
625
|
+
puts "[#{channel}] Old timestamp, sending magic replay ID #{DEFAULT_REPLAY_ID}"
|
626
|
+
|
627
|
+
DEFAULT_REPLAY_ID
|
628
|
+
else
|
629
|
+
@channels[channel]
|
630
|
+
end
|
631
|
+
end
|
632
|
+
|
633
|
+
def []=(channel, replay_id)
|
634
|
+
puts "[#{channel}] Writing replay ID: #{replay_id}"
|
635
|
+
|
636
|
+
@last_modified = Time.now
|
637
|
+
@channels[channel] = replay_id
|
638
|
+
end
|
639
|
+
|
640
|
+
def old_replay_id?
|
641
|
+
@last_modified.is_a?(Time) && Time.now - @last_modified > MAX_AGE
|
642
|
+
end
|
643
|
+
end
|
644
|
+
```
|
645
|
+
|
646
|
+
In order to use it, simply pass the object as the value of the `replay` option
|
647
|
+
of the subscription:
|
648
|
+
|
649
|
+
```ruby
|
650
|
+
EM.run {
|
651
|
+
# Subscribe to the PushTopic and use the custom replay handler to store any
|
652
|
+
# received replay ID.
|
653
|
+
client.subscription '/topic/AllAccounts', replay: SimpleReplayHandler.new do |message|
|
654
|
+
puts message.inspect
|
655
|
+
end
|
656
|
+
}
|
657
|
+
```
|
658
|
+
|
659
|
+
_See also_:
|
660
|
+
|
661
|
+
* [Force.com Streaming API docs](http://www.salesforce.com/us/developer/docs/api_streaming/index.htm)
|
662
|
+
* [Message Durability docs](https://developer.salesforce.com/docs/atlas.en-us.api_streaming.meta/api_streaming/using_streaming_api_durability.htm)
|
551
663
|
|
552
664
|
*Note:* Restforce's streaming implementation is known to be compatible with version `0.8.9` of the faye gem.
|
553
665
|
|