saddle 0.0.53 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -13
- data/.github/workflows/ci.yml +55 -0
- data/.gitignore +1 -0
- data/Appraisals +39 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +2 -2
- data/README.md +48 -10
- data/bin/template/lib/saddle-client/middleware/exception_raiser.rb +1 -1
- data/gemfiles/activesupport_3.2.gemfile +20 -0
- data/gemfiles/activesupport_4.0.gemfile +20 -0
- data/gemfiles/activesupport_4.1.gemfile +20 -0
- data/gemfiles/activesupport_4.2.gemfile +20 -0
- data/gemfiles/activesupport_5.0.gemfile +20 -0
- data/gemfiles/activesupport_5.1.gemfile +20 -0
- data/gemfiles/activesupport_5.2.gemfile +20 -0
- data/gemfiles/activesupport_6.0.gemfile +20 -0
- data/gemfiles/activesupport_6.1.gemfile +20 -0
- data/gemfiles/activesupport_7.0.gemfile +20 -0
- data/lib/saddle/endpoint.rb +6 -9
- data/lib/saddle/faraday/rack_builder.rb +15 -0
- data/lib/saddle/faraday/request.rb +4 -0
- data/lib/saddle/middleware/authentication/oauth1.rb +6 -6
- data/lib/saddle/middleware/authentication/oauth2.rb +2 -2
- data/lib/saddle/middleware/extra_env.rb +2 -2
- data/lib/saddle/middleware/logging/rails.rb +1 -1
- data/lib/saddle/middleware/logging/statsd.rb +7 -7
- data/lib/saddle/middleware/request/encode_json.rb +1 -7
- data/lib/saddle/middleware/request/path_prefix.rb +2 -2
- data/lib/saddle/middleware/request/retry.rb +8 -4
- data/lib/saddle/middleware/request/url_encoded.rb +1 -1
- data/lib/saddle/middleware/request/user_agent.rb +1 -1
- data/lib/saddle/middleware/response/default_response.rb +1 -1
- data/lib/saddle/middleware/response/parse_json.rb +0 -6
- data/lib/saddle/middleware/response/raise_error.rb +2 -2
- data/lib/saddle/middleware/ruby_timeout.rb +2 -2
- data/lib/saddle/requester.rb +27 -28
- data/lib/saddle/version.rb +1 -1
- data/saddle.gemspec +6 -8
- data/spec/endpoint/base_endpoint_spec.rb +2 -2
- data/spec/middleware/instrumentation_spec.rb +1 -1
- data/spec/middleware/request/retry_spec.rb +1 -1
- data/spec/requester/get_spec.rb +1 -1
- metadata +37 -24
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
NGI3MWM5MDgzZWIyYjVkM2RhYzk1YmRjMGY5YjU3MmE2N2MxNGYyMQ==
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c6cbc5f3bed08d163ba1f6bb948acb555c16b9034ff6adac036a0f1f4252f872
|
4
|
+
data.tar.gz: 6b509a1bdb969e7b54c3c6fd93d742ef3cfd7144de2e8c36014f8a5fdc32484a
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
YmI4ZjBkMzhiOWJhMmFlYjg1MGE1YTJjZDg4MmY5Mjc0N2RmNDBkZjFjZmMy
|
11
|
-
ZjYxZWVjYzZiZjI1MzMwYWJmMjdiYWY3NDJmODNmMDk5ZGY0M2I=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
M2Q3NWU4ODRkZGRkOWI5MDY2NmFkZWY3NDViNmZmYjE2NWJlMjEyYTBhY2Qx
|
14
|
-
ZGY3M2VmYzIwMmFkMjc2M2VlZTRhNTQwZjU1Yjg1MGRlNzMyMTQ0Mzg0NDRj
|
15
|
-
NGViYjZjY2EwMWIwN2VkYzgzNGU0MGI2NjJiODVkNGY5M2ZjZDU=
|
6
|
+
metadata.gz: c22f775da62289da5111c42fc64373aec52b3c831b828a0b40f9fda5d354d569da0481e8d789422965cd802ea23855816c4d53224ec3507a5a8dd977f7209c0c
|
7
|
+
data.tar.gz: 392ebba3e48907a68867ba54125fdccbc26df04659fd84db2aa053823af414da24093eca48bf3b460efaf43bfcbc1792c813b25e04c6a521b221f815ef89503d
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
2
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
3
|
+
|
4
|
+
name: Ruby
|
5
|
+
|
6
|
+
on: [pull_request, push]
|
7
|
+
|
8
|
+
permissions:
|
9
|
+
contents: read
|
10
|
+
|
11
|
+
jobs:
|
12
|
+
test:
|
13
|
+
runs-on: ubuntu-latest
|
14
|
+
strategy:
|
15
|
+
matrix:
|
16
|
+
ruby-version: [2.6, 2.7, '3.0', 3.1]
|
17
|
+
gemfile:
|
18
|
+
- activesupport_3.2
|
19
|
+
- activesupport_4.0
|
20
|
+
- activesupport_4.1
|
21
|
+
- activesupport_4.2
|
22
|
+
- activesupport_5.0
|
23
|
+
- activesupport_5.1
|
24
|
+
- activesupport_5.2
|
25
|
+
- activesupport_6.0
|
26
|
+
- activesupport_6.1
|
27
|
+
- activesupport_7.0
|
28
|
+
exclude:
|
29
|
+
- ruby-version: 2.6
|
30
|
+
gemfile: activesupport_7.0
|
31
|
+
- ruby-version: '3.0'
|
32
|
+
gemfile: activesupport_4.1
|
33
|
+
- ruby-version: 3.1
|
34
|
+
gemfile: activesupport_4.1
|
35
|
+
steps:
|
36
|
+
- uses: actions/checkout@v3
|
37
|
+
|
38
|
+
- name: Set up Ruby
|
39
|
+
uses: ruby/setup-ruby@v1
|
40
|
+
with:
|
41
|
+
ruby-version: ${{ matrix.ruby-version }}
|
42
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
43
|
+
|
44
|
+
- name: Generate Appraisal gemfiles
|
45
|
+
run: bundle exec appraisal generate
|
46
|
+
|
47
|
+
- name: Install dependencies
|
48
|
+
env:
|
49
|
+
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
|
50
|
+
run: bundle install
|
51
|
+
|
52
|
+
- name: Run rspec
|
53
|
+
env:
|
54
|
+
BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
|
55
|
+
run: bundle exec rspec
|
data/.gitignore
CHANGED
data/Appraisals
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
appraise "activesupport_3.2" do
|
2
|
+
gem "activesupport", "~> 3.2.22"
|
3
|
+
end
|
4
|
+
|
5
|
+
appraise "activesupport_4.0" do
|
6
|
+
gem "activesupport", "~> 4.0.13"
|
7
|
+
end
|
8
|
+
|
9
|
+
appraise "activesupport_4.1" do
|
10
|
+
gem "activesupport", "~> 4.1.16"
|
11
|
+
end
|
12
|
+
|
13
|
+
appraise "activesupport_4.2" do
|
14
|
+
gem "activesupport", "~> 4.2.11"
|
15
|
+
end
|
16
|
+
|
17
|
+
appraise "activesupport_5.0" do
|
18
|
+
gem "activesupport", "~> 5.0.7"
|
19
|
+
end
|
20
|
+
|
21
|
+
appraise "activesupport_5.1" do
|
22
|
+
gem "activesupport", "~> 5.1.7"
|
23
|
+
end
|
24
|
+
|
25
|
+
appraise "activesupport_5.2" do
|
26
|
+
gem "activesupport", "~> 5.2.8"
|
27
|
+
end
|
28
|
+
|
29
|
+
appraise "activesupport_6.0" do
|
30
|
+
gem "activesupport", "~> 6.0.6"
|
31
|
+
end
|
32
|
+
|
33
|
+
appraise "activesupport_6.1" do
|
34
|
+
gem "activesupport", "~> 6.1.7"
|
35
|
+
end
|
36
|
+
|
37
|
+
appraise "activesupport_7.0" do
|
38
|
+
gem "activesupport", "~> 7.0.4"
|
39
|
+
end
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -41,16 +41,16 @@ Saddle enables you to create beautifully stable and functionaly API clients, in
|
|
41
41
|
[saddle-example](https://github.com/mLewisLogic/saddle-example)
|
42
42
|
|
43
43
|
### client construction
|
44
|
-
0. For the sake of cleanliness, pick a namespace that everything related to your client should live in. For this example, we'll use __SaddleExample__
|
45
|
-
1. Inherit your client class, __SaddleExample::Client__, from __Saddle::Client__
|
46
|
-
2. Create an _endpoints_ directory at the same level as your client class file
|
47
|
-
3. Create endpoint classes in the _endpoints_ directory that inherit from __Saddle::TraversalEndpoint__ and are under the __SaddleExample::Endpoints__ namespace module
|
48
|
-
1. Give these endpoints methods that call
|
49
|
-
2. Their module/class namespace determines how they are accessed in the client's call tree. For example, the
|
44
|
+
0. For the sake of cleanliness, pick a namespace that everything related to your client should live in. For this example, we'll use __SaddleExample__.
|
45
|
+
1. Inherit your client class, __SaddleExample::Client__, from __Saddle::Client__.
|
46
|
+
2. Create an _endpoints_ directory at the same level as your client class file.
|
47
|
+
3. Create endpoint classes in the _endpoints_ directory that inherit from __Saddle::TraversalEndpoint__ and are under the __SaddleExample::Endpoints__ namespace module.
|
48
|
+
1. Give these endpoints methods that call `get` or `post` to perform the actual request
|
49
|
+
2. Their module/class namespace determines how they are accessed in the client's call tree. For example, the `get_all` in __SaddleExample::Endpoints::Fish::Guppy__ would be accessed by:
|
50
50
|
|
51
|
-
|
51
|
+
client.fish.guppy.get_all
|
52
52
|
|
53
|
-
3. If you need REST style endpoints like client.
|
53
|
+
3. If you need REST style endpoints like `client.kitten.by_id('Whiskers').info` then check out __Saddle::ResourceEndpoint__ and how it's used in [saddle-example](https://github.com/mLewisLogic/saddle-example/blob/master/lib/saddle-example/endpoints/kitten.rb)
|
54
54
|
|
55
55
|
4. Initialize an instance of your client. ex:
|
56
56
|
|
@@ -62,11 +62,49 @@ Saddle enables you to create beautifully stable and functionaly API clients, in
|
|
62
62
|
* xml posting/parsing
|
63
63
|
|
64
64
|
|
65
|
+
## version notes
|
66
|
+
|
67
|
+
* Saddle versions 0.2.x supports Ruby 3.x, drops support for 2.6
|
68
|
+
* Saddle versions 0.1.x are compatible with Faraday versions ~> 0.9.0
|
69
|
+
* Saddle versions 0.0.x are compatible with Faraday versions ~> 0.8.7
|
70
|
+
|
71
|
+
## Appraisal Usage
|
72
|
+
|
73
|
+
Appraisal is a gem that allows us to test our library against different versions of dependencies in repeatable scenarios called "appraisals". For more information see
|
74
|
+
the [Appraisal repository](https://github.com/thoughtbot/appraisal)
|
75
|
+
|
76
|
+
First make sure appraisal is installed by running
|
77
|
+
|
78
|
+
```
|
79
|
+
$ bundle install
|
80
|
+
```
|
81
|
+
|
82
|
+
To update the Appraisal's gemfiles run
|
83
|
+
|
84
|
+
```
|
85
|
+
$ bundle exec appraisal generate
|
86
|
+
```
|
87
|
+
|
88
|
+
To test against a specific version of `activesupport` first install the dependencies, ideally we would want to install them by running
|
89
|
+
```
|
90
|
+
$ bundle exec appraisal install
|
91
|
+
```
|
92
|
+
|
93
|
+
However, this isn't posible fot the different constraints these versions have. So instead install the dependencies for the desired version we want to test against by running
|
94
|
+
|
95
|
+
```
|
96
|
+
$ BUNDLE_GEMFILE=gemfiles/activesupport_6.0.gemfiles bundle install
|
97
|
+
```
|
98
|
+
|
99
|
+
In this example we want to install the dependencies of `activesupport` version `6.0`. Then to run `rspec` with that constraints we run
|
100
|
+
|
101
|
+
```
|
102
|
+
$ BUNDLE_GEMFILE=gemfiles/activesupport_6.0.gemfiles bundle exec rspec
|
103
|
+
```
|
104
|
+
|
65
105
|
## Code Status
|
66
106
|
|
67
|
-
* [](https://travis-ci.org/mLewisLogic/saddle)
|
68
107
|
* [](https://codeclimate.com/github/mLewisLogic/saddle)
|
69
|
-
* [](https://gemnasium.com/mLewisLogic/saddle)
|
70
108
|
|
71
109
|
|
72
110
|
## License
|
@@ -19,7 +19,7 @@ module <%= root_module %>
|
|
19
19
|
def call(env)
|
20
20
|
begin
|
21
21
|
@app.call(env)
|
22
|
-
rescue Faraday::
|
22
|
+
rescue Faraday::ClientError => e
|
23
23
|
# This is our chance to reinterpret the response into a meaningful, client-specific
|
24
24
|
# exception that a consuming service can handle
|
25
25
|
exception = <%= root_module %>::GenericException
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "activesupport", "~> 3.2.22"
|
6
|
+
|
7
|
+
group :test do
|
8
|
+
gem "rake"
|
9
|
+
gem "rspec", "~> 3.12"
|
10
|
+
gem "rspec-instafail", "~> 1"
|
11
|
+
gem "airbrake"
|
12
|
+
gem "simple_oauth", "~> 0.2.0"
|
13
|
+
gem "statsd-ruby", require: ["statsd"]
|
14
|
+
end
|
15
|
+
|
16
|
+
group :development, :test do
|
17
|
+
gem "pry"
|
18
|
+
end
|
19
|
+
|
20
|
+
gemspec path: "../"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "activesupport", "~> 4.0.13"
|
6
|
+
|
7
|
+
group :test do
|
8
|
+
gem "rake"
|
9
|
+
gem "rspec", "~> 3.12"
|
10
|
+
gem "rspec-instafail", "~> 1"
|
11
|
+
gem "airbrake"
|
12
|
+
gem "simple_oauth", "~> 0.2.0"
|
13
|
+
gem "statsd-ruby", require: ["statsd"]
|
14
|
+
end
|
15
|
+
|
16
|
+
group :development, :test do
|
17
|
+
gem "pry"
|
18
|
+
end
|
19
|
+
|
20
|
+
gemspec path: "../"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "activesupport", "~> 4.1.16"
|
6
|
+
|
7
|
+
group :test do
|
8
|
+
gem "rake"
|
9
|
+
gem "rspec", "~> 3.12"
|
10
|
+
gem "rspec-instafail", "~> 1"
|
11
|
+
gem "airbrake"
|
12
|
+
gem "simple_oauth", "~> 0.2.0"
|
13
|
+
gem "statsd-ruby", require: ["statsd"]
|
14
|
+
end
|
15
|
+
|
16
|
+
group :development, :test do
|
17
|
+
gem "pry"
|
18
|
+
end
|
19
|
+
|
20
|
+
gemspec path: "../"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "activesupport", "~> 4.2.11"
|
6
|
+
|
7
|
+
group :test do
|
8
|
+
gem "rake"
|
9
|
+
gem "rspec", "~> 3.12"
|
10
|
+
gem "rspec-instafail", "~> 1"
|
11
|
+
gem "airbrake"
|
12
|
+
gem "simple_oauth", "~> 0.2.0"
|
13
|
+
gem "statsd-ruby", require: ["statsd"]
|
14
|
+
end
|
15
|
+
|
16
|
+
group :development, :test do
|
17
|
+
gem "pry"
|
18
|
+
end
|
19
|
+
|
20
|
+
gemspec path: "../"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "activesupport", "~> 5.0.7"
|
6
|
+
|
7
|
+
group :test do
|
8
|
+
gem "rake"
|
9
|
+
gem "rspec", "~> 3.12"
|
10
|
+
gem "rspec-instafail", "~> 1"
|
11
|
+
gem "airbrake"
|
12
|
+
gem "simple_oauth", "~> 0.2.0"
|
13
|
+
gem "statsd-ruby", require: ["statsd"]
|
14
|
+
end
|
15
|
+
|
16
|
+
group :development, :test do
|
17
|
+
gem "pry"
|
18
|
+
end
|
19
|
+
|
20
|
+
gemspec path: "../"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "activesupport", "~> 5.1.7"
|
6
|
+
|
7
|
+
group :test do
|
8
|
+
gem "rake"
|
9
|
+
gem "rspec", "~> 3.12"
|
10
|
+
gem "rspec-instafail", "~> 1"
|
11
|
+
gem "airbrake"
|
12
|
+
gem "simple_oauth", "~> 0.2.0"
|
13
|
+
gem "statsd-ruby", require: ["statsd"]
|
14
|
+
end
|
15
|
+
|
16
|
+
group :development, :test do
|
17
|
+
gem "pry"
|
18
|
+
end
|
19
|
+
|
20
|
+
gemspec path: "../"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "activesupport", "~> 5.2.8"
|
6
|
+
|
7
|
+
group :test do
|
8
|
+
gem "rake"
|
9
|
+
gem "rspec", "~> 3.12"
|
10
|
+
gem "rspec-instafail", "~> 1"
|
11
|
+
gem "airbrake"
|
12
|
+
gem "simple_oauth", "~> 0.2.0"
|
13
|
+
gem "statsd-ruby", require: ["statsd"]
|
14
|
+
end
|
15
|
+
|
16
|
+
group :development, :test do
|
17
|
+
gem "pry"
|
18
|
+
end
|
19
|
+
|
20
|
+
gemspec path: "../"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "activesupport", "~> 6.0.6"
|
6
|
+
|
7
|
+
group :test do
|
8
|
+
gem "rake"
|
9
|
+
gem "rspec", "~> 3.12"
|
10
|
+
gem "rspec-instafail", "~> 1"
|
11
|
+
gem "airbrake"
|
12
|
+
gem "simple_oauth", "~> 0.2.0"
|
13
|
+
gem "statsd-ruby", require: ["statsd"]
|
14
|
+
end
|
15
|
+
|
16
|
+
group :development, :test do
|
17
|
+
gem "pry"
|
18
|
+
end
|
19
|
+
|
20
|
+
gemspec path: "../"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "activesupport", "~> 6.1.7"
|
6
|
+
|
7
|
+
group :test do
|
8
|
+
gem "rake"
|
9
|
+
gem "rspec", "~> 3.12"
|
10
|
+
gem "rspec-instafail", "~> 1"
|
11
|
+
gem "airbrake"
|
12
|
+
gem "simple_oauth", "~> 0.2.0"
|
13
|
+
gem "statsd-ruby", require: ["statsd"]
|
14
|
+
end
|
15
|
+
|
16
|
+
group :development, :test do
|
17
|
+
gem "pry"
|
18
|
+
end
|
19
|
+
|
20
|
+
gemspec path: "../"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "activesupport", "~> 7.0.4"
|
6
|
+
|
7
|
+
group :test do
|
8
|
+
gem "rake"
|
9
|
+
gem "rspec", "~> 2.14.1"
|
10
|
+
gem "rspec-instafail", "~> 0.2"
|
11
|
+
gem "airbrake"
|
12
|
+
gem "simple_oauth", "~> 0.2.0"
|
13
|
+
gem "statsd-ruby", require: ["statsd"]
|
14
|
+
end
|
15
|
+
|
16
|
+
group :development, :test do
|
17
|
+
gem "pry"
|
18
|
+
end
|
19
|
+
|
20
|
+
gemspec path: "../"
|
data/lib/saddle/endpoint.rb
CHANGED
@@ -17,18 +17,15 @@ module Saddle
|
|
17
17
|
def initialize(requester, relative_path_override=nil, parent=nil)
|
18
18
|
@requester = requester
|
19
19
|
@parent = parent
|
20
|
-
@relative_path = relative_path_override || _relative_path
|
20
|
+
@relative_path = relative_path_override || _relative_path
|
21
21
|
end
|
22
22
|
|
23
23
|
|
24
24
|
# Generic request wrapper
|
25
25
|
def request(method, action, params={}, options={})
|
26
26
|
# Augment in interesting options
|
27
|
-
options[:
|
28
|
-
options[:
|
29
|
-
:call_chain => _path_array(),
|
30
|
-
:action => action,
|
31
|
-
}
|
27
|
+
options[:call_chain] = _path_array
|
28
|
+
options[:action] = action
|
32
29
|
@requester.send(method, _path(action), params, options)
|
33
30
|
end
|
34
31
|
|
@@ -87,7 +84,7 @@ module Saddle
|
|
87
84
|
if defined?(self.class::ABSOLUTE_PATH)
|
88
85
|
[self.class::ABSOLUTE_PATH]
|
89
86
|
else
|
90
|
-
_path_array
|
87
|
+
_path_array
|
91
88
|
end
|
92
89
|
# Join it with the action
|
93
90
|
paths = pre_action_paths + [action]
|
@@ -97,7 +94,7 @@ module Saddle
|
|
97
94
|
end
|
98
95
|
|
99
96
|
def _path_array
|
100
|
-
_endpoint_chain
|
97
|
+
_endpoint_chain.map(&:relative_path).compact
|
101
98
|
end
|
102
99
|
|
103
100
|
# Get the parent chain that led to this endpoint
|
@@ -108,7 +105,7 @@ module Saddle
|
|
108
105
|
chain << node
|
109
106
|
node = node.parent
|
110
107
|
end
|
111
|
-
chain.reverse
|
108
|
+
chain.reverse
|
112
109
|
end
|
113
110
|
|
114
111
|
# If the parent is not an endpoint, it is a root node
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Saddle
|
2
|
+
# Same as the standard Faraday::RackBuilder, but also allows passing saddle options to the env.
|
3
|
+
class RackBuilder < ::Faraday::RackBuilder
|
4
|
+
def saddle_options
|
5
|
+
@saddle_options ||= {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def build_env(connection, request)
|
9
|
+
env = super
|
10
|
+
env[:saddle] = saddle_options.deep_merge(request.saddle_options)
|
11
|
+
env
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -14,17 +14,17 @@ module Saddle
|
|
14
14
|
TYPE_URLENCODED = 'application/x-www-form-urlencoded'.freeze
|
15
15
|
|
16
16
|
def call(env)
|
17
|
-
if env[:
|
18
|
-
env[:
|
19
|
-
env[:
|
20
|
-
env[:
|
21
|
-
env[:
|
17
|
+
if env[:saddle][:client_options][:oauth1] &&
|
18
|
+
env[:saddle][:client_options][:oauth1][:consumer_key] &&
|
19
|
+
env[:saddle][:client_options][:oauth1][:consumer_secret] &&
|
20
|
+
env[:saddle][:client_options][:oauth1][:token] &&
|
21
|
+
env[:saddle][:client_options][:oauth1][:token_secret]
|
22
22
|
|
23
23
|
env[:request_headers]['Authorization'] ||= SimpleOAuth::Header.new(
|
24
24
|
env[:method],
|
25
25
|
env[:url].to_s,
|
26
26
|
filtered_body_params(env),
|
27
|
-
env[:
|
27
|
+
env[:saddle][:client_options][:oauth1]
|
28
28
|
).to_s
|
29
29
|
end
|
30
30
|
|
@@ -16,10 +16,10 @@ module Saddle
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def call(env)
|
19
|
-
if env[:
|
19
|
+
if env[:saddle][:client_options][@key_name.to_sym]
|
20
20
|
new_query = []
|
21
21
|
new_query << env[:url].query if env[:url].query
|
22
|
-
new_query << "#{@key_name}=#{CGI.escape(env[:
|
22
|
+
new_query << "#{@key_name}=#{CGI.escape(env[:saddle][:client_options][@key_name.to_sym].to_s)}"
|
23
23
|
env[:url].query = new_query.join('&')
|
24
24
|
end
|
25
25
|
|
@@ -9,8 +9,8 @@ module Saddle
|
|
9
9
|
|
10
10
|
class ExtraEnv < Faraday::Middleware
|
11
11
|
def call(env)
|
12
|
-
if env[:
|
13
|
-
env.merge!(env[:
|
12
|
+
if env[:saddle][:client_options][:extra_env]
|
13
|
+
env.merge!(env[:saddle][:client_options][:extra_env])
|
14
14
|
end
|
15
15
|
|
16
16
|
@app.call env
|
@@ -33,16 +33,16 @@ module Saddle
|
|
33
33
|
|
34
34
|
def call(env)
|
35
35
|
# Try to build up a path for the STATSD logging
|
36
|
-
if env[:
|
37
|
-
statsd_path = env[:
|
38
|
-
elsif env[:
|
36
|
+
if env[:saddle][:statsd_path]
|
37
|
+
statsd_path = env[:saddle][:statsd_path]
|
38
|
+
elsif env[:saddle][:client]
|
39
39
|
statsd_path_components = [
|
40
40
|
'saddle',
|
41
|
-
env[:
|
41
|
+
env[:saddle][:client].name.underscore,
|
42
42
|
]
|
43
|
-
if env[:
|
44
|
-
statsd_path_components += env[:
|
45
|
-
statsd_path_components << env[:
|
43
|
+
if env[:saddle][:call_chain] && env[:saddle][:action]
|
44
|
+
statsd_path_components += env[:saddle][:call_chain]
|
45
|
+
statsd_path_components << env[:saddle][:action]
|
46
46
|
else
|
47
47
|
statsd_path_components << 'raw'
|
48
48
|
statsd_path_components << "#{env[:url].host}#{env[:url].path}"
|
@@ -1,7 +1,5 @@
|
|
1
1
|
require 'faraday'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
3
|
module Saddle
|
6
4
|
module Middleware
|
7
5
|
module Request
|
@@ -15,12 +13,8 @@ module Saddle
|
|
15
13
|
CONTENT_TYPE = 'Content-Type'.freeze
|
16
14
|
MIME_TYPE = 'application/json'.freeze
|
17
15
|
|
18
|
-
dependency do
|
19
|
-
require 'json' unless defined?(::JSON)
|
20
|
-
end
|
21
|
-
|
22
16
|
def call(env)
|
23
|
-
if env[:
|
17
|
+
if env[:saddle][:request_style] == :json
|
24
18
|
# Make sure we're working with a valid body that's not a String
|
25
19
|
if env[:body] and !env[:body].respond_to?(:to_str)
|
26
20
|
env[:request_headers][CONTENT_TYPE] ||= MIME_TYPE
|
@@ -10,8 +10,8 @@ module Saddle
|
|
10
10
|
|
11
11
|
class PathPrefix < Faraday::Middleware
|
12
12
|
def call(env)
|
13
|
-
if env[:
|
14
|
-
env[:url].path = "/#{env[:
|
13
|
+
if env[:saddle][:client_options][:path_prefix]
|
14
|
+
env[:url].path = "/#{env[:saddle][:client_options][:path_prefix]}#{env[:url].path}"
|
15
15
|
end
|
16
16
|
|
17
17
|
@app.call env
|
@@ -17,13 +17,13 @@ module Saddle
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def call(env)
|
20
|
-
retries = env[:
|
21
|
-
backoff = env[:
|
20
|
+
retries = env[:saddle][:num_retries] || 0
|
21
|
+
backoff = env[:saddle][:retry_backoff] || 0.050 # in seconds
|
22
22
|
begin
|
23
23
|
@app.call(self.class.deep_copy(env))
|
24
24
|
rescue => e
|
25
25
|
# Only retry for GET or if the request is marked as idempotent
|
26
|
-
if env[:method] == :get || env[:
|
26
|
+
if env[:method] == :get || env[:saddle][:idempotent]
|
27
27
|
unless @ignored_exceptions.include?(e.class)
|
28
28
|
# Retry a limited number of times
|
29
29
|
if retries > 0
|
@@ -40,7 +40,11 @@ module Saddle
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def self.deep_copy(value)
|
43
|
-
if value.is_a?(
|
43
|
+
if value.is_a?(Struct)
|
44
|
+
result = value.clone
|
45
|
+
value.each{|k, v| result.send("#{k}=", deep_copy(v))}
|
46
|
+
result
|
47
|
+
elsif value.is_a?(Hash)
|
44
48
|
result = value.clone
|
45
49
|
value.each{|k, v| result[k] = deep_copy(v)}
|
46
50
|
result
|
@@ -24,7 +24,7 @@ module Saddle
|
|
24
24
|
|
25
25
|
|
26
26
|
def call(env)
|
27
|
-
if env[:
|
27
|
+
if env[:saddle][:request_style] == :urlencoded
|
28
28
|
# Make sure we're working with a valid body that's not a String
|
29
29
|
if env[:body] and !env[:body].respond_to?(:to_str)
|
30
30
|
if has_multipart?(env[:body])
|
@@ -13,7 +13,7 @@ module Saddle
|
|
13
13
|
user_agent = nil
|
14
14
|
# Build a user agent that looks like 'SaddleExample 0.0.1'
|
15
15
|
begin
|
16
|
-
user_agent = client_name = env[:
|
16
|
+
user_agent = client_name = env[:saddle][:client].name
|
17
17
|
parent_module = client_name.split('::')[0..-2].join('::').constantize
|
18
18
|
if parent_module
|
19
19
|
if defined?(parent_module::VERSION)
|
@@ -1,7 +1,5 @@
|
|
1
1
|
require 'faraday'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
3
|
module Saddle
|
6
4
|
module Middleware
|
7
5
|
module Response
|
@@ -12,10 +10,6 @@ module Saddle
|
|
12
10
|
CONTENT_TYPE = 'Content-Type'.freeze
|
13
11
|
MIME_TYPE = 'application/json'.freeze
|
14
12
|
|
15
|
-
dependency do
|
16
|
-
require 'json' unless defined?(::JSON)
|
17
|
-
end
|
18
|
-
|
19
13
|
def call(env)
|
20
14
|
result = @app.call(env)
|
21
15
|
|
@@ -11,9 +11,9 @@ module Saddle
|
|
11
11
|
|
12
12
|
case result.status
|
13
13
|
when 404
|
14
|
-
raise Faraday::
|
14
|
+
raise Faraday::ResourceNotFound, response_values(result)
|
15
15
|
when 400...600
|
16
|
-
raise Faraday::
|
16
|
+
raise Faraday::ClientError, response_values(result)
|
17
17
|
end
|
18
18
|
|
19
19
|
result
|
@@ -13,13 +13,13 @@ module Saddle
|
|
13
13
|
class RubyTimeout < Faraday::Middleware
|
14
14
|
|
15
15
|
def call(env)
|
16
|
-
timeout = env[:
|
16
|
+
timeout = env[:saddle][:hard_timeout] # nil or 0 means no timeout
|
17
17
|
Timeout.timeout(timeout, Saddle::TimeoutError) do
|
18
18
|
@app.call(env)
|
19
19
|
end
|
20
20
|
# It is possible that faraday will catch the timeout first and throw
|
21
21
|
# this exception, rethrow as a class derived from standard error.
|
22
|
-
rescue Faraday::
|
22
|
+
rescue Faraday::TimeoutError
|
23
23
|
raise Saddle::TimeoutError
|
24
24
|
end
|
25
25
|
|
data/lib/saddle/requester.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'active_support/core_ext/hash'
|
2
|
+
require 'active_support/notifications'
|
2
3
|
|
3
4
|
require 'faraday'
|
4
|
-
require '
|
5
|
-
|
5
|
+
require 'saddle/faraday/request'
|
6
|
+
require 'saddle/faraday/rack_builder'
|
6
7
|
|
7
8
|
require 'saddle/middleware/request/encode_json'
|
8
9
|
require 'saddle/middleware/request/path_prefix'
|
@@ -79,7 +80,7 @@ module Saddle
|
|
79
80
|
# Make a GET request
|
80
81
|
def get(url, params={}, options={})
|
81
82
|
response = connection.get do |req|
|
82
|
-
req.options
|
83
|
+
req.saddle_options = options
|
83
84
|
req.body = options[:body] if options.has_key?(:body)
|
84
85
|
req.url(url, params)
|
85
86
|
end
|
@@ -89,7 +90,7 @@ module Saddle
|
|
89
90
|
# Make a POST request
|
90
91
|
def post(url, data={}, options={})
|
91
92
|
response = connection.post do |req|
|
92
|
-
req.options
|
93
|
+
req.saddle_options = options
|
93
94
|
req.url(url)
|
94
95
|
req.body = data
|
95
96
|
end
|
@@ -99,7 +100,7 @@ module Saddle
|
|
99
100
|
# Make a PUT request
|
100
101
|
def put(url, data={}, options={})
|
101
102
|
response = connection.put do |req|
|
102
|
-
req.options
|
103
|
+
req.saddle_options = options
|
103
104
|
req.url(url)
|
104
105
|
req.body = data
|
105
106
|
end
|
@@ -109,7 +110,7 @@ module Saddle
|
|
109
110
|
# Make a DELETE request
|
110
111
|
def delete(url, params={}, options={})
|
111
112
|
response = connection.delete do |req|
|
112
|
-
req.options
|
113
|
+
req.saddle_options = options
|
113
114
|
req.url(url, params)
|
114
115
|
end
|
115
116
|
handle_response(response)
|
@@ -131,61 +132,59 @@ module Saddle
|
|
131
132
|
|
132
133
|
# Build a connection instance, wrapped in the middleware that we want
|
133
134
|
def connection
|
134
|
-
@connection ||= Faraday.new(base_url) do |
|
135
|
+
@connection ||= Faraday.new(base_url, :builder_class => Saddle::RackBuilder) do |connection|
|
135
136
|
# Include the requester level options
|
136
|
-
builder.
|
137
|
+
connection.builder.saddle_options[:client_options] = @options
|
137
138
|
|
138
139
|
# Config options
|
139
|
-
|
140
|
-
builder.
|
141
|
-
builder.
|
142
|
-
builder.
|
143
|
-
:client => @parent_client,
|
144
|
-
}
|
140
|
+
connection.options[:timeout] = @timeout
|
141
|
+
connection.builder.saddle_options[:request_style] = @request_style
|
142
|
+
connection.builder.saddle_options[:num_retries] = @num_retries
|
143
|
+
connection.builder.saddle_options[:client] = @parent_client
|
145
144
|
|
146
145
|
# Support default return values upon exception
|
147
|
-
|
146
|
+
connection.use(Saddle::Middleware::Response::DefaultResponse)
|
148
147
|
|
149
148
|
# Hard timeout on the entire request
|
150
|
-
|
149
|
+
connection.use(Saddle::Middleware::RubyTimeout)
|
151
150
|
|
152
151
|
# Set up a user agent
|
153
|
-
|
152
|
+
connection.use(Saddle::Middleware::Request::UserAgent)
|
154
153
|
|
155
154
|
# Set up the path prefix if needed
|
156
|
-
|
155
|
+
connection.use(Saddle::Middleware::Request::PathPrefix)
|
157
156
|
|
158
157
|
# Apply additional implementation-specific middlewares
|
159
158
|
@additional_middlewares.each do |m|
|
160
|
-
m[:args] ?
|
159
|
+
m[:args] ? connection.use(m[:klass], *m[:args]) : connection.use(m[:klass])
|
161
160
|
end
|
162
161
|
|
163
162
|
# Request encoding
|
164
|
-
|
165
|
-
|
163
|
+
connection.use(Saddle::Middleware::Request::JsonEncoded)
|
164
|
+
connection.use(Saddle::Middleware::Request::UrlEncoded)
|
166
165
|
|
167
166
|
# Automatic retries
|
168
|
-
|
167
|
+
connection.use(Saddle::Middleware::Request::Retry)
|
169
168
|
|
170
169
|
# Raise exceptions on 4xx and 5xx errors
|
171
|
-
|
170
|
+
connection.use(Saddle::Middleware::Response::RaiseError)
|
172
171
|
|
173
172
|
# Handle parsing out the response if it's JSON
|
174
|
-
|
173
|
+
connection.use(Saddle::Middleware::Response::ParseJson)
|
175
174
|
|
176
175
|
# Set up instrumentation around the adapter for extensibility
|
177
|
-
|
176
|
+
connection.request :instrumentation
|
178
177
|
|
179
178
|
# Add in extra env data if needed
|
180
|
-
|
179
|
+
connection.use(Saddle::Middleware::ExtraEnv)
|
181
180
|
|
182
181
|
# Set up our adapter
|
183
182
|
if @stubs.nil?
|
184
183
|
# Use the default adapter
|
185
|
-
|
184
|
+
connection.adapter(@http_adapter[:key], *@http_adapter[:args])
|
186
185
|
else
|
187
186
|
# Use the test adapter
|
188
|
-
|
187
|
+
connection.adapter(:test, @stubs)
|
189
188
|
end
|
190
189
|
end
|
191
190
|
end
|
data/lib/saddle/version.rb
CHANGED
data/saddle.gemspec
CHANGED
@@ -21,13 +21,11 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.files = `git ls-files`.split($\)
|
22
22
|
s.executables = ['saddle']
|
23
23
|
s.test_files = s.files.grep(%r{^(spec)/})
|
24
|
-
|
25
|
-
if RUBY_VERSION < '1.9'
|
26
|
-
s.add_dependency 'activesupport', '~> 3.0'
|
27
|
-
else
|
28
|
-
s.add_dependency 'activesupport', '>= 3.0'
|
29
|
-
end
|
30
24
|
|
31
|
-
s.
|
32
|
-
|
25
|
+
s.required_ruby_version = '>= 2.6'
|
26
|
+
|
27
|
+
s.add_dependency 'activesupport', '>= 3.2'
|
28
|
+
s.add_dependency 'faraday', '~> 2.1'
|
29
|
+
|
30
|
+
s.add_development_dependency 'appraisal'
|
33
31
|
end
|
@@ -4,11 +4,11 @@ describe Saddle::BaseEndpoint do
|
|
4
4
|
let(:base_endpoint) { Saddle::BaseEndpoint.new(Saddle::Client.create) }
|
5
5
|
|
6
6
|
it 'can define singleton methods' do
|
7
|
-
expect(base_endpoint.respond_to?(:define_singleton_method)).to
|
7
|
+
expect(base_endpoint.respond_to?(:define_singleton_method)).to be_truthy
|
8
8
|
end
|
9
9
|
|
10
10
|
it 'responds to any defined singleton methods' do
|
11
11
|
base_endpoint.define_singleton_method(:my_method) { true }
|
12
|
-
expect(base_endpoint.my_method).to
|
12
|
+
expect(base_endpoint.my_method).to be_truthy
|
13
13
|
end
|
14
14
|
end
|
data/spec/requester/get_spec.rb
CHANGED
metadata
CHANGED
@@ -1,57 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: saddle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Lewis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-05-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '3.
|
19
|
+
version: '3.2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '3.
|
26
|
+
version: '3.2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: faraday
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: '2.1'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: '2.1'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: appraisal
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 0
|
48
|
-
type: :
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 0
|
54
|
+
version: '0'
|
55
55
|
description: Makes writing API clients as easy as giving high fives
|
56
56
|
email: mike.lewis@airbnb.com
|
57
57
|
executables:
|
@@ -59,9 +59,11 @@ executables:
|
|
59
59
|
extensions: []
|
60
60
|
extra_rdoc_files: []
|
61
61
|
files:
|
62
|
-
- .
|
63
|
-
- .
|
64
|
-
- .
|
62
|
+
- ".github/workflows/ci.yml"
|
63
|
+
- ".gitignore"
|
64
|
+
- ".rspec"
|
65
|
+
- ".travis.yml"
|
66
|
+
- Appraisals
|
65
67
|
- CHANGELOG.md
|
66
68
|
- Gemfile
|
67
69
|
- LICENSE
|
@@ -83,10 +85,22 @@ files:
|
|
83
85
|
- bin/template/spec/middleware/exception_raiser_spec.rb
|
84
86
|
- bin/template/spec/spec_helper.rb
|
85
87
|
- bin/template/spec/stub/stub_spec.rb
|
88
|
+
- gemfiles/activesupport_3.2.gemfile
|
89
|
+
- gemfiles/activesupport_4.0.gemfile
|
90
|
+
- gemfiles/activesupport_4.1.gemfile
|
91
|
+
- gemfiles/activesupport_4.2.gemfile
|
92
|
+
- gemfiles/activesupport_5.0.gemfile
|
93
|
+
- gemfiles/activesupport_5.1.gemfile
|
94
|
+
- gemfiles/activesupport_5.2.gemfile
|
95
|
+
- gemfiles/activesupport_6.0.gemfile
|
96
|
+
- gemfiles/activesupport_6.1.gemfile
|
97
|
+
- gemfiles/activesupport_7.0.gemfile
|
86
98
|
- lib/saddle.rb
|
87
99
|
- lib/saddle/client_attributes.rb
|
88
100
|
- lib/saddle/endpoint.rb
|
89
101
|
- lib/saddle/errors.rb
|
102
|
+
- lib/saddle/faraday/rack_builder.rb
|
103
|
+
- lib/saddle/faraday/request.rb
|
90
104
|
- lib/saddle/method_tree_builder.rb
|
91
105
|
- lib/saddle/middleware/authentication/oauth1.rb
|
92
106
|
- lib/saddle/middleware/authentication/oauth2.rb
|
@@ -130,17 +144,16 @@ require_paths:
|
|
130
144
|
- lib
|
131
145
|
required_ruby_version: !ruby/object:Gem::Requirement
|
132
146
|
requirements:
|
133
|
-
- -
|
147
|
+
- - ">="
|
134
148
|
- !ruby/object:Gem::Version
|
135
|
-
version: '
|
149
|
+
version: '2.6'
|
136
150
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
151
|
requirements:
|
138
|
-
- -
|
152
|
+
- - ">="
|
139
153
|
- !ruby/object:Gem::Version
|
140
154
|
version: '0'
|
141
155
|
requirements: []
|
142
|
-
|
143
|
-
rubygems_version: 2.2.2
|
156
|
+
rubygems_version: 3.0.3.1
|
144
157
|
signing_key:
|
145
158
|
specification_version: 4
|
146
159
|
summary: A full-featured, generic consumer layer for you to build API client implementations
|