Compare commits

...

855 Commits

Author SHA1 Message Date
dependabot[bot]
bc27144430
Bump actions/checkout from 4 to 5 (#1636)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-12 09:42:18 +02:00
Olle Jonsson
f0aab63319
Lint: use filter_map (#1637) 2025-08-12 09:38:38 +02:00
Matt
d099fafd65
Version bump to 2.13.4 2025-07-25 13:19:35 +01:00
Matt
cf32578f25
Improve error handling logic and add missing test coverage (#1633) 2025-07-25 13:18:53 +01:00
Matt
e76e60d3c0
Version bump to 2.13.3 2025-07-22 09:34:48 +01:00
Matt
674fc1583f
Fix type assumption in Faraday::Error (#1630)
Following #1627, we began to assume that the parameter passed to `Faraday::Error#new` could only be either and `Exception` or a `Hash`.

As demonstrated in #1629, it turns out in the real world we're also passing `Faraday::Env` instances when building errors, which also respond to `each_key` and `[]` too.
2025-07-22 09:34:19 +01:00
Matt
da86ebae9c
Version bump to 2.13.2 2025-07-04 14:14:39 +01:00
Niels Buus
ad8fe1e89a
Include HTTP method and URL in Faraday::Error messages for improved exception log transparency (#1628) 2025-07-04 14:09:46 +01:00
Olle Jonsson
1ddd281893 CONTRIBUTING: update socials links to Mastodon 2025-06-18 09:41:40 +02:00
Josef Šimánek
976369857e
Add migrating from rest-client docs section. (#1625) 2025-06-15 13:46:10 +03:00
Olle Jonsson
64e8a2bdb1
Lint rack_builder.rb: avoid naming a method (#1626)
Lint rack_builder.rb: avoid naming a method

The method name gave a complaint
2025-06-15 10:03:01 +03:00
Earlopain
bbaa093dbc
Only load what is required from cgi (#1623)
In Ruby 3.5 most of the `cgi` gem will be removed. Only the various escape/unescape methods will be retained by default.

On older versions, `require "cgi/util"` is needed because the unescape* methods don't work otherwise.

https://bugs.ruby-lang.org/issues/21258
2025-05-12 11:12:42 +01:00
Earlopain
fa9424b05a CI against Ruby 3.4 2025-05-11 15:10:53 +02:00
Matt
4018769a30
Version bump to 2.13.1 2025-04-25 15:37:39 +02:00
Matt
b5a02d7300
Fix Style/RedundantParentheses in options/env.rb (#1620) 2025-04-25 15:28:56 +02:00
Robert Keresnyei
b63eb9121f
Logger middleware default options (#1618) 2025-04-25 15:20:50 +02:00
Matt
77204cc7e8
Version bump to 2.13.0 2025-04-08 21:19:06 +01:00
Benjamin Fleischer
919dc8fdb3
feat(ssl options): support SNI hostname (#1615) 2025-04-08 21:16:16 +01:00
Matt
064a54be6c
Version bump to 2.12.3 2025-04-08 14:05:30 +01:00
Hiroaki Osawa
cd1c44a4aa
Fix thread safety issue by avoiding mutation of proxy options hash (#1617) 2025-04-08 13:53:16 +01:00
Sebastian Cohnen
1551c32371 removes ruby2_keywords usage 2025-03-03 06:54:32 +01:00
Matt
a9cf00425e
Version bump to 2.12.2 2024-12-09 10:50:18 +00:00
kodram
529b5b043e
Formatting the log using parameter progname for the logger (#1606) 2024-12-09 10:45:36 +00:00
Mamoru TASAKA
b7b2bc19e9 [TEST] fix compatibility with ruby 3.4.0dev
ruby 3.4 changes Hash#inspect formatting as:
https://bugs.ruby-lang.org/issues/20433

Closes #1602
2024-12-03 08:47:00 +01:00
chaymaeBZ
f9f4ce5bc1 Use generic argument forwarding + remove ruby2_keywords 2024-11-26 09:48:05 +01:00
Matt
93ef9e0ea9
Version bump to 2.12.1 2024-11-14 11:38:20 +00:00
Richard Marbach
fff02307ac
Allow faraday-net_http 3.4.x (#1599) 2024-11-14 11:37:28 +00:00
Matt
59c5003ceb
Version bump to 2.12.0 2024-09-18 10:03:36 +01:00
Clemens Kofler
98d5adf924
Make RaiseError middleware configurable to not raise error on certain status codes (e.g. 404) (#1590) 2024-09-13 15:08:50 +01:00
David Rodríguez
9e5c8a113f
Add json as an explicit dependency (#1589) 2024-09-11 08:31:10 +02:00
JC (Jonathan Chen)
9fcff671ff
docs: fix grammar (#1588) 2024-09-10 08:19:42 +02:00
Matt
3170e7df6f
Version bump to 2.11.0 2024-08-26 09:48:45 +01:00
Matt
f208ffcc9a
Allow faraday-net_http 3.3.x 2024-08-26 09:48:10 +01:00
womblep
9056eccea6
Add ciphers attribute to SSLOptions (#1582) 2024-08-24 11:25:57 +01:00
Geremia Taglialatela
99228e4743
Fix typos (#1585)
Found via `codespell`.
2024-08-24 09:23:20 +02:00
Geremia Taglialatela
9cdc025759
Opt-in for MFA requirement explicitly (#1580)
As a popular gem, `faraday` implicitly requires that all privileged
operations by any of the owners require OTP.

However, by explicitly setting `rubygems_mfa_required` metadata, the
gem will show "NEW VERSIONS REQUIRE MFA" and
"VERSION PUBLISHED WITH MFA" in the sidebar at
https://rubygems.org/gems/faraday

Ref:
- https://blog.rubygems.org/2022/08/15/requiring-mfa-on-popular-gems.html
- https://guides.rubygems.org/mfa-requirement-opt-in/
2024-08-22 17:17:20 +01:00
Matt
3835b48d80
Add support for a new ParallelManager#execute method. (#1584)
* Add support for a new `ParallelManager#execute` method.

The new interface passes the parallel block with all the requests to the ParallelManager, instead of running it beforehand.

This allows for better, stateless ParallelManager implementations.

Fixes https://github.com/lostisland/faraday/issues/1583

* Update docs/adapters/custom/parallel-requests.md

Co-authored-by: Olle Jonsson <olle.jonsson@gmail.com>

---------

Co-authored-by: Olle Jonsson <olle.jonsson@gmail.com>
2024-08-22 13:05:07 +01:00
dependabot[bot]
3efc0a8982
Update faraday-net_http requirement from >= 2.0, < 3.2 to >= 2.0, < 3.3 (#1579)
Updates the requirements on [faraday-net_http](https://github.com/lostisland/faraday-net_http) to permit the latest version.
- [Release notes](https://github.com/lostisland/faraday-net_http/releases)
- [Commits](https://github.com/lostisland/faraday-net_http/compare/v2.0.0...v3.2.0)

---
updated-dependencies:
- dependency-name: faraday-net_http
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-05 15:23:59 +02:00
Olle Jonsson
f27f7ab801 v2.10.1 2024-07-31 14:07:48 +02:00
Olle Jonsson
051a635f4b
fix: Avoid lazy-initialized lock (#1577) 2024-07-31 14:02:46 +02:00
Olle Jonsson
4860f75372 Update JS deps
We use docsify to render the documentation site, and so we have a package.json.

This updates its lockfile.

I used `npm audit fix` to update only the reported issues.
2024-07-22 13:05:29 +02:00
Matt
073faf7539
Remove rubygems-await version pinning
The commit being pinned has now been merged to master and released
2024-07-22 12:00:20 +01:00
Matt
18524c6e89
Version bump to 2.10.0 2024-07-08 10:36:36 +01:00
Matt
d51c392c2c
Use specific version of rubygems-await
See https://github.com/segiddins/rubygems-await/issues/47
2024-07-08 10:35:46 +01:00
Ryan McNeil
d83a2818e7
Introduce Middleware DEFAULT_OPTIONS with Application and Instance Configurability (#1572) 2024-07-05 19:30:43 +01:00
Fabian Winkler
1958cb1ce2
Add logger as explicit dependency (#1573) 2024-07-05 16:08:44 +01:00
Yutaka Kamei
d7d5a6a36f
Configure "npm" package-ecosystem for Dependabot (#1571) 2024-06-25 11:57:48 +01:00
Matt
5996054fd4
Version bump to 2.9.2 2024-06-18 09:52:10 +01:00
ykrods
d8bfca25fa
Merge relative url without escaping (#1569) 2024-06-18 09:50:41 +01:00
Mattia Giuffrida
4abafa5c66 Add Bundler::GemHelper tasks to Rakefile 2024-06-05 16:30:09 +01:00
Matt
89107f9889
Add missing bundle install to publish.yml 2024-06-05 15:57:43 +01:00
Matt
b5245081d9
Version bump to 2.9.1 2024-06-05 15:06:55 +01:00
Max Rozenoer
04515f38b3
Support default json decoder even when nil responds to :load (#1563)
In Rails (some versions at least), nil responds to `:load` (via ActiveSupport::Dependencies::Loadable mixin).
Enable default json decoder to work in this case
2024-06-05 15:06:16 +01:00
Tijmen Brommet
6933e9b70f
Add TooManyRequestsError (429) to error docs (#1565) 2024-06-04 11:34:03 +01:00
Masato Nakamura
6d82d716c2
Fix compatibility with Ruby 3.4.0-preview1 (#1560) 2024-05-24 15:50:52 +01:00
Mattia Giuffrida
7dc694150d Fix Rubocop errors 2024-05-24 16:41:19 +02:00
Vitali Semenyuk
c9cc1b30ec Make dig method case-insensitive in Faraday::Utils::Headers 2024-04-02 14:37:59 +02:00
Olle Jonsson
c0540b7ba3 Lint fix
Lint/RedundantCopDisableDirective: Unnecessary disabling of Performance/RedundantBlockCall
2024-04-02 12:54:46 +02:00
Matt
87e655f306
Use Rubygems Trusted Publishers to publish. (#1552) 2024-01-20 17:09:48 +00:00
dependabot[bot]
cd2cdfd446
Update rack requirement from ~> 2.2 to ~> 3.0 (#1549) 2024-01-20 16:53:12 +00:00
Matt
f56e9387c8
Remove unnecessary rubocop disable comments. (#1551)
These were added in #1550 because of an unsafe autocorrect, but have since been addressed in https://github.com/rubocop/rubocop/pull/12628
2024-01-20 16:33:29 +00:00
Gareth Jones
18154c8332
docs: update body param type for run_request (#1545) 2024-01-20 08:49:37 +00:00
Olle Jonsson
4b34b509fe Add RuboCop disables
The -a autoformatting failed. Putting these in, to pass.
2024-01-15 16:44:18 +01:00
geemus
d820a58314 add bundler config to dependabot 2024-01-15 16:07:29 +01:00
Matt
cc5d607766
Version bump to 2.9.0 2024-01-09 10:35:49 +00:00
Matt
ceb01e42e8
Bump faraday-net_http version to allow 3.1 (#1546)
v3.1 increases the minimum ruby version to 3.0
2024-01-09 10:33:43 +00:00
Mattia Giuffrida
074506e67c Use latest Ruby version to publish and run rubocop 2023-12-28 18:09:17 +01:00
Mattia Giuffrida
898f203584 Run rubocop in CI using Ruby 3.3 2023-12-28 18:09:17 +01:00
Mattia Giuffrida
f0f549d7ef Fix Rubocop offenses 2023-12-28 18:09:17 +01:00
Mattia Giuffrida
caa4ff42f8 Update GitHub workflows, add 3.3 to CI matrix 2023-12-28 18:09:17 +01:00
Mattia Giuffrida
13732f7ff2 Remove ruby2_keywords dependency 2023-12-28 18:09:17 +01:00
Mattia Giuffrida
8cbfd758c2 Make 3.0 the minimum supported Ruby version 2023-12-28 18:09:17 +01:00
Earlopain
9487833b42
Remove runtime dependency on base64 (#1541) 2023-12-27 10:07:35 +00:00
Olle Jonsson
7e12133b92
v2.8.1 2023-12-21 09:10:21 +01:00
Olle Jonsson
1206b3917c [ci skip] Add context-preserving comment 2023-12-21 09:07:45 +01:00
Olle Jonsson
d0e0436e24 Revert "Lint"
This require is necessary, in order to have access to the method Hash#pretty_inspect. Thanks segiddins for sharp eyes!

This reverts commit 53c7b499db87894c56d9a556ff9bddf5852b002d.
2023-12-21 09:07:45 +01:00
Matt
25da081f59
Version bump to 2.8.0 2023-12-20 09:36:53 +00:00
Igor Tikhomirov
1e81e2c71a
Configurable JSON encoders and decoders (#1539) 2023-12-20 09:35:08 +00:00
dependabot[bot]
b8e2e454df Bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-14 09:26:48 +01:00
Olle Jonsson
09a635f30e CI: tell dependabot to update GH Actions 2023-12-14 09:25:30 +01:00
Olle Jonsson
fa6075c0f9 lint: Style/HashEachMethods 2023-12-14 09:23:34 +01:00
Olle Jonsson
53c7b499db Lint 2023-12-14 09:23:34 +01:00
Olle Jonsson
639e1b52e7 Gemfile: add racc to development, lint group
In Ruby 3.3, this is not a stdlib.
2023-12-14 09:23:34 +01:00
Wesley Beary
342e7e65cd Update testing.md
fix `deflate` typo in description of compression feature
2023-12-13 22:13:34 +01:00
Matt
3e27447a80
Version bump to 2.7.12 2023-11-21 13:55:44 +00:00
Daniel Pepper
63ba2aaf0c 429 error 2023-10-21 01:45:30 +02:00
k0i
5fccc20854 Update parallel-requests.md 2023-10-03 06:51:57 +02:00
Matt
28a097f756
Version bump to 2.7.11 2023-09-12 16:41:46 +01:00
Clayton Passmore
5ccddaafef
Add option for omitting request data from Faraday exceptions (#1526) 2023-09-12 16:38:01 +01:00
Koichi ITO
ea30bd0b54 Add base64 to runtime dependency
This PR add `base64` to runtime dependency to suppress the following Ruby 3.3's warning:

```console
$ ruby -ve 'require "faraday"'
ruby 3.3.0dev (2023-08-14T15:48:39Z master 52837fcec2) [x86_64-darwin22]
/Users/koic/.rbenv/versions/3.3.0-dev/lib/ruby/gems/3.3.0+0/gems/faraday-2.7.10/lib/faraday/utils.rb:3:
warning: base64 which will be not part of the default gems since Ruby 3.4.0
```

cf: https://github.com/rails/rails/pull/48907
2023-08-15 10:47:52 +02:00
Olle Jonsson
230fa1b1f5 Format code with less indent 2023-08-15 08:58:34 +02:00
Koichi ITO
7ce686503a Fix a test failure using Ruby 3.3.0dev
This PR fixes the following test failure using Ruby 3.3.0dev:

```console
$ ruby -v
ruby 3.3.0dev (2023-08-14T15:48:39Z master 52837fcec2) [x86_64-darwin22]
$ bundle exec rspec spec/faraday_spec.rb

Randomized with seed 57031

Faraday
  has a version number
  proxies to default_connection
    uses method_missing on Faraday if there is no proxyable method (FAILED - 1)
    proxies methods that exist on the default_connection
    proxied methods can be accessed

Failures:

  1) Faraday proxies to default_connection uses method_missing on Faraday if there is no proxyable method
     Failure/Error:
       expect { Faraday.this_method_does_not_exist }.to raise_error(
         NoMethodError, expected_message
       )

       expected NoMethodError with "undefined method `this_method_does_not_exist' for Faraday:Module",
       got #<NoMethodError: undefined method `this_method_does_not_exist' for module Faraday> with backtrace:
         # ./lib/faraday.rb:147:in `method_missing'
         # ./spec/faraday_spec.rb:27:in `block (4 levels) in <top (required)>'
         # ./spec/faraday_spec.rb:27:in `block (3 levels) in <top (required)>'
     # ./spec/faraday_spec.rb:27:in `block (3 levels) in <top (required)>'
```

That error message has been changed by https://github.com/ruby/ruby/commit/e7b8d32e in Ruby 3.3.0dev.

cf. https://bugs.ruby-lang.org/issues/18285

So the test error message is changed:

Ruby 3.2 or lower:

```
undefined method `this_method_does_not_exist' for Faraday:Module
```

Ruby 3.3.0dev:

```
NoMethodError: undefined method `this_method_does_not_exist' for module Faraday
```
2023-08-15 08:52:00 +02:00
Edward Loveall
26168c4ce4 Fix included middleware links
The links were pointing to `/middleware/___` instead of
`/middleware/included/___`
2023-08-07 08:45:41 +02:00
shane pope
63c38f7716 Fix 404 link in UPGRADING documentation
https://lostisland.github.io/faraday/#/middleware/included/authentication is the corrected url
2023-08-05 07:19:54 +02:00
Fernando Briano
e88b55a3d4
Fix capitalization for Elasticsearch (#1520) 2023-08-02 15:11:56 +01:00
Matt
1eca6a987d
Remove dead links to "Faraday Team" page.
Fixes #1518
2023-07-25 10:35:05 +01:00
Mattia Giuffrida
0580f101ce Add new logo image 2023-07-22 18:06:09 +01:00
Matt
30c4205958
Add "why use faraday?" section to repository README.md 2023-07-22 08:57:06 +01:00
Matt
c88fa65e07
Support twitter meta tags for docs site link preview 2023-07-13 15:55:00 +01:00
Matt
228f660a92
Improve Docs site link preview 2023-07-13 15:50:12 +01:00
Matt
17d586cb2f
📄 New docs 🎉 (#1517) 2023-07-13 15:29:16 +01:00
Olle Jonsson
15788115f5
Refer to correct branch [ci skip] (#1516) 2023-07-10 12:52:09 +01:00
Matt
1518a984c0
Version bump to 2.7.10 2023-07-06 09:47:20 +01:00
Simon Perepelitsa
d1743e6476
Fix some logging inefficiencies (#1515) 2023-07-06 09:45:36 +01:00
Matt
3af5211900
Version bump to 2.7.9 2023-06-30 09:37:22 +01:00
Yutaka Kamei
1e3e4e056d
Include env[:headers] in Stubs::NotFound (#1514) 2023-06-30 09:36:05 +01:00
Sebastian Cohnen
83676df431 adds hint to docs/README.md how to compile eventmachine with Ruby >= 3.0 on macOS 2023-06-29 09:05:18 +02:00
Sebastian Cohnen
baa7b2724a updates raise error middleware docs 2023-06-29 09:05:18 +02:00
Sebastian Cohnen
b47e22bf5d adds Faraday::Response::RaiseError for HTTP 408 when using raise error middleware 2023-06-29 09:05:18 +02:00
Matt
2824eaf968
Version bump to 2.7.8 2023-06-28 10:18:00 +01:00
Eike Send
990799a850
Fix: Logging headers & errors fails when ConnectionFailed is raised (#1512) 2023-06-28 10:17:24 +01:00
Matt
be98e8ef6f
Version bump to 2.7.7 2023-06-20 11:55:34 +01:00
Mattia Giuffrida
b54e7aefcc Fix implementation of Faraday::Error helpers.
Fix #1509
2023-06-19 08:30:58 +02:00
Mattia Giuffrida
de709cda8d Remove edge version of rubocop-packaging from Gemfile.
The issue it resolved has now been released.
See https://github.com/utkarsh2102/rubocop-packaging/issues/44
2023-06-15 16:45:30 +01:00
Matt
e0ce4a4d79
Bump version to 2.7.6 2023-06-07 09:49:57 +01:00
Matt Brictson
86298d0c45
Fix "method redefined" warnings introduced in Faraday 2.7.5 (#1506)
* Print Ruby warnings when running specs

* Fix 'method redefined' warnings
2023-06-07 09:46:49 +01:00
Matt
d40f3dbb99
Add blog post link to README
Courtesy of @mattbrictson, the post clarifies some unintuitive behaviour of the gem and shows how to build robust clients using Faraday.
2023-05-31 10:21:27 +01:00
Matt
819cfe7f24
Version bump to 2.7.5 2023-05-23 16:30:48 +01:00
TATSUNO “Taz” Yasuhiro
98947e6853
ProxyOptions should treat empty string as nil (#1493) 2023-05-23 16:29:22 +01:00
Yutaka Kamei
6d37ef7e3c
Encode false to "false" in Faraday::Request::Json (#1504)
Previously, `Faraday::Request::Json` doesn't encode the value `false`
while it encodes `true` to `"true"`.

This patch fixes the inconsistent behavior to make the middleware encode
`false` to `"false"`.
2023-05-23 16:19:20 +01:00
Yutaka Kamei
111d354b7f
Always assume the existence of URI::Generic#find_proxy (#1502)
Previously, the method `#proxy_from_env` checked the existence of
`URI::Generic#find_proxy` by using `respond_to?(:find_proxy)`;
this method was introduced in Ruby 2.0.0.

Since the latest Faraday requires Ruby 2.6, as specified
in `faraday.gemspec`, there is no need for `#proxy_from_env` to handle
the case where `URI::Generic#find_proxy` doesn't exist.
2023-05-18 17:08:30 +01:00
Matt Brictson
75dfbd6275
Fix incorrect use of logger middleware in docs (#1497) 2023-04-14 10:50:33 +01:00
Bart de Water
450b0d9ff8
Remove direct struct subclassing (#1491)
This is a follow-up to 39f1b35db671fbf9d55c1ef9cea61514a1a4d64d - I noticed I was still missing Faraday::Request#body= from Tapioca's generated definitions. Also did Faraday::Adapter::Test::Stub while we're here for consistency.
2023-02-08 12:59:29 +00:00
Bart de Water
39f1b35db6
Subclass Options structs using a block (#1489)
As recommended on https://ruby-doc.org/core-2.2.2/Struct.html#method-c-new and https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/StructInheritance

Has the nice side-effect of making the methods defined by Struct.new discoverable by Tapioca.

Using the @!parse directive to ensure YARD doesn't collapse the separate pages into constants under the Faraday module
2023-02-04 08:53:51 +00:00
Matt
f6c38689c6
Version bump to 2.7.4 2023-01-20 14:54:04 +00:00
Matt
2b9a6241c6
Use Uri.parse instead of Utils.URI (#1485)
Utils.URI can be configured to use a different parser and return an object that "behaves like a URI". However, `opaque` is not available in other objects (e.g. Addressable::URI), so in this instance we need to use URI.

Fixes #1484
2023-01-20 14:53:38 +00:00
Matt
cc7e7bcea9
Version bump to 2.7.3 2023-01-16 16:06:59 +00:00
Wladimir Braguini Domingues
f26715c9f3
Update connection.rb documentation (#1482)
Updates connection.rb documentation with PUT example
2023-01-16 16:00:17 +00:00
Aaron Stillwell
bf3ed115fa
Add URL to to_hash in Faraday::Response (#1475)
Co-authored-by: Matt <iMacTia@users.noreply.github.com>
2023-01-16 15:59:23 +00:00
hyuraku
f77d3a18ab Connection#build_exclusive_url: replace simple syntax 2023-01-13 14:06:43 +01:00
Olle Jonsson
a384efbc72 Fix Style/ZeroLengthPredicate 2023-01-12 09:58:17 +01:00
Frederik Spang Thomsen
85577e2613 docs: Update to 2023 2023-01-04 07:40:04 +01:00
Henrique Albuquerque
0e16de8e5a Delete .DS_Store 2022-12-26 07:24:08 +01:00
Henrique Albuquerque
16934978e8 Fix typo in Adapters documentation 2022-12-26 07:24:08 +01:00
Peter Goldstein
8d7e5a7e0f Adds Ruby 3.2 to the CI matrix. 2022-12-26 07:22:27 +01:00
Henry Yang
a34861a3b0
Clarify diff between connection settings timeout and open_timeout (#1470) 2022-12-22 14:39:26 +00:00
Matt
20a5d573f9
Version bump to 2.7.2 2022-12-14 09:55:17 +00:00
Matt
86aa000b2d
Improve documentation around Middleware stack
Add an example to showcase the rack-style nested structure generated by the rack builder.
Addresses https://github.com/lostisland/faraday/issues/1458#issuecomment-1330715727
2022-12-14 09:54:49 +00:00
Matt
c02a104469
Rename Faraday::Logger::Formatter#error to #exception (#1468)
This is because #error is already delegated to the internal Logger, and could cause an infinite loop when the log_level is set to "error".

Fixes #1467
2022-12-14 09:48:10 +00:00
Daniel Pepper
9a16831147 rubocop 2022-12-09 17:07:19 +01:00
Daniel Pepper
1914d594c4 test adapter timeout 2022-12-09 17:07:19 +01:00
Katsuhiko YOSHIDA
3ee9c81335 Replace actions/setup-ruby with ruby/setup-ruby 2022-12-08 09:08:35 +01:00
Matt
c6668ef8a8
Version bump to 2.7.1 2022-11-18 11:08:50 +00:00
Olle Jonsson
4ad9c1e921 fix: require 'pp' to have access to #pretty_inspect
Fixes #1462
2022-11-18 09:05:33 +01:00
Matt
8af0c875bc
Version bump to 2.7.0 2022-11-15 10:28:52 +00:00
epaew
2862ae6212 Update documents for response logger middleware. 2022-11-14 17:31:46 +01:00
epaew
12bab73ec3 Formatter: make errors' logging controllable. 2022-11-14 17:31:46 +01:00
epaew
93affec586 Faraday::Logging::Formatter#error: Prevent NoMethodError when received anything other than Faraday::Error. 2022-11-14 17:31:46 +01:00
epaew
5d28006566 Feature: Allows logging of errors that raised in adapter or other middleware. 2022-11-14 17:31:46 +01:00
Yutaka Kamei
ebdcee2b6e
Utils::Headers: Convert self[key] to a String with #<< on #add_parsed (#1459) 2022-11-10 13:27:19 +00:00
Matt
26a35fd76a
Remove unnecessary require 'pp' (#1457) 2022-11-09 16:46:18 +00:00
Alex
36916f0759
GitHub Workflows security hardening (#1451) 2022-10-10 09:59:47 +01:00
Matt
4024f4d402
Version bump to 2.6.0 2022-10-03 17:27:35 +01:00
Yutaka Kamei
fe6e71bbe0
Update @param of methods on Connection (#1452) 2022-10-03 14:29:08 +01:00
Joe Swatosh
e1dbdf065e
Forward the env to Request::Authorization#header_from (#1450) 2022-10-03 13:20:07 +01:00
mi-wada
7926e3aa89
docs: fix usage page to match latest version's default adapter specification (#1447) 2022-09-05 17:11:48 +02:00
Felix Yan
4816043101 Correct a typo inUPGRADING.md 2022-08-28 16:12:28 +02:00
Matt
b3b922949d
Version bump to 2.5.2 2022-08-11 13:48:46 +01:00
Matt
89b1fe3da9
Explicitly pass reason_phrase to save_response in test adapter. (#1445)
Fixes #1444
2022-08-11 13:48:13 +01:00
Matt
43d6797770
Enables and fixes all new cops. (#1443) 2022-08-08 15:46:54 +01:00
Mattia Giuffrida
5e01af3828 Version bump to 2.5.1 2022-08-08 14:29:52 +01:00
Mattia Giuffrida
646c30b8cb Allow faraday-net_http up to v3.1
Version 3.0 of `faraday-net_http` uses the new streaming API and the new `finished` option in `save_response`, which are not available in `faraday` prior to version 2.5, and has therefore been released as a new major version.

To avoid the same issue in future, we're fixing the version to allow any 3.0.x version, but not 3.1+.
This will allow us to ship a minor versions of the adapter with "breaking" changes for older versions of Faraday.
2022-08-08 14:29:24 +01:00
Matt
591b58fc06
Version bump to 2.5.0 2022-08-08 12:29:03 +01:00
Sampat Badhe
1ddf062331
Fix documentation typo (#1441) 2022-08-08 12:26:02 +01:00
Mattia Giuffrida
1a5b794b88 Disable new streaming API specific tests 2022-08-08 12:23:09 +01:00
Mattia Giuffrida
8a6a12100d Update CI matrix:
* Make `truffleruby-head` experimental
* Add `ruby-head` as experimental
2022-08-08 12:23:09 +01:00
Mattia Giuffrida
6799f5852d Introduce new streaming API (#1439)
* Backwards-compatible
* Allow adapters to provide response info to on_call block
* Provide `stream_response` helper method
2022-08-08 12:23:09 +01:00
Mattia Giuffrida
5d4c1fb962 Temporarily use edge rubocop-packaging 2022-08-08 12:23:09 +01:00
Mattia Giuffrida
af116aa0a3 Add bake-test-external and test faraday-net_http as part of the CI 2022-08-08 12:23:09 +01:00
Matt
7f444c3971 Add encoders #sort_params to documentation
Fixes #1429
2022-08-01 09:56:38 +02:00
Matt
69e88b4d52
Version bump to 2.4.0 2022-07-28 10:04:18 +01:00
Yutaka Kamei
cfbea91a69
Support Proc type for stubbed request body (#1436)
Previously, the Faraday testing adapter compared the request body to the
stubbed body just by calling `#==` if the stubbed body is present.
Sometimes, I want to check the equality between request and stubbed body
in more advanced ways. For example, there is a case that I want to check
only the parts of the body are actually passed to Faraday instance like
this:

```ruby
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
  stub.post('/foo', '{"name:"YK","created_at":"ANY STRING IS OK"}') { [200, {}, ''] }
end
connection.post('/foo', JSON.dump(name: 'YK', created_at: Time.now))
stubs.verify_stubbed_calls
```

In this case, it's difficult to make tests always pass with
`"created_at"` because the value is dynamic. So, I came up with an idea
to pass a proc as a stubbed value and compare bodies, inside the proc:

```ruby
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
  check = -> (request_body) { JSON.parse(request_body).slice('name') == { 'name' => 'YK' } }
  stub.post('/foo', check) { [200, {}, ''] }
end
connection.post('/foo', JSON.dump(name: 'YK', created_at: Time.now))
stubs.verify_stubbed_calls
```

I believe this would be flexible but compatible with the previous behavior.
2022-07-28 10:03:13 +01:00
sampatbadhe
fecc0a24cb Fix syntax to use correct doc link for url_encoded 2022-07-25 16:47:43 +02:00
Jason Karns
607a725719 Move JsonResponse middleware to response section
The JsonResponse middleware was listed under the Request middleware section for some reason.
2022-07-24 16:11:41 +02:00
水上 皓登
9d4486616a docs link fixed 2022-07-08 17:16:39 +02:00
Konstantin S Kazarin
d420a12a57
Handle verify hostname ssl option (#1428) 2022-06-30 22:26:16 +01:00
Olle Jonsson
fcb2003178
docs: Update to 2022 (#1420) 2022-05-23 14:24:45 +01:00
Matt
71a70f1d8c Remove examples using extension middleware
People want to copy documentation snippets and use them, so they should be compatible with what Faraday offers out-of-the-box.
Fixes #1417
2022-05-17 11:06:50 +02:00
Matt
6ea010be93
Version bump to 2.3.0 2022-05-06 16:26:46 +01:00
Olle Jonsson
257268e0c8
CI: Update GitHub Action "checkout" to v3 (#1416) 2022-05-06 16:10:46 +01:00
Chris AtLee
a2b5f7f3a8
Allow application/x-www-form-url_encoded POST requests to use file objects as the request body (#1415) 2022-05-06 15:49:09 +01:00
Thong Kuah
56d58442e5 docs: Correct default default_adapter value
Since https://github.com/lostisland/faraday/pull/1366, the default value for `default_adapter` is `:net_http`.

Fixes https://www.rubydoc.info/gems/faraday/Faraday#default_adapter-class_method
2022-05-03 06:18:24 +02:00
Nicolas Svirchevsky
24eafaa99a
Doc: Added raise_error middleware configuration (#1412) 2022-04-27 15:52:38 +01:00
Matt
24b3fd36e6
Clarifies removal of net_http from v2.0
Adds an explicit not to explain that the `net_http` adapter was originally removed from 2.0 and reintroduced in 2.0.1.
Fixes #1409
2022-03-31 10:35:17 +01:00
Alexander Popov
8f00640dd5 Update custom middleware documentation
Add a section with link to the repo with template.
2022-02-23 21:09:13 +01:00
Joshua Bremer
fc11225474 Add one more require to the quickstart to make this whole thing work immediately 2022-02-18 16:34:22 +01:00
Thomas Sanchez
f003443acc
Add indices when arrays are encoded (#1399) 2022-02-16 10:05:38 +00:00
Olle Jonsson
b2390ec2b3
docs: UPGRADE Note #dependency removed in 2.0 (#1398)
This adds a missing explanation to the UPGRADE document. Anyone searching for `dependency` should be able to find this section.
2022-02-07 10:41:52 +00:00
Olle Jonsson
3fc35dac23
CHANGELOG: add 2.2.0 section (#1394) 2022-02-03 09:50:54 +00:00
Matt
948274e25e
Version bump to 2.2.0 2022-02-03 09:36:00 +00:00
Olle Jonsson
46f3b678f0 Refactor test
This avoids leaking the class definition.
2022-02-02 20:24:49 +01:00
Mattia Giuffrida
85dfdf824c Re-add register middleware w/ Symbol, String, Proc
Reintroduce the possibility to register middleware with symbols, strings or procs.

Fixes #1389
2022-02-02 20:24:49 +01:00
Olle Jonsson
33563e3d63 docs: Amend CHANGELOG, link to Releases 2022-02-02 16:07:43 +01:00
Andrew Haines
26d47ca5bb
Remove Faraday 2.0 alpha warning from README (#1385) 2022-01-19 18:59:09 +00:00
José Augusto
816d824bc1
Removing all sushi.com references and change to httpbingo.org (#1384)
Fixes #1164
2022-01-18 16:43:36 +00:00
José Augusto
9f80f875f7
Update docs to use httpbingo on example requests and add webrick for ruby 3.x support (#1383) 2022-01-18 10:44:16 +00:00
Matt
ae55a744d1
Version bump to 2.1.0 2022-01-15 14:34:05 +00:00
Yuki Hirasawa
7f004913eb
Add default adapter options (#1382) 2022-01-15 14:32:39 +00:00
Matt
577f0d3e75
Fix test adapter thread safety (#1380) 2022-01-15 08:58:30 +00:00
Matt
996028a165
Introduce mutex Monitor in Faraday::Test::Stubs (#1379)
Fixes #1365
2022-01-12 15:56:25 +00:00
Yuki Hirasawa
026e9569a1
docs: fix regex pattern in logger.md examples (#1378) 2022-01-11 14:26:06 +00:00
Peter Goldstein
295f112356
Add Ruby 3.1 to CI (#1374) 2022-01-07 22:08:29 +00:00
Matt
9825916400
Update instructions for adapters in UPGRADING.md 2022-01-06 09:30:11 +00:00
Matt
309797d573
Version bump to 2.0.1 2022-01-05 21:49:07 +00:00
Matt
5f88f8ff85
Re-add faraday-net_http as default adapter (#1366) 2022-01-05 21:48:13 +00:00
Olle Jonsson
565f463fdc
docs: Make UPGRADING examples more copyable (#1363) 2022-01-05 08:34:32 +00:00
Mark Huk
50e3ebb805
Updated sample format in UPGRADING.md (#1361) 2022-01-04 19:04:07 +01:00
Matt
0a5714e8c8
Version bump to 2.0.0 2022-01-04 08:34:19 +00:00
Matt
88d16b7e2d Provide removed middleware with its own section for clarity 2022-01-03 09:40:52 +01:00
Mattia Giuffrida
2d60ce0ac7 Update UPGRADING.md 2022-01-03 09:40:52 +01:00
Mattia Giuffrida
cb47eca810 Remove multipart middleware and all its documentation and tests. 2022-01-03 09:40:52 +01:00
Matt
93a693b9ef
* Remove retry middleware and all its documentation and tests. (#1356) 2022-01-02 10:19:15 +00:00
Matt
c9b8490bb7
Remove default Faraday.default_adapter value and add exception message with link to usage documentation. (#1354) 2021-12-30 15:38:49 +00:00
Matt
1c3e27616d
Improve documentation for v2 (#1353) 2021-12-30 14:46:00 +00:00
Jonathan Rochkind
b1165eac65
Don't call retry_block if retry won't happen due to max_interval and retry_after (#1350) 2021-12-23 10:30:50 +00:00
DariuszMusielak
a555580f5f
Allow to raise a Faraday::Error without parameters (#1351) 2021-12-21 09:57:19 +00:00
Jason Banahan
5b8c8a6f2e Include latest jruby openssl version
Fixes issues with letsencrypt certificates
2021-12-17 09:24:12 +01:00
Matt
23e2495636
Update version.rb 2021-12-15 15:22:18 +00:00
Simon Schmid
9ef407a028
Callable authorizers (#1345) 2021-12-15 15:21:05 +00:00
Mattia Giuffrida
65b8d3904f Fix Faraday.default_connection_options deep-merge tests 2021-11-30 10:00:43 +00:00
Matt
64058b983c
Bump version to 2.0.0.alpha-3 2021-11-30 09:39:46 +00:00
Matt
cc749c612d
Update UPGRADING.md to highlight change about Faraday.default_connection_options 2021-11-30 09:39:14 +00:00
xkwd
746ab737b5
Replace Hash#merge with Utils#deep_merge for connection options (#1343) 2021-11-30 09:37:13 +00:00
Igor Victor
3caf118cbc
Update ci.yml (#1341) 2021-11-13 15:10:28 +00:00
Matt
d159fac7b5 Remove legacy scripts and convert bootstrap, test and console into the more up-to-date bin scripts 2021-11-02 11:23:20 +01:00
Matt
c6bff34abb
Version bump to 2.0.0.alpha-2 2021-10-28 10:48:12 +01:00
Matt
498f6027a1 Load the test adapter now that it's the default one. 2021-10-28 10:43:42 +01:00
Matt
de1e9f82d2
Explain plan for faraday_middleware in UPGRADING.md (#1339) 2021-10-27 11:31:19 +01:00
Thomas
b3f417dc20 update changelog 1.8.0 2021-10-26 09:57:28 +02:00
Matt
de78dff26d
Update version.rb 2021-10-25 11:18:02 +01:00
Matt
c010031269
Remove net-http adapter and update docs (#1336) 2021-10-25 11:17:11 +01:00
willianzocolau
ceeaa7476f
Improve request info in exceptions raised by RaiseError Middleware (#1335) 2021-10-16 10:31:49 +02:00
Jonathan Rochkind
1d567df2ee
Retry middleware, exceptions option should handle string exception class name consistently (#1334) 2021-10-12 16:16:52 +02:00
Matt
77a464344a
Swap Gitter badge for GitHub Discussions one in README 2021-10-09 10:47:55 +02:00
Jens Dahl Møllerhøj
5366029282
Register json middleware correctly (#1331) 2021-10-08 14:38:11 +02:00
Matt
506e97afe6
Fix passing a URL with embedded basic auth (#1324) 2021-09-13 16:36:26 +01:00
Matt
04c43898ee
Add Connection#*_auth helpers deprecation to UPGRADING.md 2021-09-13 14:53:35 +02:00
Matt
fdf797bb28 Add Faraday 1.x examples in authentication.md docs
Fixes #1317
Fixes #1314
2021-09-01 10:57:37 +02:00
Yutaka Kamei
0f9626c48d Respect the params_encoder in Faraday::Adapter::Test (#1316) 2021-08-30 09:35:26 +01:00
Matt
dd1552f3ff
Automatically refresh website Team page on commit to default branch (#1315) 2021-08-21 10:27:27 +01:00
Matt
94b7bf4bf8
Update copyright year in README 2021-08-21 08:50:38 +01:00
Olle Jonsson
7de0a389dc
Say "2021" on the docs website
Using the current year has no legal weight, but it pops.
2021-08-20 17:58:17 +02:00
Matt
1dd6d98a28
Update CHANGELOG.md 2021-08-20 09:36:42 +01:00
Olle Jonsson
abe78b5df5 Lint: Lint/RedundantSafeNavigation 2021-08-17 08:44:04 +02:00
Olle Jonsson
fa26357178 Lint: Performance/BlockGivenWithExplicitBlock, and...
also Performance/RedundantSplitRegexpArgument.
2021-08-17 08:44:04 +02:00
Olle Jonsson
120c56988e Lint: skip Performance/StringInclude
We are after the side-effect of setting something in the last match,
from this "useless" RegExp.
2021-08-17 08:44:04 +02:00
Olle Jonsson
f1f36be663 Lint: Style/PerlBackrefs 2021-08-17 08:44:04 +02:00
Olle Jonsson
f0bc54fecb Gem rubocop-inclusivity features are now upstream
This commit enables the Naming/InclusiveLanguage rule.
2021-08-17 08:44:04 +02:00
Olle Jonsson
b79a36f65f Lint: Style/NegatedIfElseCondition 2021-08-17 08:44:04 +02:00
Olle Jonsson
4f6d2f830e RuboCop: Update .rubocop_todo.yml 2021-08-17 08:44:04 +02:00
Olle Jonsson
babfdeaf04 Lint: Avoid an issue with numeric suffix 2021-08-17 08:44:04 +02:00
Olle Jonsson
c95038abb5 Lint: Style/RedundantSelfAssignmentBranch 2021-08-17 08:44:04 +02:00
Olle Jonsson
9fa6a7e2aa Lint: Layout/LineEndStringConcatenationIndentation 2021-08-17 08:44:04 +02:00
Olle Jonsson
c0d97cefa5 Lint: Layout/EmptyLineBetweenDefs 2021-08-17 08:44:04 +02:00
Olle Jonsson
33235f482e Lint: Layout/LineEndStringConcatenationIndentation 2021-08-17 08:44:04 +02:00
Olle Jonsson
b183095c52 Lint: Style/HashConversion 2021-08-17 08:44:04 +02:00
Olle Jonsson
01e840e151 RuboCop: add new rules 2021-08-17 08:44:04 +02:00
Olle Jonsson
cc5391bc0d Gemfile: unlock RuboCop to get 1.x 2021-08-17 08:44:04 +02:00
Olle Jonsson
e640be9866 Lint Style/RedundantBegin 2021-08-17 08:44:04 +02:00
Olle Jonsson
59c32867b3 Regenerate RuboCop TODO file 2021-08-17 08:44:04 +02:00
Olle Jonsson
0b719c18a6 Add all new RuboCop rules 2021-08-17 08:44:04 +02:00
Olle Jonsson
d143b2d4f0 chore: Remove unnecessary lint skip 2021-08-17 08:44:04 +02:00
Olle Jonsson
006940a359 Use latest RuboCop, and bump Ruby req to 2.6 2021-08-17 08:44:04 +02:00
Matt
fe600c72ad
Drop deprecated auth helpers from Connection. (#1308)
Merge Authentication middleware.
Add possibility of passing a proc.
Update documentation.
2021-08-15 10:28:49 +02:00
Matt
7d727f4f02 Merge latest commits from 1.x 2021-08-14 13:32:53 +01:00
Matt
fa612a060a
[1.x] Deprecate Authorization helpers in Faraday::Connection (#1306) 2021-08-14 13:30:11 +01:00
Matt
ce0fdf8bca
Remove deprecated Faraday::UploadIO (#1307) 2021-08-14 09:48:16 +01:00
Matt
da878eaf38
Update README to inform about main branch containing unreleased v2 code and documentation (#1305) 2021-08-13 16:26:52 +01:00
Olle Jonsson
456191715a
Remove deprecated Faraday::Request#method (#1303) 2021-08-09 15:30:37 +02:00
Matt
4b6162d364
Move json middleware (request and response) from faraday_middleware (#1300) 2021-08-09 08:52:02 +01:00
Matt
83a97b72df
Version Bump to 1.7.0 2021-08-09 08:50:42 +01:00
Matt
08b7d4d3b7
Autoloading, dependency loading and middleware registry cleanup (#1301) 2021-08-09 08:25:02 +01:00
Matt
ca37a9420e Merge branch '1.x' of https://github.com/lostisland/faraday 2021-08-01 18:08:32 +01:00
Yutaka Kamei
a1ee375bcd
Add strict_mode to Test::Stubs (#1298) 2021-08-01 17:45:32 +01:00
Matt
6333b73d13
Begin v2 release (#1297)
* Update UPGRADING.md to highlight adapters being moved out
* Cleanup tests
* Cleanup Gemfile
* Update CI
2021-08-01 17:09:03 +01:00
Matt
a089fb83fa
Version bump to 1.6.0 2021-08-01 09:03:31 +01:00
Matt
fd1007ae33
Use external Rack adapter (#1296) 2021-08-01 09:01:13 +01:00
Matt
66d5dae371
Version bump to 1.5.1 2021-07-11 11:03:24 +01:00
Pavel Rosický
6ed220cabf
Fix jruby incompatibility after moving out EM adapters (#1294) 2021-07-11 11:02:52 +01:00
Kenichi Kamiya
8727853801
Update YARD to follow RackBuilder (#1292) 2021-07-08 15:41:27 +01:00
Matt
0e8bfa592f
Version bump to 1.5.0 2021-07-04 19:51:28 +01:00
Matt
bc4eb877c9
Use external patron adapter (#1290) 2021-07-04 19:50:59 +01:00
Matt
274f5fa6ba
Use external httpclient adapter (#1289) 2021-07-04 16:55:22 +01:00
Matt
8ca6a7eb58
Update version.rb 2021-06-24 16:10:59 +01:00
Alexey D
4dd36897af
Always dup url_prefix in Connection#build_exclusive_url (#1288) 2021-06-24 16:09:26 +01:00
Adam Doppelt
830b696ae7
silence warning (#1286) 2021-05-27 08:06:31 +02:00
Matt
63c33d234d
Version bump to 1.4.2 2021-05-22 09:33:25 +01:00
Adam Doppelt
1f496a7f17
Default proxy scheme to http:// if necessary, fixes #1282 (#1283) 2021-05-22 09:27:06 +01:00
Adam Doppelt
11d793dd7e
Docs: add more middleware examples (#1277) 2021-05-02 08:28:29 +02:00
Catalin
53e4baedc7
Add proxy setting when url_prefix is changed (#1276)
* Add proxy setting when url_prefix is changed

Without this setting, setting the url_prefix after
a Faraday::Connection is initialized results in no_proxy
settings ignored when using relative paths.

* Increase Rubocop Metrics/ClassLength
2021-04-28 15:54:08 +02:00
Matt
67c5f7b239
Use external em_http and em_synchrony adapters (#1274) 2021-04-26 11:57:10 +02:00
Adam Doppelt
a582495311
[docs] Improve introduction page (#1273)
This set of change are intended to help the first-time reader.

- show method signatures for HTTP verbs
- give an overview of adapters & middleware
- explain a bit more about the shortcut methods vs. creating a connection
- use httpbingo.org instead of the defunct sushi.com
- make a quick note about the default connection and url encoding

Discussion started in #1270.
2021-04-26 09:00:28 +02:00
Matt
048718fb79
Update version.rb 2021-04-18 19:22:24 +01:00
Matt
e82694793b
Fix dependencies from external adapter gems (excon, net_http_persistent) (#1269) 2021-04-18 19:22:01 +01:00
Matt
41d87d6225
Update version.rb 2021-04-16 11:27:04 +01:00
Olle Jonsson
bf7d855598
Add rubocop-inclusivity (#1267)
Co-authored-by: Mattia Giuffrida <giuffrida.mattia@gmail.com>
2021-04-14 17:57:11 +02:00
Olle Jonsson
38d9398559
CONTRIBUTING: add a policy on inclusive language (#1262) 2021-04-14 16:35:26 +01:00
Olle Jonsson
0787548639
Drop RDoc support file .document (#1264)
Co-authored-by: Matt <iMacTia@users.noreply.github.com>
2021-04-14 16:34:03 +02:00
Olle Jonsson
952dac0b4c Update RuboCop TODO file
Fixes #1258
2021-04-14 08:52:10 +02:00
Olle Jonsson
a0c4a1cd03 Trivially edit docs/ README
...to push to the docs/ directory, to try to get it to build.
2021-04-14 08:31:48 +02:00
Olle Jonsson
21ac595919
CI: Rename default branch to main (#1263) 2021-04-13 19:57:39 +01:00
Olle Jonsson
fbb441eca2
CONTRIBUTING: Fix grammar and layout (#1261) 2021-04-13 18:51:23 +02:00
Olle Jonsson
33ee1c4eed
Drop CodeClimate (#1259)
This removes CodeClimate test reporter ID and badge.

Since the quality of reporting has gone down, and these fail the
builds, reducing our warning-seeing ability, I now take step of
stopping reporting to CC.

If we want to do any spot-checks, we can run rubycritic, or some other
metrics tool, which does not disrupt our workflow.
2021-04-13 18:27:34 +02:00
Matt
20be816bc8
Replace Excon adapter with Faraday::Excon gem, and fix autoloading issue with Faraday::NetHttpPersistent (#1257) 2021-04-12 11:36:09 +02:00
Damau
8d379a16fe
Some docs on EventMachine adapters. (#1232) 2021-04-11 13:30:57 +01:00
Marouen Bousnina
99afc0ff6f
Fix NoMethodError undefined method 'coverage' (#1255) 2021-03-28 11:36:26 +01:00
Olle Jonsson
506954e5fe
CI: Configure the regenerated Coveralls token (#1256) 2021-03-28 10:10:16 +01:00
Mike Rogers
14d0dd70c4
Replacing Net::HTTP::Persistent with faraday-net_http_persistent (#1250) 2021-03-26 08:00:05 +00:00
Hiroshi Hatake
850155eb41
Handle IPv6 address String on Faraday::Connection#proxy_from_env (#1252) 2021-03-22 11:30:22 +00:00
Tiago
118f896ac3
[docs] Add httpx to list of external adapters (#1246)
httpx bundles its own faraday adapter, a la typhoeus. This adds it to the external adapters list.
2021-03-05 12:49:48 +01:00
Olle Jonsson
e7ab94f169
gemspec: Pick a good ruby2_keywords release (#1241) 2021-01-20 14:10:34 +00:00
yarafan
0ed6480f6e
escape colon in path segment (#1237) 2021-01-18 16:18:21 +00:00
Nick Campbell
d22dd00856
Fix broken Rubydoc.info links (#1236)
For some reason the docs are not being published for this gem anymore,
but they are still reachable when referencing the github path instead.
2021-01-12 15:19:45 +01:00
Ryunosuke Sato
086bb62217
Refactor CI to remove duplicated line (#1230)
"libcurl4-openssl-dev" is already installed in previous step.
2021-01-02 06:49:49 +01:00
Matt
18b9bd5e0c
Update CHANGELOG.md 2020-12-31 13:26:33 +00:00
Matt
f68a821dde
Version bump to 1.3.0 2020-12-31 13:13:52 +00:00
Matt
023cc41335
Improves consistency with Faraday::Error and Faraday::RaiseError (#1229) 2020-12-31 13:07:21 +00:00
Matt
453b26f1f0
Improves retry middleware documentation. (#1228) 2020-12-31 11:25:20 +00:00
Matt
687108bb4d
Adds Ruby 3.0 to CI Matrix (#1226) 2020-12-31 10:51:03 +00:00
brian p o'rourke
d67d012dd5
Don't assign to global ::Timer (#1227) 2020-12-31 09:34:59 +00:00
Olle Jonsson
968dfc18ba
CHANGELOG: add releases after 1.0 (#1225) 2020-12-29 13:06:21 +01:00
Matt
e41668ee59
Move out Net::HTTP adapter (#1222) 2020-12-29 11:29:21 +00:00
Mattia Giuffrida
2457525702 Version bump to 1.2.0 2020-12-23 14:39:22 +00:00
Matt
97a3bc2386
Fix #1219 Net::HTTP still uses env proxy (#1221) 2020-12-23 14:00:45 +00:00
Michael Grosser
e111db34c3
Avoid 1 use of keyword hackery (#1211) 2020-12-02 07:06:38 +01:00
Olle Jonsson
47411d8154
EmHttp adapter: drop superfluous loaded? check (#1213)
We are loaded in this section.
2020-12-01 10:21:42 +01:00
Michael Grosser
ebbbab5c2e
test against ruby head (#1208)
* CI: add "head" Ruby to matrix

* Gemfile: Allow Ruby 3 to use net-http-client 4.x

* Gemfile: Select net-http-persistent 4 differently

Check for Ruby version 3+

* Gemfile: doc net-http-persistent has no gemspec

* redo

Co-authored-by: Olle Jonsson <olle.jonsson@auctionet.com>
Co-authored-by: Olle Jonsson <olle.jonsson@gmail.com>
2020-11-28 09:24:02 +01:00
Kyle Keesling
b766d1f848
Update call to em_http_ssl_patch (#1202) 2020-11-19 14:45:40 +01:00
Matt
1595e6fc05
Fix rdebug recursion issue (#1205)
Co-authored-by: @native-api
2020-11-13 09:00:18 +00:00
Rusty Geldmacher
8c746f68e3 Require 'date' to avoid retry exception
Without requiring 'date', we get an exception in the retry middleware
when it tries to use DateTime for handling the Retry-After header.
2020-11-13 07:26:33 +01:00
Nathan Beyer
01c25e880c
Adjust the retry documentation and spec to align with implementation (#1197) (#1198) 2020-10-27 06:11:38 +01:00
Tijmen Brommet
95667f848a
Update documentation on using the logger (#1196)
`Faraday::Logging::Formatter` is the correct class to subclass.
2020-10-26 09:17:27 +01:00
Olle Jonsson
4e9f4b06f1
Fix a typo re: on_response -> on_complete 2020-10-23 17:28:00 +02:00
Olle Jonsson
0977306827
docs: Fix typo in markdown
Missing backtick ruined some formatting.
2020-10-22 20:23:25 +02:00
Matt
d56742a174
Introduces on_request and on_complete methods in Faraday::Middleware. (#1194) 2020-10-22 15:04:46 +01:00
Olle Jonsson
7326cd8bfd
docs: Adapters, how to create them (#1193)
This begins a new section, probably we want to move the Parallel section to its own "Advanced Adapter authoring" or a subject-specific text. Anyway, we have started!
2020-10-22 11:55:46 +02:00
Matt
680407daa9
Add comment in gemspec to explain exposure of examples and spec folders. (#1192)
Fixes #1190
2020-10-21 09:22:52 +01:00
Matt
571dc11c2f
Version bump to 1.1.0 2020-10-17 11:49:07 +01:00
Igor Victor
0461c4b321
Upgrade CI to ruby/setup-ruby (#1187)
This replaces rvm in GitHub Actions.
2020-10-13 16:22:53 +02:00
Joel Stimson
85b46bef6c
Remove retry_change_requests from documentation (#1185) 2020-10-06 10:33:29 +01:00
Utkarsh Gupta
a5b7a6bc81
Drop git ls-files in gemspec (#1183) 2020-09-23 11:20:37 +02:00
Sandro Damilano
8ee406d788
Include request info in exceptions raised by RaiseError Middleware (#1181) 2020-09-17 16:45:25 +02:00
Matt
868fe9bb18
Fix linting bumping Rubocop to 0.90.0 (#1182) 2020-09-17 16:02:47 +02:00
Matt
9af091f9c4
Improves documentation on how to contribute to the site by using Docker. (#1175) 2020-09-01 16:32:18 +01:00
Vít Ondruch
6521a1606e Properly fix test failure with Rack 2.1+.
Rack is not to blame, just naive test case which was enough so far.

Fixes #1119
2020-07-25 01:51:43 +02:00
Mattia
5acab36239
Introduces flat_encode option for multipart adapter. (#1163)
Fixes #1157
2020-07-09 10:43:09 +01:00
John W Higgins
e02a8c1009
Makes parameters sorting configurable (#1162) 2020-07-07 10:02:50 +01:00
Alexander Popov
f6130995eb
Update typhoeus to new stable version (1.4) (#1159) 2020-05-27 17:34:43 +01:00
Olle Jonsson
90b4564cec
Rubocop linting with 0.84.0 (#1160) 2020-05-27 17:26:31 +01:00
Daniel George Holz
722821fab7
Avoid 'last arg as keyword param' warning when building user middleware on Ruby 2.7 (#1153) 2020-05-15 15:32:38 +01:00
Mattia
019e1a8417
Limits net-http-persistent version to < 4.0 (#1156) 2020-05-07 23:34:48 +01:00
Olle Jonsson
41c0dc7edf
Add 1.0 release to wording in CONTRIBUTING (#1155) 2020-05-07 14:28:57 +01:00
Alexander Popov
87ecaf9682 Return tests of Test adapter 2020-04-20 08:27:04 +02:00
Alexander Popov
680b9f8a6c Add EditorConfig file
Resolve issues.

More info here: https://editorconfig.org/
2020-04-19 22:56:50 +02:00
Alexander Popov
c26df87b86 Update RuboCop
Require its specific version in `Gemfile`.

Fix it's installation in CI.

Enable new cops.

Resolve new offenses.

Drop support of Ruby 2.3
(it's not supported by RuboCop and by MRI:https://www.ruby-lang.org/en/news/2019/03/31/support-of-ruby-2-3-has-ended/)

Deprecate `Faraday::Request#method`, replace it with `#http_method`.
2020-04-19 17:44:07 +02:00
LuckyWind_sck
3b3de79e3d Fix typo for RSpec 2020-04-06 12:34:24 +02:00
Olle Jonsson
3ca146de4d Update year markers to 2020 for a lively look 2020-04-03 18:18:51 +02:00
Olle Jonsson
e33c559345
Link from GitHub Actions badge to CI workflow (#1141) 2020-04-03 17:02:01 +01:00
Olle Jonsson
f0c76f826f Remove Codeclimate coverage badge
- Until it supports SimpleCov 0.18, we drop this from our CI and README
2020-04-02 10:40:38 +02:00
Mattia
5547e9131a
Bump version to 1.0.1 2020-03-29 14:46:47 +01:00
Karl Entwistle
864a7e52f3
Encode Spaces in Query Strings as '%20' Instead of '+' (#1125) 2020-03-29 11:48:15 +01:00
Mattia
b4ad6e386e
Update publish.yml
Replace deprecated `version` with `ruby-version`
2020-03-29 11:12:08 +01:00
Olle Jonsson
f6401225a4 Adapter Registry reads also use mutex 2020-03-25 12:58:36 +01:00
Olle Jonsson
5d24afc373 External adapters exposed
- this was inadvertently removed in 0c873c1500b0849cafcc6a0c4d7ccfeedcc7a48a
  - the feature was introduced in #941
2020-03-07 06:40:32 +01:00
Marjan Povolni
e2c56e90c9 docs(website): fix request/response mix-up in text 2020-02-24 09:36:13 +01:00
Olle Jonsson
52e30bf8e8 spec: JRuby-proof a test about error messages 2020-02-10 16:04:04 +01:00
Olle Jonsson
284d920cf3 specs: JRuby-Skip EM specs 2020-02-10 16:04:04 +01:00
Olle Jonsson
e80b829976 specs: JRuby-Skip Patron specs 2020-02-10 16:04:04 +01:00
nic-lan
1042a45618
Allows parse method to be private/protected in response middleware (#1123) 2020-02-10 14:38:27 +00:00
Bobby McDonald
a4837c8509 Update org name for typhoeus repo 2020-02-07 18:14:34 +01:00
Olle Jonsson
d77c9efee9
Fully qualify constants to be checked (#1122) 2020-02-07 15:57:00 +00:00
Justin Bull
8560572d16
Use Net::HTTP#start(&block) to ensure closed TCP connections (#1117)
Co-authored-by: Byron Wolfman <byronwolfman@users.noreply.github.com>
2020-02-07 14:54:18 +00:00
Mattia
614c26fe9d
Limits rack to v2.0.x (#1127)
Fixes #1119
2020-02-06 20:31:26 +00:00
Olle Jonsson
099dd45f63
Merge pull request #1116 from vvo/docs/add-documentation-search
docs(website): add search to the website
2020-01-22 11:03:36 +01:00
Vincent Voyer
47dcf037a7
Merge branch 'master' into docs/add-documentation-search 2020-01-21 12:38:59 +01:00
Vincent Voyer
008321b24f docs(website): add search to the website
This commit adds documentation search to the whole website using Algolia's
DocSearch project: https://community.algolia.com/docsearch/.
Analytics are available via an Algolia account, ask vincent@codeagain.com for
more information.

I tried to be as close as the Faraday design as possible.
2020-01-21 12:38:12 +01:00
Olle Jonsson
e346b8bdb4 README: Link the logo to the website (#1112) 2020-01-09 11:45:11 +00:00
Olle Jonsson
b30ec73e99
docs(retry): precise usage of retry-after (#1111)
* docs(retry): precise usage of retry-after

Fixes https://github.com/lostisland/faraday/pull/1109#issuecomment-572448991
2020-01-09 10:46:43 +01:00
Olle Jonsson
6015ae97d6
[docs] Use "including" wording
By mentioning "including" instead of "configuring like this", we avoid the possible understanding "replace the whole list".
2020-01-09 10:37:22 +01:00
Vincent Voyer
024bfebd1a
docs(retry): precise usage of retry-after
fixes https://github.com/lostisland/faraday/pull/1109#issuecomment-572448991
2020-01-09 09:48:13 +01:00
Mattia
8a43a47919
Retry middleware documentation fix (#1109)
Fixes https://github.com/lostisland/faraday/pull/773#issuecomment-571089608
2020-01-08 20:20:44 +00:00
risk danger olson
ff9dc1d121
Merge pull request #1101 from lostisland/ship-1.0
Ship 1.0
2019-12-31 17:03:26 -07:00
technoweenie
cd9f83d86c indent so yard-junk doesn't think it's a 'tag' 2019-12-31 16:51:53 -07:00
risk danger olson
9f8e13753b
Update CHANGELOG.md 2019-12-31 16:41:38 -07:00
technoweenie
94e4e48ef4 Merge branch 'master' into ship-1.0 2019-12-31 08:55:20 -07:00
risk danger olson
bf454e6369
Update CHANGELOG.md 2019-12-31 08:54:02 -07:00
risk danger olson
688d5706b4
Merge pull request #1095 from lostisland/upstream-error-init
improve error initializer consistency
2019-12-31 08:21:09 -07:00
Mattia
41bc84e15f
Merge branch 'master' into upstream-error-init 2019-12-31 10:15:48 +00:00
Olle Jonsson
dac0eee62d
Merge pull request #1104 from lostisland/remove-connect-method
remove CONNECT method
2019-12-31 07:27:27 +01:00
technoweenie
df5fc690df remove ruby 2.7 deprecation
spec/faraday/response/logger_spec.rb:73: warning: Using the last argument as
keyword parameters is deprecated; maybe ** should be added to the call

lib/faraday/logging/formatter.rb:13: warning: The called method 'initialize'
is defined here
2019-12-30 08:11:59 -07:00
technoweenie
5b6f9d87d3 remove CONNECT method 2019-12-30 08:09:02 -07:00
technoweenie
61d466df87 start on changelog update 2019-12-29 23:32:53 -07:00
technoweenie
a0fd827dc5 version 1.0.0 2019-12-29 23:26:10 -07:00
technoweenie
d2372224f2 bump documented support up to ruby 2.4 2019-12-29 23:25:16 -07:00
risk danger olson
aea390a67c
Merge pull request #1084 from mrexox/fix-empty-body-for-flat-params-encoder
Fix empty array for FlatParamsEncoder {key: []} -> "key="
2019-12-29 23:18:21 -07:00
risk danger olson
cbedb826c9
Merge branch 'master' into fix-empty-body-for-flat-params-encoder 2019-12-29 23:08:05 -07:00
technoweenie
b4b328b720 Merge branch 'master' into upstream-error-init 2019-12-29 22:44:04 -07:00
risk danger olson
5a2bb2e5e6
Ci: ruby 2.7 (#1100)
* ci: run against ruby 2.7

* fix ruby 2.7 warning

lib/faraday/adapter/net_http_persistent.rb:13: warning: Using the last
argument as keyword parameters is deprecated; maybe ** should be added to the
call

https://github.com/lostisland/faraday/pull/1099/checks?check_run_id=367324080
https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/

* use rvm to install ruby 2.7
2019-12-29 22:43:23 -07:00
technoweenie
b322331923 revert error subclass changes 2019-12-29 18:37:05 -07:00
technoweenie
7ba417400f how do i get this to init 2019-12-27 13:14:08 -07:00
technoweenie
6833062a5c dont re-init them 2019-12-27 13:04:11 -07:00
technoweenie
5efd43f749 init these ivars 2019-12-27 12:46:56 -07:00
technoweenie
24b99b8231 don't force response to be {} 2019-12-27 12:35:23 -07:00
technoweenie
e4aee9f7f2 improve error initializer consistency 2019-12-27 12:25:22 -07:00
Mattia
3301356e7d
Merge branch 'master' into fix-empty-body-for-flat-params-encoder 2019-12-27 17:02:59 +00:00
Amr El-Bakry
9726bc2029 Add log_level option to logger default formatter (#1079) 2019-12-27 17:02:08 +00:00
Samuel Williams
15595d0370 Add Adapter#close so that derived classes can call super. (#1091) 2019-12-27 16:48:45 +00:00
Mattia
a53a4360e2
Adds compatibility with latest rubocop (#1093) 2019-12-27 16:43:11 +00:00
Mattia
465b1db267
Adds info about error classes hierarchy changes 2019-12-27 16:20:52 +00:00
Valentine Kiselev
7856e18a31
Merge branch 'master' into fix-empty-body-for-flat-params-encoder 2019-12-11 10:50:11 +03:00
Julien Kirch
073bc25cd4 Very small fix in adapter documentation 2019-12-11 06:54:35 +01:00
Valentine Kiselev
970a1922c0
Merge branch 'master' into fix-empty-body-for-flat-params-encoder 2019-12-10 10:46:07 +03:00
Kiselev Valentine
f1768df507 Fix CI for Ruby 2.3
Support for github action of ruby 2.3 was removed. Now according to
https://github.com/actions/setup-ruby/blob/master/action.yml
theminimal version is 2.4.
2019-12-10 08:45:05 +01:00
Kiselev Valentine
475ddeab13 Fix empty array for FlatParamsEncoder {key: []} -> "key=" 2019-12-09 14:05:01 +03:00
risk danger olson
0ebc233513
Merge pull request #1072 from lostisland/changelog
bring release notes back to changelog.md
2019-11-13 15:58:19 -07:00
risk danger olson
69f3078825
Merge pull request #1069 from ioquatix/patch-1
Add default implementation of `Middleware#close`.
2019-11-13 10:06:07 -07:00
Samuel Williams
4d49b031cd
It was off by 1. 2019-11-13 09:40:40 +09:00
Samuel Williams
0b9552e707
Expose Connection#close. 2019-11-12 08:58:47 +09:00
Samuel Williams
9379c716d4
Add spec for Middleware#close. 2019-11-11 11:14:39 +09:00
Samuel Williams
e7ddc2d298
Issue warning if #close is not implemented. 2019-11-11 10:58:01 +09:00
rick olson
108a0a7b74 [ ok ] 2019-11-06 13:33:49 -07:00
rick olson
5a9644937e appease rubocop 2019-11-06 13:26:20 -07:00
rick olson
0c873c1500 add changelog 2019-11-06 13:14:47 -07:00
Samuel Williams
f33e2fa1f8
Add default implementation of Middleware#close. 2019-11-02 08:31:02 +13:00
risk danger olson
d5eaa4ffe0
Merge pull request #1063 from lostisland/proxy-settings
remove temp_proxy and improve proxy tests
2019-10-23 11:23:34 -06:00
rick olson
b5f9936dbe remove temp_proxy and improve proxy tests 2019-10-18 11:10:41 -06:00
risk danger olson
e4b4b97307
Merge pull request #1057 from lostisland/actions-revert
0.1x-specific workflow changes will be recorded in the appropriate branch
2019-10-17 14:09:13 -06:00
rick olson
27a6509797 0.1x-specific workflow changes will be recorded in the appropriate branch, not master 2019-10-17 11:44:13 -06:00
risk danger olson
c638dbcb4b
Merge pull request #1056 from lostisland/actions-0.1x
[0.1x] skip rubocop and yard linting on faraday 0.1x related branches
2019-10-17 11:33:47 -06:00
rick olson
4e358a6741 skip codeclimate on 0.1x 2019-10-17 11:13:08 -06:00
rick olson
2c4087d78f gh actions: skip rubocop and yard linting on faraday 0.1x related branches 2019-10-17 11:07:15 -06:00
risk danger olson
520e3578d4
Merge pull request #1023 from lostisland/cleanup-adapter-connections
Cleanup adapter connections
2019-10-17 10:39:24 -06:00
rick olson
c82135056b lint: Layout/EmptyLines, Style/BracesAroundHashParameters 2019-10-17 10:26:12 -06:00
rick olson
b1b617e53f Correct documentation to show #connection returns the block return value.
This is so that it returns an HTTP response object from the client lib.
2019-10-17 10:24:03 -06:00
rick olson
0294fed33c Forgot to git-add these 2019-10-17 10:23:28 -06:00
rick olson
43cd327f19 Merge branch 'master' into cleanup-adapter-connections
Update for latest #request_timeout changes.
2019-10-17 10:19:03 -06:00
risk danger olson
9e4fa74515
Merge pull request #1022 from lostisland/springerigor-read-timeout-request-option
read timeout request option (part 2)
2019-10-17 10:09:34 -06:00
rick olson
68c53c448f prefer Hash#fetch 2019-10-17 10:05:09 -06:00
Mattia
48e6c3f820
Merge branch 'master' into springerigor-read-timeout-request-option 2019-10-17 11:26:41 +01:00
Bobby McDonald
e331955fd8 Fix instances of frozen empty string literals (#1040) 2019-10-17 11:25:15 +01:00
Mattia
b5bbf1f2d2
Improves CI workflow
* Allow CC test reporter step to fail (currently not working on fork)
* Only trigger workflow for pushes against master
2019-10-17 11:17:22 +01:00
Mattia
9de70e0184
Merge branch 'master' into springerigor-read-timeout-request-option 2019-10-17 11:02:23 +01:00
Mattia
9c3b8f40cb
Adds pull_request to events triggering the CI 2019-10-17 10:55:31 +01:00
risk danger olson
993a483ec3
Merge pull request #1053 from lostisland/raise-error-nil
Raise error nil
2019-10-16 10:42:20 -06:00
risk danger olson
c844e4c53e
Merge branch 'master' into raise-error-nil 2019-10-16 10:35:24 -06:00
Mattia
e78a1e022a
Merge branch 'master' into cleanup-adapter-connections 2019-10-16 10:59:18 +01:00
Mattia
708ca5b9ab
Use GitHub Actions for CI (#1051) 2019-10-16 10:57:42 +01:00
rick olson
f7f91b7077 raise_error: update docs to mention nil status code 2019-10-15 13:37:41 -06:00
rick olson
232ec3892e the nil status is extremely rare, so check it last 2019-10-15 13:23:33 -06:00
risk danger olson
a91581a04e
Update lib/faraday/adapter/net_http.rb
Co-Authored-By: Olle Jonsson <olle.jonsson@gmail.com>
2019-10-15 10:35:10 -06:00
risk danger olson
296f336b62
Update lib/faraday/adapter/net_http.rb
Co-Authored-By: Olle Jonsson <olle.jonsson@gmail.com>
2019-10-15 10:35:03 -06:00
Jonny
07ddcb93f5 Pass the exception correctly 2019-10-15 10:26:10 -06:00
Michael Herold
72b917c8be Raise exception on nil status 2019-10-15 10:26:06 -06:00
rick olson
83d933a61e fix bad merge 2019-10-14 14:35:14 -06:00
rick olson
75b9804e33 unused 2019-10-14 14:21:19 -06:00
rick olson
18c204e3a5 lint fixes 2019-10-14 14:18:03 -06:00
risk danger olson
edcbd9f8e4
Merge branch 'master' into cleanup-adapter-connections 2019-10-14 14:13:02 -06:00
rick olson
b85589c72a Merge branch 'master' into springerigor-read-timeout-request-option 2019-10-14 14:08:02 -06:00
rick olson
0aea513d72 teach rack adapter to use #request_timeout 2019-10-14 14:07:42 -06:00
rick olson
6394bc08a5 teach patron adapter how to use #request_timeout 2019-10-14 14:06:07 -06:00
rick olson
711c257295 teach httpclient adapter how to use #request_timeout 2019-10-14 14:03:29 -06:00
rick olson
55c0b742ec test current httpclient timeout behavior 2019-10-14 11:19:48 -06:00
Stanisław Pitucha
cccc145e2f Describe clearing cached stubs
This was the solution proposed in https://github.com/lostisland/faraday/issues/1041
2019-10-07 19:48:59 +02:00
Orien Madgwick
940e01ce38 Add project metadata to the gemspec (#1046)
As per https://guides.rubygems.org/specification-reference/#metadata,
add metadata to the gemspec file. This'll allow people to more easily
access the source code, raise issues and read the changelog. These
`bug_tracker_uri`, `changelog_uri`, `documentation_uri`, `wiki_uri` and
`source_code_uri` links will appear on the rubygems page at
https://rubygems.org/gems/faraday and be available via the rubygems
API after the next release.
2019-10-07 19:21:28 +02:00
Olle Jonsson
6c7bf772b9 Rubocop: Lint/SendWithMixinArgument (#1047)
Same as 0ac691abaf1f78185f025ea8c8711f3970b49ebc, credits to @BobbyMcWho
2019-10-07 17:54:17 +01:00
risk danger olson
dcae077607
Merge pull request #1029 from lostisland/rel-v0.16.0
release v0.16.0
2019-09-27 10:34:02 -06:00
rick olson
9882080737 release v0.16.0 2019-09-27 10:26:47 -06:00
risk danger olson
435e45b154
Merge pull request #1000 from lostisland/add-testing-examples
Add testing examples
2019-09-22 09:50:58 -06:00
risk danger olson
872a249fa7
Excon streaming (#1026)
* implement excon streaming

* trust that excon will return empty body on streamed responses

* track total byte size ourselves

* the extra args are needed
2019-09-22 09:43:18 -06:00
rick olson
f8615d5255 net_http and net_http_persistent share _some_ config code 2019-09-20 07:30:21 -06:00
rick olson
ba7b82d9a2 lint: fix alignment and rescue stmt 2019-09-20 05:32:14 -06:00
risk danger olson
80ba52c721
update multipart docs to mention ParamPart class (#1018)
* update multipart docs to mention ParamsPart class

* Use newer "FilePart" name

* annotate example

* Consistently use single quotes

* remove last UploadIO reference
2019-09-20 05:08:56 -06:00
rick olson
bfe360a0a7 Refactor patron adapter to use #connection 2019-09-20 04:25:02 -06:00
rick olson
bfdb66ab71 Refactor httpclient adapter to use #connection 2019-09-19 20:44:18 -06:00
rick olson
86d3cf2e8b Refactor excon adapter to use #connection 2019-09-19 20:38:20 -06:00
rick olson
36ff4a5c3e Refactor net_http and net_http_persistent adapters to use #connection 2019-09-19 20:26:26 -06:00
rick olson
b35f6a2480 RequestOptions#fetch_timeout => Adapter#request_timeout
This allows adapter internals and specs to treat request options as a 
plain hash.
2019-09-19 16:39:39 -06:00
rick olson
8dae875906 lint 2019-09-19 16:05:06 -06:00
rick olson
a5a398c231 teach Excon to use #fetch_timeout 2019-09-19 15:50:50 -06:00
rick olson
6c117f47b9 test current Excon timeout config 2019-09-19 15:50:25 -06:00
rick olson
24cf49c216 teach EMHttp adapter to use #fetch_timeout 2019-09-19 15:40:36 -06:00
rick olson
abade0d453 test current EMHttp timeout config 2019-09-19 15:32:22 -06:00
rick olson
dbe4fae178 teach Faraday::RequestOptions to get the correct timeout configuration 2019-09-19 12:20:45 -06:00
rick olson
956c53f99a space things out a bit 2019-09-19 12:01:00 -06:00
rick olson
3575ad6485 Merge branch 'read-timeout-request-option' of https://github.com/springerigor/faraday into springerigor-read-timeout-request-option 2019-09-19 12:00:09 -06:00
risk danger olson
b863c167d6
Merge pull request #1021 from lostisland/upload_io_file_part
Rename UploadIO -> FilePart
2019-09-19 11:38:01 -06:00
rick olson
c0c911d0ee properly indent @param tags 2019-09-18 14:50:54 -06:00
rick olson
c3bbb16dd3 remove class scope decl 2019-09-18 14:43:53 -06:00
rick olson
df8b15e720 move the Faraday::ParamPart#initialize yard desc to the class 2019-09-18 14:42:01 -06:00
rick olson
6fdc48e163 add specs for FilePart 2019-09-18 14:25:21 -06:00
rick olson
249835f8b6 add alias Faraday::FilePart for older Faraday::UploadIO 2019-09-18 14:18:14 -06:00
risk danger olson
1418454f04
Merge pull request #1017 from trainline-eu/add-part-params-class-to-allow-multipart-posts-with-json-content-and-file-upload
Create PartParams class to allow multipart posts with JSON content and file upload at the same time
2019-09-17 13:30:04 -06:00
Jeremy ISRAEL
7dded89b33 Create PartParams class to allow multipart posts with JSON content and IO content in the same request 2019-09-17 10:29:22 +02:00
Aaron Patterson
f4ae96ea9b This fixes warnings on Ruby 2.7 (#1009) 2019-08-15 22:17:16 +01:00
risk danger olson
e8792e43d5 port changes from #1000 (#1004) 2019-07-19 14:11:30 +02:00
rick olson
f825112db3 remove debugging code 2019-07-18 14:32:26 -06:00
rick olson
e1c71d4d57 whats up with webmock and patron 2019-07-18 14:10:53 -06:00
rick olson
ffbc597146 fix rubocop issues in examples 2019-07-18 13:45:59 -06:00
rick olson
d0ed8f891f describe stub request response, add exception example 2019-07-18 12:51:19 -06:00
rick olson
8e31ce1684 fix pointers to example files 2019-07-18 12:51:02 -06:00
rick olson
90122910d1 isolate examples from rspec test suite run in ci 2019-07-18 12:48:34 -06:00
rick olson
25c4791791 add example testing exception 2019-07-18 12:00:09 -06:00
risk danger olson
8d2eb3c079
Update docs/adapters/testing.md
Co-Authored-By: Olle Jonsson <olle.jonsson@gmail.com>
2019-07-18 10:30:51 -06:00
risk danger olson
fff3227cee
Update docs/adapters/testing.md
Co-Authored-By: Olle Jonsson <olle.jonsson@gmail.com>
2019-07-18 10:30:43 -06:00
risk danger olson
52b260112a
Update spec/examples/client_spec.rb
Co-Authored-By: Olle Jonsson <olle.jonsson@gmail.com>
2019-07-18 10:30:31 -06:00
Igor Springer
25979431e4 Add support for setting Ruby Net::HTTP read_timeout option separately
Right now `timeout` setting sets all the timeout values (`read`, `open` & `write` if available). To unify the API with `Net::HTTP` one (which has a dedicated method for `read_timeout` as well) I propose extending the `RequestOptions` by `read_timeout`.
2019-07-18 11:03:58 +02:00
rick olson
4a2d1e6b3d so picky 2019-07-10 10:35:21 -06:00
rick olson
d8ccce2bc0 show example of testing the env object too 2019-07-10 10:34:50 -06:00
rick olson
8b71ba3320 let it goooooo 2019-07-10 10:29:53 -06:00
rick olson
bbb015b500 let it go 2019-07-10 10:19:56 -06:00
rick olson
657b0231f8 Link directly to the blob pages on github 2019-07-10 10:05:18 -06:00
rick olson
869cf338de add test/unit and rspec test examples 2019-07-10 10:00:34 -06:00
Lewis Cowles
ac27ce502e Configure Jekyll plugin jekyll-remote-theme to support Docker usage (#999)
I tried to build with Jekyll 3.6.x (`jekyll/jekyll:latest`). It went badly.

By following the author guide https://github.com/benbalter/jekyll-remote-theme I noticed we were missing a YAML configuration entry.
2019-07-09 22:05:10 +02:00
risk danger olson
8fa2b46196
Merge pull request #994 from lostisland/fix/website-navigation
Website Navigation Fix
2019-07-08 12:07:02 -06:00
risk danger olson
8585604508
Merge pull request #995 from lostisland/fix-options-inspect
teach #inspect how to build string without appending to a frozen string
2019-07-08 12:06:24 -06:00
rick olson
432fcd267d fix test 2019-07-08 11:55:56 -06:00
iMacTia
0ec66e8959 Fixes website navigation by adding trailing slashes to /index.md files.
See https://stackoverflow.com/questions/54727643/trailing-slashes-in-jekyll-github-pages-site-cause-404
2019-07-08 18:45:46 +01:00
rick olson
70764fb34e teach #inspect how to build string without appending to a frozen string 2019-07-08 11:43:19 -06:00
risk danger olson
7eae1cbf23
Merge pull request #993 from lostisland/prep-1.0-rc1
Ship 1.0.0-rc1
2019-07-08 11:30:13 -06:00
rick olson
2a2a0ebfe5 Merge branch 'master' into prep-1.0-rc1 2019-07-08 11:14:20 -06:00
risk danger olson
a285d7a8b6
Merge pull request #982 from lostisland/faraday-website
Faraday Website
2019-07-08 11:11:59 -06:00
rick olson
26c542d9e1 fix the order of the site nav 2019-07-02 07:43:06 -06:00
iMacTia
6cd8c5dc35 Fixes placeholders for Faraday website URL. 2019-06-27 15:47:06 +01:00
iMacTia
0826817f4e Switches back to standard theme. 2019-06-26 12:08:20 +01:00
iMacTia
5d3e667c1a Merge branch 'faraday-website' of https://github.com/lostisland/faraday into faraday-website 2019-06-26 09:54:16 +01:00
iMacTia
9070f6bf2e Fixes homepage title. 2019-06-26 09:53:44 +01:00
rick olson
275d1e3daa bump version to 1.0.0-rc1 2019-06-25 10:57:44 -06:00
rick olson
62cbdb9d78 restructure adapters section:
* more prominent placing of test adapter
* remove next/prev navigation for adapter pages, they don't need to be read in order
* ensure all adapter pages link to top nav
2019-06-25 10:28:14 -06:00
rick olson
08cd1b3be9 top links to middleware pages 2019-06-25 10:09:12 -06:00
rick olson
caf7545906 add top links to usage pages 2019-06-25 10:07:43 -06:00
rick olson
75605b9c36 remove redundant sitemap 2019-06-25 09:59:18 -06:00
rick olson
2f96d9b3a7 rename Introduction section => to Usage 2019-06-25 09:38:52 -06:00
iMacTia
cf078cf20b Adds Elena contribution to team page and footer.
Aligns README footer with Website one.
2019-06-25 16:31:51 +01:00
iMacTia
94a78e7eba Fix alt-img typo in README. 2019-06-25 15:56:33 +01:00
iMacTia
637c81196b Use slim repo card in README. 2019-06-25 15:54:32 +01:00
iMacTia
5cf6753e60 Merge remote-tracking branch 'origin/faraday-website' into faraday-website 2019-06-18 17:57:40 +01:00
iMacTia
a50fcc413b Adds Team page with dynamic GitHub loading.
Styles website with new branding.
2019-06-18 17:57:27 +01:00
rick olson
32be8ce245 redundant title 2019-06-13 09:32:14 -06:00
rick olson
a8295c2c4a use conn local var 2019-06-13 09:31:36 -06:00
rick olson
5ca8630d9b use consistent url hints 2019-06-13 09:31:20 -06:00
rick olson
112331a325 use consistent "learn more" callouts with punctuation 2019-06-13 09:30:52 -06:00
iMacTia
32eacfd4ee Expands menu items. 2019-06-08 17:38:58 +01:00
iMacTia
a963c12a82 Fixes TODOs in introduction. 2019-06-08 17:32:19 +01:00
iMacTia
f851834ccd Merges Introduction and Basics pages.
Adds navigation to introduction section.
2019-06-08 17:29:03 +01:00
iMacTia
8434b225a1 Fixes link in homepage. 2019-06-08 17:23:46 +01:00
iMacTia
f1d72a4cdf Adds navigation to adapters section. 2019-06-08 17:19:00 +01:00
iMacTia
79da580283 Improves middleware documentation adding a diagram. 2019-06-08 17:05:44 +01:00
rick olson
681b6baa33 convert to regular markdown link 2019-06-05 15:24:37 -06:00
rick olson
31d03bec46 rewrite basics page. focus on making requests, not middleware. 2019-06-05 15:22:41 -06:00
iMacTia
78fd49eecf Use Font Awesome icons for docs nav. 2019-06-04 17:50:30 +01:00
iMacTia
069b422750 Reduces the amount of comments in code snippets. 2019-06-04 17:09:14 +01:00
iMacTia
9f99e11596 Fixes review comments. 2019-06-03 21:42:12 +01:00
risk danger olson
1c3bf50d8a
rdoc: fix type info for SSLOptions (#990) 2019-06-03 13:47:52 -04:00
iMacTia
caa877dc83 Fixes documentation nav menu to always use correct floating. 2019-06-02 15:13:44 +01:00
iMacTia
4400acfd2b Introduces documentation layout with bottom navigation links. 2019-06-02 15:09:35 +01:00
iMacTia
a2becaaf6a Adds instrumentation middleware page. 2019-05-29 17:29:47 +01:00
iMacTia
1a2970eba0 Adds retry middleware page. 2019-05-29 17:00:15 +01:00
iMacTia
86fd91cf04 Merge remote-tracking branch 'origin/faraday-website' into faraday-website
# Conflicts:
#	docs/introduction/customize.md
2019-05-28 16:26:51 +01:00
iMacTia
eb9660a818 Adds multipart and url_encoded middleware pages. 2019-05-28 16:26:16 +01:00
Olle Jonsson
eb80f9aa26 Faraday website edits (#987) 2019-05-26 17:44:05 +01:00
iMacTia
d5906c100a Adds documentation for RaiseError middleware. 2019-05-26 15:32:53 +01:00
iMacTia
ad9a3965ee Merge branch 'master' of https://github.com/lostisland/faraday into faraday-website 2019-05-24 21:20:20 +01:00
Damir Gainetdinov
d76489a062 Fix a typo in raise_error spec description (#983) 2019-05-24 14:41:42 +02:00
iMacTia
06e364d998 Adds docs/README.md with instrucitons on how to run the Faraday Website on Jekyll. 2019-05-24 12:51:31 +01:00
iMacTia
75f3ca2443 Updates CONTRIBUTING guide including instrucitons on how to run the Faraday Website on Jekyll. 2019-05-24 11:56:43 +01:00
iMacTia
f97523dbf1 Removes last bits from README 2019-05-23 18:51:08 +01:00
iMacTia
c17f918425 Removes Travis link from README 2019-05-23 18:39:53 +01:00
iMacTia
3acd1c8d31 Moves README tutorials into separate pages. 2019-05-23 18:30:14 +01:00
iMacTia
f0b780f822 Merge branch 'master' of https://github.com/lostisland/faraday into faraday-website 2019-05-23 17:05:03 +01:00
iMacTia
1818542ab7 Fixes Rubocop in master. 2019-05-23 16:57:46 +01:00
iMacTia
bd8d044507 Fixes test not working with Net::HTTP::Persistent 3.0.1 2019-05-23 16:56:03 +01:00
iMacTia
1a9312ce82 Merge branch 'master' of https://github.com/lostisland/faraday into faraday-website 2019-05-23 11:04:10 +01:00
iMacTia
d4f062a56b Use latest rubocop version like CircleCI. 2019-05-23 11:02:59 +01:00
iMacTia
9214d0b8ee Use latest rubocop version like CircleCI. 2019-05-23 10:58:26 +01:00
iMacTia
11f27d2214 Rubocop fixes. 2019-05-23 10:52:09 +01:00
iMacTia
06b4fac02b Merge branch 'master' of https://github.com/lostisland/faraday into faraday-website 2019-05-23 10:40:49 +01:00
lucasmoreno
91ba32e9d2 Introduces Faraday::ConflictError for 409 response code (#979) 2019-05-23 10:35:21 +01:00
iMacTia
43233f5766 Merge branch 'master' of https://github.com/lostisland/faraday into faraday-website
# Conflicts:
#	README.md
2019-05-21 22:18:35 +01:00
KevinKawai
7af105dabf Update license valid through year (#981) 2019-05-21 22:16:41 +01:00
iMacTia
66384d32dd Merges #970.
Adds table of content to homepage.
Adds details page for logger middleware.
2019-05-19 17:41:27 +01:00
iMacTia
8e89cab029 Merge branch 'expand-readme-2' of https://github.com/lostisland/faraday into faraday-website 2019-05-19 15:10:44 +01:00
iMacTia
7ad1bcd2ed Adds style override files.
Introduces styling for buttons.
2019-05-13 11:16:18 +01:00
iMacTia
272de2e480 Removes unused nav.yml
Renames About page into Team
2019-05-12 10:54:55 +01:00
Mattia
a217471dc6
Explain Absolute path behaviour in README (#977)
Updates the REAME to explain how the absolute path overrides the one provided while initialising the connection.
Fixes #976
2019-05-12 10:18:27 +01:00
Tomas Sandven
3abe9d1eea README: Fixed a code typo (#975) 2019-04-27 19:44:00 +02:00
iMacTia
9265247834 Modifies existing adapters doc to support jekyll options.
Switches theme.
2019-04-20 12:09:12 +02:00
Olle Jonsson
be097190e9
Refactor: Extract repeated calls to a shared map (#973)
* Extract repeated calls to a shared map

* Spec for net_http_persistent min_version

* Use realistic value in a spec
2019-04-14 20:51:52 +02:00
iMacTia
4b63db64a0 Merge branch 'master' of https://github.com/lostisland/faraday into faraday-website 2019-04-14 16:23:36 +01:00
Olle Jonsson
8a65a58de8
Merge pull request #972 from bdewater/net-http-persistent-ssl-minmax-version
Allow setting min/max SSL version for a Net::HTTP::Persistent connection
2019-04-14 09:02:33 +02:00
Bart de Water
b4a27f3734 Allow setting min/max SSL version for a Net::HTTP::Persistent connection 2019-04-13 19:17:59 -04:00
Olle Jonsson
980a9514e0
[ci skip] Add missing "you" 2019-04-12 21:33:51 +02:00
risk danger olson
84200628ee
expose the gemfile.lock file in CircleCI (#971) 2019-04-10 16:18:42 -06:00
rick olson
07788ab977 finish testing, and start listing docs in readme 2019-04-10 12:05:53 -06:00
rick olson
d9ec3a5f48 add new pages for testing, the env, and middleware usage 2019-04-10 11:36:59 -06:00
Olle Jonsson
03a0217354
RuboCop TODO update (#968) 2019-04-08 21:59:10 +02:00
risk danger olson
71c78694d4
CI: yard junk (#958)
* run yard-junk during ci

* better indentation

* create test-results/yard

* wat

* waat

* try this

* or this

* does that dir exist

* combine rubocop and yard-junk into single linting task

* dump to stdout

* create linting dir

* test-results does not exist

* persist test-results too

* cant persist HOME

* create test-results subdirs in the container that uses them

* dont care
2019-04-08 13:13:32 -06:00
Olle Jonsson
c8cf1ac535
Merge pull request #967 from lostisland/rubocop-use-performance-gem
Rubocop: use performance gem
2019-04-08 21:09:14 +02:00
risk danger olson
b9a7560f72
Merge pull request #964 from lostisland/multipart-content-disposition-test
use multipart-parser gem in multipart tests
2019-04-08 12:47:20 -06:00
Olle Jonsson
7c9a322b0d Add --require to RuboCop configuration 2019-04-08 20:42:31 +02:00
Olle Jonsson
7280a3803d Lint Style/IfUnlessModifier 2019-04-08 20:42:10 +02:00
Olle Jonsson
d91a5f4567 CI: use rubocop-performance gem 2019-04-08 20:40:55 +02:00
Olle Jonsson
def850b619 Lint Naming/RescuedExceptionsVariableName 2019-04-08 20:39:24 +02:00
Olle Jonsson
e74dbad644 Gemfile: Add rubocop-performance gem, update rubocop 2019-04-08 20:31:33 +02:00
Olle Jonsson
f6ee27d0c7
Merge pull request #966 from lostisland/expand-readme
Expand readme
2019-04-08 20:00:25 +02:00
rick olson
aa125e1bc1 add em adapter docs 2019-04-03 09:53:53 -06:00
rick olson
39058484d4 extract httpclient docs 2019-04-01 16:53:02 -06:00
rick olson
522b0d595d extract excon docs 2019-04-01 16:47:51 -06:00
rick olson
913583ff11 extract patron docs 2019-04-01 16:24:59 -06:00
rick olson
5d62e6f70f link to the net/http docs page 2019-04-01 16:21:59 -06:00
rick olson
e4f41053a0 extract net/http docs 2019-04-01 16:21:09 -06:00
rick olson
17b576ef12 extract net-http-persistent docs 2019-04-01 16:12:19 -06:00
rick olson
bd684191dd small tweaks 2019-04-01 16:12:05 -06:00
risk danger olson
a8cd68e18f
Merge pull request #959 from lostisland/docs-connection-overload
document both uses of Connection#options
2019-04-01 15:41:08 -06:00
rick olson
474b2b690f monkeypatch no longer necessary 2019-04-01 15:14:08 -06:00
rick olson
e54c86a6ce use multipart-parser gem in multipart tests 2019-04-01 15:11:56 -06:00
risk danger olson
8230d11214
Merge pull request #963 from lostisland/trim-gemfile
remove test/unit related gems
2019-04-01 09:58:12 -06:00
rick olson
1fa623b35a remove test/unit related gems 2019-03-31 14:13:04 -06:00
risk danger olson
cda3a0171d
Merge pull request #962 from lostisland/memoized-wo-block
Fix Memoized w/o block
2019-03-31 13:51:34 -06:00
rick olson
34bf23ae40 feed rubocop 2019-03-31 13:42:02 -06:00
rick olson
7aa80e21b9 stop relying on surprising Proc.new behavior
this raises a warning in ruby 2.7.0
https://docs.ruby-lang.org/en/trunk/NEWS.html
2019-03-31 13:39:21 -06:00
rick olson
342c2e4eb8 raise ArgumentError if Faraday::Options.memoized is called w/o a block 2019-03-31 13:28:25 -06:00
risk danger olson
ef8d9eb2bc
Merge pull request #957 from lostisland/docs-retry-arg
document missing `:retry_statuses` argument
2019-03-30 08:52:31 -06:00
rick olson
4656ca4283 document both uses of Connection#options 2019-03-29 16:03:05 -06:00
rick olson
d986824c32 i've determined there's a spelling mistake here 2019-03-29 14:51:43 -06:00
rick olson
e2c07759de document missing argument 2019-03-29 14:50:45 -06:00
risk danger olson
5063ffe963 rubocop: fix Style/Documentation offenses (#951)
* rubocop: fix Style/Documentation offenses

* no test dir

* use @see tag

* put @example after @params, before @return
2019-03-21 09:40:49 +01:00
risk danger olson
ffc6911ed3
Merge pull request #948 from lostisland/document-example
[documentation] RackBuilder example, params
2019-03-20 16:34:33 -06:00
rick olson
e500ccd42d Merge branch 'master' into document-example 2019-03-20 16:27:34 -06:00
risk danger olson
d16ea15626
Merge pull request #952 from lostisland/rubocop-0.66
Rubocop 0.66
2019-03-20 16:26:38 -06:00
rick olson
9e29d03f63 prefer Lint/SafeNavigationWithEmpty 2019-03-20 13:29:27 -06:00
rick olson
6394090d1b ignore more weird const names 2019-03-20 13:27:52 -06:00
rick olson
6167052fc7 Execute Order 66.
A manual version tweak in the Gemfile is required because rubocop 
updated its 
unicode-display_width dependency version:
* OLD - '~> 1.4.0'
* NEW - '< 1.6, >= 1.4.0'
Bundler wanted to install v1.5.0 for rubocop v0.66, but fails to update 
rubocop
because unicode-display_width v1.5.0 will not work with rubocop v0.65.
2019-03-20 13:27:31 -06:00
rick olson
a2161e10a8 remove sinatra from gemspec, only used for live http tests 2019-03-20 13:23:35 -06:00
Olle Jonsson
5b924852fb YARD comment for RackBuilder example 2019-03-18 14:46:33 +01:00
Mattia
6f0168b20b Setup CodeClimate TestReporter on CircleCI (#945)
* CircleCI now runs CodeClimate TestReporter only on Ruby2.6

* Expects simplecov report instead of clover
2019-03-14 07:25:01 +01:00
iMacTia
f50de1c6ed Initial setup of Jekyll for github-pages website 2019-03-12 14:09:53 +00:00
Ted Johansson
88698363fd Chore: RuboCop Style/MultipleComparison (#923) 2019-03-11 20:59:09 +00:00
Mattia
224dd98ebe Update badges in README.md (#942)
Update Test coverage and Maintainability badges in README.md
2019-03-10 11:02:58 +01:00
Mattia
14b596fd30 Support standalone adapters (#941)
* Expose relevant specs to external adapters
2019-03-10 11:02:19 +01:00
Geoff Hubbard
6ff61c0ecc chore: RuboCop lint Style/Globalvars (#943) 2019-03-09 13:23:48 +00:00
Olle Jonsson
c8c9a0217c README: Add CircleCI badge (#940) 2019-03-09 10:21:56 +00:00
Olle Jonsson
0a47c7b115
CI: CircleCI configuration (#935)
* CI: CircleCI example

* README: Drop Travis CI badge

* NetHttp adapter: include EADDRNOTAVAIL, too

  - this is about connections failing in JRuby tests

* HttpClient adapter: add EADDRNOTAVAIL failing in JRuby tests

* CI: deploy on Git tags

* CI: Try adding JRuby 9.2

* CI: add JRUBY_OPTS=--debug

* CI: Add RspecJunitFormatter

* CI: Identify Test Results via directory names

* CI: Use valid config YAML

* CI: Call rspec CLI

* CI: YAML alias to share steps

* CI: Drop Travis configuration file
2019-03-08 20:03:42 +01:00
Olle Jonsson
a1f698ef44 CI: Drop Travis configuration file 2019-03-08 19:35:38 +01:00
Olle Jonsson
c5632466d9 CI: Avoid bad cache 2019-03-08 19:34:49 +01:00
Olle Jonsson
752b67cad4 CI: YAML alias to share steps 2019-03-08 19:32:54 +01:00
Olle Jonsson
e955e55cb7 CI: Call rspec CLI
- Rakefile: remove CI-specific detail
2019-03-08 19:25:05 +01:00
Olle Jonsson
94a26eb1a8
Merge branch 'master' into use-circleci 2019-03-08 18:46:32 +01:00
risk danger olson
bd322bba6b chore: rubocop lint Metrics/LineLength (#938) 2019-03-08 17:45:12 +00:00
Mattia
4102f3add4
Removes legacy tests as replaced by RSpec (#939) 2019-03-08 11:00:56 +00:00
Mattia
626d68f6ff
Adds rack adapter to RSpec tests (#937) 2019-03-07 23:18:29 +00:00
Olle Jonsson
82c82a9a8f CI: disable JRuby 2019-03-07 22:47:01 +01:00
risk danger olson
c58723d028
Merge pull request #933 from lostisland/rubocop-style-classvars
Rubocop: style/classvars
2019-03-07 10:47:38 -07:00
rick olson
490ee83ddf Merge branch 'master' into rubocop-style-classvars 2019-03-07 10:37:20 -07:00
rick olson
4d88475295 remove #constantize use and unnecessary nil checks 2019-03-07 10:28:55 -07:00
Mattia
609d1768cb
Adds em-synchrony adapter to RSpec tests (#936) 2019-03-07 13:23:41 +00:00
Olle Jonsson
385203be78 CI: Use valid config YAML 2019-03-06 22:04:48 +01:00
Olle Jonsson
780222e1ec CI: Identify Test Results via directory names 2019-03-06 22:02:14 +01:00
Olle Jonsson
e84d1653b7 Linting 2019-03-06 21:57:08 +01:00
Olle Jonsson
5b97393d2b CI: Add RspecJunitFormatter to RSpec rake task 2019-03-06 21:56:14 +01:00
Olle Jonsson
96047c855b CI: add JRUBY_OPTS=--debug 2019-03-06 21:04:14 +01:00
Olle Jonsson
0d3e566f68 CI: Try adding JRuby 9.2 2019-03-06 21:00:38 +01:00
Olle Jonsson
ea1142a4a2 CI: deploy on Git tags 2019-03-06 20:52:30 +01:00
Olle Jonsson
338de4d938 HttpClient adapter: add EADDRNOTAVAIL 2019-03-06 19:53:20 +01:00
Olle Jonsson
148b99ee0f NetHttp adapter: include EADDRNOTAVAIL, too
- this is about connections failing, an experiment
2019-03-06 19:50:23 +01:00
rick olson
726de4a186 use a descriptive variable name 2019-03-06 11:23:52 -07:00
Olle Jonsson
2730f1247a README: Drop Travis CI badge 2019-03-06 18:22:20 +01:00
Olle Jonsson
f6e8d7ad58 CI: CircleCI example 2019-03-06 18:14:58 +01:00
rick olson
907c5190b1 add AdapterRegistry spec 2019-03-06 10:14:10 -07:00
rick olson
73747c66b7 Merge branch 'master' into rubocop-style-classvars 2019-03-06 09:30:09 -07:00
risk danger olson
c801391d18
Merge pull request #932 from lostisland/em-http-tests
Adds em-http adapter to RSpec tests
2019-03-06 09:29:15 -07:00
Sergey Prikhodko
1d3d675821 Add the log formatter that is easy to override and safe to inherit (#889) 2019-03-06 16:13:14 +00:00
iMacTia
04dff67cfa Fixes an issue with macOS require order. 2019-03-06 09:20:47 +00:00
iMacTia
28e995d9c6 Merge branch 'master' of https://github.com/lostisland/faraday into em-http-tests
# Conflicts:
#	spec/spec_helper.rb
2019-03-06 08:53:40 +00:00
Geoff Hubbard
b9ea1d92ce Accurate test code coverage percentage (#934) 2019-03-06 08:46:51 +00:00
rick olson
00cbb94f3d chore: update rubocop_todo 2019-03-05 11:38:44 -07:00
rick olson
5f276b36fa replace @@classvars with AdapterRegistry usage 2019-03-05 11:38:24 -07:00
rick olson
dcb7030289 always require 'monitor' since it's used by AdapterRegistry too. 2019-03-05 11:38:07 -07:00
rick olson
e8382421aa reimplement const-lookup from Faraday::RackBuilder::Handler 2019-03-05 11:37:42 -07:00
rick olson
04b90eb43e chore: replace class vars with class instance var
probably unnecessary since the integration test suite is going away
2019-03-05 11:33:15 -07:00
iMacTia
ab33c8ace1 Adds em-http adapter to RSpec tests 2019-03-05 18:26:46 +00:00
Mattia
ded4f6ef9a
Fixes Rubocop Style/GuardClause (#931) 2019-03-05 12:25:15 +00:00
Geoff Hubbard
e342992751 chore: Rubocop lint Style/MissingRespondToMissing (#930) 2019-03-04 23:25:25 +01:00
Geoff Hubbard
dbba0734d6 Fix test order dependency in default_connection proxy test (#929)
* Fix the default_connection proxy test

The assignment to the mock connection:

`Faraday.default_connection = mock_connection`

was persisting throughout the tests.

If the random number generator is unlucky the following error occurs:

\#<Double "Connection"> was originally created in one example but has leaked into another example and can no longer be used.  rspec-mocks' doubles are designed to only last for one example, and you need to create a new one in each example you wish to use it for.

This commit fixes the issue by explicitly setting the default_connection
back to nil in an "after" block after the tests have run.

Subsequent calls to `default_connection` within the test suite then
behave as previously expected irrespective of the random test ordering.
2019-03-04 23:16:10 +01:00
Geoff Hubbard
c5ceb2679c chore: RuboCop lint Style/MethodMissingSuper (#928) 2019-03-04 21:07:33 +00:00
Mattia
6b0eb71322
chore: RuboCop lint Metrics/BlockLength (#927) 2019-03-04 21:02:46 +00:00
Mattia
ef4044281d chore: RuboCop lint Style/IfUnlessModifier (#926)
* Fixes Rubocop Style/IfUnlessModifier

* Update lib/faraday/adapter/httpclient.rb

Co-Authored-By: iMacTia <iMacTia@users.noreply.github.com>

* Update lib/faraday/request/retry.rb

Co-Authored-By: iMacTia <iMacTia@users.noreply.github.com>
2019-03-04 14:49:25 +01:00
Olle Jonsson
8ba22d5da2
Merge pull request #925 from lostisland/fix/rubocop-style-m
chore: RuboCop lint Style/M*
2019-03-04 14:23:41 +01:00
iMacTia
2a04aeadb3 Fixes Rubocop Style/ModuleFunction 2019-03-04 13:01:46 +00:00
iMacTia
f3e9adba3b Fixes Rubocop Style/MutableConstant 2019-03-04 12:55:20 +00:00
Ted Johansson
5b49e6c9b2 Chore: RuboCop Style/MultilineIfModifier (#924) 2019-03-04 08:40:44 +01:00
Olle Jonsson
c209c41da6
RuboCop rule: Allow !! (#922)
* RuboCop rule: Allow !!

* chore: Regenerate RuboCop TODO
2019-03-03 23:27:34 +01:00
Mattia
fb21e2db1a chore: RuboCop lint Style/N* (#921)
* Fixes Rubocop Style/NumericPredicate

* Fixes Rubocop Style/NilComparison
2019-03-03 22:40:17 +01:00
Olle Jonsson
1a7ce3e367
Merge pull request #920 from lostisland/fix/rubocop-style-p
chore: RuboCop lint Style/P*
2019-03-03 20:36:28 +01:00
Olle Jonsson
8140cba74c Drop scripts/release, scripts/package (#919)
* Drop scripts/release
  - GitHub Releases are used to create and annotate tags
  - Travis CI publishes and pushes gems

* Drop script/package
2019-03-03 19:30:40 +00:00
Olle Jonsson
af1c1b5bb6 Drop auto-generated bin/ (#918) 2019-03-03 19:26:18 +00:00
iMacTia
f8f5985f3e Fixes Rubocop Style/ParallelAssignment 2019-03-03 19:23:46 +00:00
iMacTia
376eb2307a Fixes Rubocop Style/ParenthesesAroundCondition 2019-03-03 19:21:51 +00:00
iMacTia
49073081c8 Fixes Rubocop Style/PerlBackrefs 2019-03-03 19:20:53 +00:00
iMacTia
cfb80e55af Fixes Rubocop Style/PreferredHashMethods 2019-03-03 19:19:36 +00:00
iMacTia
5d4ed5e401 Fixes Rubocop Style/Proc 2019-03-03 19:08:54 +00:00
Olle Jonsson
b80111bed5 Excon adapter: extract methods (#916) 2019-03-03 19:00:49 +00:00
htwroclau
1fe9763c19 chore: Fix RuboCop Style/IfInsideElse (#915) 2019-03-03 18:38:56 +01:00
Olle Jonsson
1c0f43b9fd chore: RuboCop lint Style/MultilineTernaryOperator (#913) 2019-03-03 16:42:31 +00:00
htwroclau
801f7d517e chore: Fix RuboCop Style/FormatStringToken (#914) 2019-03-03 13:08:08 +01:00
Mattia
d657e3d3c3 chore: RuboCop lints Style/R* (#910)
* Fixes Rubocop Style/RescueStandardError

* Fixes Rubocop Style/RegexpLiteral

* Fixes Rubocop Style/RaiseArgs
2019-03-03 10:50:49 +01:00
Olle Jonsson
ea61fd7e44
Merge pull request #909 from lostisland/fix/rubocop-style-s
chore: RuboCop lints Style/S*
2019-03-03 10:22:54 +01:00
iMacTia
06a7c74162 Merge branch 'master' of https://github.com/lostisland/faraday into fix/rubocop-style-s
# Conflicts:
#	.rubocop_todo.yml
2019-03-03 08:59:49 +00:00
htwroclau
f1d0b3933d chore: Fix RuboCop Style/EmptyMethod (#912) 2019-03-03 08:58:00 +00:00
iMacTia
7931f07d6f Regenerates Rubocop TODOs. 2019-03-02 16:36:16 +00:00
iMacTia
228df3da71 Fixes Rubocop Style/SafeNavigation. 2019-03-02 16:35:22 +00:00
iMacTia
15303a3415 Fixes Rubocop Style/SingleLineMethods. 2019-03-02 16:33:29 +00:00
iMacTia
a41b6ac8d9 Fixes Rubocop Style/SpecialGlobalVars. 2019-03-02 16:32:29 +00:00
iMacTia
096a1c8bac Fixes Rubocop Style/StringLiteralsInInterpolation. 2019-03-02 16:31:12 +00:00
Olle Jonsson
61baf2b466
Merge pull request #908 from lostisland/fix/stderrputs-rubocop
chore: RuboCop Style/StderrPuts, SemiColon
2019-03-02 12:24:30 +01:00
Olle Jonsson
2c9a288046 chore: Regenerate RuboCop TODO 2019-03-02 12:16:48 +01:00
Olle Jonsson
c8bee3ed22 chore: RuboCop Style/SemiColon 2019-03-02 12:15:05 +01:00
Olle Jonsson
4d97cc13ac Simplify UploadIO require 2019-03-02 12:15:05 +01:00
htwroclau
5f55e62e88 chore: RuboCop lint Style/C* cops excluding Style/ClassVars (#902)
* chore: RuboCop lint Style/CaseEquality

* chore: RuboCop lint Style/ClassAndModuleChildren

* chore: RuboCop lint Style/ClassCheck

* chore: RuboCop lint Style/ConditionalAssignment
2019-03-02 10:47:56 +01:00
risk danger olson
4171215da7 chore: Rubocop lint Style/PercentLiteralDelimiters (#905) 2019-03-02 10:33:45 +01:00
htwroclau
f46a17573d chore: Fix RuboCop Style/BlockDelimiters (#906) 2019-03-02 10:10:48 +01:00
risk danger olson
c1febd329f chore: rubocop lint Style/StructInheritance (#904) 2019-03-02 10:01:04 +01:00
htwroclau
c9fcbcc048 chore: Fix RuboCop Style/BracesAroundHashParameters (#907) 2019-03-02 09:42:00 +01:00
James Herdman
4c7e0a7717 More Cops On Patrol (#901) 2019-03-01 15:28:19 +00:00
Mattia
5bbf4eb3ef
CI: Send CodeClimate test reports, deploy to RubyGems on tagging (#900) 2019-03-01 14:30:19 +00:00
Olle Jonsson
c2719dc5cb
Merge pull request #896 from lostisland/fix-more-lint-offenses
fix Lint/* offenses
2019-02-28 19:04:02 +01:00
Olle Jonsson
9e23ce0be5
Merge branch 'master' into fix-more-lint-offenses 2019-02-28 18:58:28 +01:00
Olle Jonsson
3396561021
Merge pull request #898 from lostisland/rubocop/styles
chore: RuboCop Style lints
2019-02-28 18:55:53 +01:00
iMacTia
5d469d7ece chore: Rubocop lint Style/SymbolArray 2019-02-28 17:30:10 +00:00
iMacTia
0af6142f47 chore: Rubocop lint Style/SymbolProc 2019-02-28 17:27:38 +00:00
iMacTia
2aa4d808a7 chore: Rubocop lint Style/TernaryParentheses 2019-02-28 17:26:35 +00:00
Olle Jonsson
2102b439c4
Merge branch 'master' into fix-more-lint-offenses 2019-02-28 18:26:31 +01:00
iMacTia
398f2cb236 chore: Rubocop lint Style/TrivialAccessors 2019-02-28 17:25:28 +00:00
iMacTia
e35c49efa8 chore: Rubocop lint Style/UnlessElse 2019-02-28 17:23:33 +00:00
iMacTia
127555abcf chore: Rubocop lint Style/YodaCondition 2019-02-28 17:19:40 +00:00
risk danger olson
fd7dbc709b Rubocop style (#897)
* chore: Rubocop lint Style/AccessModifierDeclarations
* chore: Rubocop lint Style/Alias
* chore: Rubocop lint Style/AndOr
* chore: Rubocop lint Naming/ConstantName
* chore: Rubocop lint Naming/PredicateName
* chore: Rubocop lint Naming/UncommunicativeMethodParamName
* chore: Rubocop lint Performance/RedundantBlockCall
* chore: Rubocop lint Performance/StringReplacement
2019-02-28 17:15:28 +00:00
rick olson
03ff75a189 chore: auto gen rubocop config 2019-02-27 15:08:26 -07:00
rick olson
6a62558687 add exception for Lint/HandleExceptions offense
This is a test that's only used in the integration suite (which spins up a
Sinatra server for tests). Removing the exception brought up more issues, which
should be looked at in a fresh pull request.
2019-02-27 15:04:56 -07:00
rick olson
8c66270eb5 Fix Lint/ReturnInVoidContext offense 2019-02-27 15:00:23 -07:00
rick olson
190467254e fix Lint/UnneededRequireStatement offenses 2019-02-27 14:46:02 -07:00
rick olson
cc703af68d fix Lint/UnusedBlockArgument offenses 2019-02-27 14:40:34 -07:00
rick olson
08c107516d fix Lint/UnusedMethodArgument offenses 2019-02-27 14:36:15 -07:00
rick olson
558746a776 fix Lint/Void offense 2019-02-27 14:26:45 -07:00
risk danger olson
d3fc6ec365
Merge pull request #891 from olleolleolle/fix/rubocop-linting-more
chore: RuboCop linting Lint/UselessAssignment, Lint/StringConversionInInterpolation
2019-02-27 14:19:45 -07:00
risk danger olson
5adaaab45c
Merge pull request #895 from olleolleolle/fix/redundant-cops
chore: RuboCop lint Style/Redundant* cops
2019-02-27 14:18:17 -07:00
risk danger olson
94f4175059
Merge pull request #892 from olleolleolle/fix/drop-ruby-18-compat
Multipart: Drop Ruby 1.8 String behavior compat
2019-02-27 14:16:06 -07:00
Olle Jonsson
afd5e634cc chore: RuboCop configuration regenerated 2019-02-27 21:48:52 +01:00
Olle Jonsson
f3cf995140 chore: RuboCop lint Style/RedundantSelf 2019-02-27 21:45:48 +01:00
Olle Jonsson
f9ffeb26f2 chore: RuboCop lint Style/RedundantException 2019-02-27 21:43:58 +01:00
Olle Jonsson
ff2a6d7eda chore: RuboCop lint Style/RedundantParentheses 2019-02-27 21:43:16 +01:00
Olle Jonsson
768c5151d2 chore: RuboCop lint Style/RedundantReturn 2019-02-27 21:42:20 +01:00
Olle Jonsson
5e462f6ce6
Merge branch 'master' into fix/rubocop-linting-more 2019-02-27 21:39:48 +01:00
Olle Jonsson
bbf937dd44
chore: RuboCop lint Style/ColonMethodCall (#894) 2019-02-27 21:37:28 +01:00
Olle Jonsson
64d9002b75
Merge branch 'master' into fix/rubocop-linting-more 2019-02-27 20:52:45 +01:00
Olle Jonsson
420b5a433f
chore: RuboCop lint Style/WordArray (#893) 2019-02-27 20:52:08 +01:00
Olle Jonsson
7bfac0cf29 Multipart: Drop Ruby 1.8 String behavior compat 2019-02-27 20:35:28 +01:00
Olle Jonsson
9005f4fbff chore: RuboCop --auto-gen-config 2019-02-27 20:31:23 +01:00
Olle Jonsson
2fa4043f21 chore: RuboCop lint Naming/MemoizedInstanceVariableName 2019-02-27 20:30:13 +01:00
Olle Jonsson
9e25ee6adc chore: RuboCop lint Lint/UselessAssignment 2019-02-27 20:09:22 +01:00
Olle Jonsson
769efe6af6 chore: RuboCop lint Lint/StringConversionInInterpolation 2019-02-27 20:02:55 +01:00
Olle Jonsson
5525c49529
Merge pull request #890 from jherdman/remaining-layout-cops
Resolve Remaining Layout Cops
2019-02-27 15:03:57 +01:00
James Herdman
25b1055dc0 chore: RuboCop Layout Rescue Ensure Alignment 2019-02-27 08:57:26 -05:00
James Herdman
553b20ac1a chore: RuboCop Indent Hash 2019-02-27 08:55:23 -05:00
James Herdman
9c25d73db7 chore: RuboCop Indent Array 2019-02-27 08:55:09 -05:00
James Herdman
615ad218b4 chore: RuboCop End Alignment (#887) 2019-02-27 14:49:04 +01:00
Olle Jonsson
e511d2fb29
Merge pull request #884 from olleolleolle/fix/rubocop-extra-spacing
chore: RuboCop Layout/ExtraSpacing, Layout/SpaceAroundOperators
2019-02-27 08:48:08 +01:00
Olle Jonsson
b000eff257 chore: RuboCop regenerate TODO 2019-02-27 08:44:09 +01:00
Olle Jonsson
2cfe8bd4b2 chore: RuboCop lint Layout/SpaceAfterComma 2019-02-27 08:43:36 +01:00
Olle Jonsson
28504a14c2 chore: RuboCop lint Layout/SpaceInsidePercentLiteralDelimiters 2019-02-27 08:42:45 +01:00
Olle Jonsson
5ea9b5d709 chore: RuboCop lint Layout/SpaceInsideParens 2019-02-27 08:42:24 +01:00
Olle Jonsson
cf60074f52 chore: RuboCop lint Layout/SpaceInsideHashLiteralBraces 2019-02-27 08:41:44 +01:00
Olle Jonsson
7ddccdbd1e chore: RuboCop lint Layout/SpaceInsideBlockBraces 2019-02-27 08:41:05 +01:00
Olle Jonsson
ba6247eb35 chore: RuboCop lint Layout/SpaceInsideArrayLiteralBrackets 2019-02-27 08:40:19 +01:00
Olle Jonsson
52a513d232 chore: RuboCop lint Layout/SpaceBeforeBlockBraces 2019-02-27 08:39:55 +01:00
Olle Jonsson
a68ebbcb72 chore: RuboCop lint Layout/SpaceAroundEqualsInParameterDefault 2019-02-27 08:39:21 +01:00
Olle Jonsson
8cb5865a78 chore: RuboCop lint Layout/SpaceAroundOperators 2019-02-27 08:37:07 +01:00
Olle Jonsson
7e6b5c6be2 chore: RuboCop Layout/ExtraSpacing 2019-02-27 07:46:49 +01:00
Olle Jonsson
52833e2f2b
chore: Disable Metrics/BlockLength in spec/ (#883) 2019-02-27 07:43:35 +01:00
James Herdman
7c823b042c chore: RuboCop Empty Lines Around Class Body (#882) 2019-02-26 21:34:25 +01:00
James Herdman
62cfe5bed1 chore: RuboCop Layout/EmptyLinesAroundAccessModifier (#881) 2019-02-26 17:08:17 +01:00
James Herdman
3adf411dcd chore: RuboCop Layout/DotPosition (#880) 2019-02-26 15:31:14 +00:00
Mattia
6634449ca0
Limits Travis builds to PRs and pushes/merges against master and 0.1x branches. (#879)
This should fix the double-build on all PRs.
2019-02-26 12:35:17 +00:00
Mattia
aa4e33ff50 chore: Fix RuboCop Style/HashSyntax (#878)
* Fixes rubocop Style/HashSyntax issues.

* Fixes rubocop Style/HashSyntax issues in comments as well.
2019-02-26 12:10:35 +01:00
Olle Jonsson
d579431fa0
chore: Layout/BlockEndNewline, Layout/MultilineBlockLayout (#877) 2019-02-26 00:12:44 +01:00
Olle Jonsson
cbbce86940
chore: RuboCop Style/CommentAnnotation (#876) 2019-02-25 23:49:00 +01:00
Olle Jonsson
7af02185d5
Merge pull request #874 from lostisland/rubocop-Lint-AssignmentInCondition
[Rubocop] fix Lint/AssignmentInCondition
2019-02-25 23:38:46 +01:00
Olle Jonsson
9cd764b2e7
Merge branch 'master' into rubocop-Lint-AssignmentInCondition 2019-02-25 23:25:26 +01:00
Olle Jonsson
281e3f4add
CI: Latest RuboCop run as Travis CI Stage (#873)
- disable the not-always recent CodeClimate RuboCop plugin
2019-02-25 23:24:26 +01:00
Olle Jonsson
8abc9e6942 chore: Re-generate RuboCop TODO 2019-02-25 23:12:14 +01:00
Olle Jonsson
00765145a3 chore: RuboCop Style/StringLiteral 2019-02-25 23:11:57 +01:00
Olle Jonsson
a4ee8a7704
Merge branch 'master' into rubocop-Lint-AssignmentInCondition 2019-02-25 22:58:42 +01:00
risk danger olson
d9c696ff2c Remove some unused gems (#875)
remove some unused gems from Bundler group: :test
2019-02-25 22:55:54 +01:00
James Herdman
dc4d8f620e [RuboCop] Trailing Blank Lines Violations (#872) 2019-02-25 22:53:32 +01:00
rick olson
0abe56597e fix todo file 2019-02-25 13:18:28 -07:00
risk danger olson
7f593f6d5f
Merge branch 'master' into rubocop-Lint-AssignmentInCondition 2019-02-25 13:09:23 -07:00
risk danger olson
39dd9549f8
Merge pull request #871 from jherdman/else-alignment
Resolve Layout/ElseAlignment Violations
2019-02-25 13:06:24 -07:00
risk danger olson
627ed8775e
Merge pull request #870 from lostisland/rubocop-failures-861
Fix rubocop issues from #861
2019-02-25 13:05:05 -07:00
rick olson
f55382880e autogen rubocop config 2019-02-25 13:00:05 -07:00
rick olson
fc53cc5d2d fix Lint/AssignmentInCondition 2019-02-25 12:59:59 -07:00
James Herdman
ff92c9ea04 [RuboCop] Resolve Layout/ElseAlignment 2019-02-25 14:19:19 -05:00
rick olson
3a11286c87 fix indentation issues 2019-02-25 11:26:58 -07:00
risk danger olson
e00e900486 Connection methods (#861) 2019-02-25 15:40:41 +00:00
htwroclau
de0e96054d chore: Fix RuboCop Layout/AlignParameters (#867) 2019-02-25 13:38:48 +00:00
Mattia
b427091f0e chore: RuboCop: Support Frozen String Literals (#868) 2019-02-24 20:35:12 +01:00
Mattia
fcc4c4043e
Fixes CodeClimate issues introduced in the latest PRs (#865) 2019-02-24 11:53:19 +00:00
Mattia
91ddced8b2 chore: RuboCop indentations (#864)
* chore: RuboCop lint Layout/CaseIndentation

* chore: RuboCop lint Layout/CommentIndentation

* chore: RuboCop lint Layout/IndentationWidth

* chore: RuboCop lint Layout/MultilineMethodCallIndentation

* chore: RuboCop lint Layout/MultilineOperationIndentation
2019-02-24 11:53:55 +01:00
Mattia
ec709b3974 chore: RuboCop lint Layout/AlignHash (#863) 2019-02-24 11:52:48 +01:00
htwroclau
671e9de604 chore: Fix RuboCop Layout/AccessModifierIndentation (#862) 2019-02-24 01:20:12 +01:00
risk danger olson
5cad588227 implement Connection#options. (#857)
fixes #305
2019-02-20 22:02:03 +00:00
Olle Jonsson
b2857e6e20
chore: RuboCop linting (#860)
* chore: RuboCop lint Layout/LeadingCommentSpace

* chore: RuboCop lint Layout/EmptyLineAfterGuardClause

* chore: RuboCop lint Layout/EmptyLineBetweenDefs

* chore: RuboCop lint Layout/EmptyLines

* chore: Regenerate RuboCop TODO
2019-02-20 22:44:57 +01:00
Olle Jonsson
f98c3e92fd
chore: RuboCop trailing commas fixed (#859) 2019-02-20 22:25:41 +01:00
Olle Jonsson
b585462dd5
chore: Fix RuboCop Style/ZeroLengthPredicate (#858) 2019-02-20 22:16:48 +01:00
Olle Jonsson
1054fcdf92
chore: RuboCop: Bundler/OrderedGems (#856)
* chore: RuboCop: Bundler/OrderedGems

* chore: Regenerate .rubocop_todo.yml
2019-02-20 22:07:03 +01:00
Olle Jonsson
03d05a25a9
RuboCop: Allow Lint/AssignmentInCondition - and enable RuboCop in CodeClimate (#853)
RuboCop: Create a TODO list and enable RuboCop in CodeClimate
2019-02-20 20:06:26 +01:00
Mattia
c8248ba2a4
Update README.md 2019-02-20 18:34:51 +00:00
Mattia
d3cbcd8825
README.md: Mark master branch as 1.0, and link to stable release branch (#850) 2019-02-20 18:29:15 +00:00
Olle Jonsson
848251420a Add RuboCop, start configuration, add --auto-gen-config (#851) 2019-02-20 18:28:48 +00:00
Olle Jonsson
9939ba6234 Gemspec: Required Ruby >=2.3 (#852) 2019-02-20 18:24:07 +00:00
Mattia
6e3c40f159
Separate Request and Response bodies (#847) 2019-02-20 16:00:58 +00:00
Mattia
6e4a2aaa05 Refactor Adapter as final endpoints (#846)
* Refactors Adapters:
* They're now final endpoints.
* They don't need to call `@app.call` anymore.
* They don't inherit from `Faraday::Middleware` anymore.
2019-02-19 10:48:52 +01:00
iMacTia
3fbf2d5261 Re-enables typhoeus tests using adapter's master branch. 2019-02-05 21:14:05 +00:00
iMacTia
0474e03d2d Use require instead of require_relative. 2019-01-14 09:17:05 +00:00
iMacTia
5ace0ea5ab [Ruby 2.7] Stops using &Proc.new for block forwarding. 2019-01-13 17:39:29 +00:00
iMacTia
1f8aae53ae Refactors params encoders into multiple files. 2019-01-13 17:04:33 +00:00
iMacTia
e14fb01063 Removes deprecated Faraday::Builder.
Refactors options into multiple files.
2019-01-13 16:59:12 +00:00
Mattia
793e6ba9c9
Add new error classes (#841)
* Removes sub-class constants definition from `Faraday::Error`. A sub-class (e.g. `ClientError`) was previously accessible
either through the `Faraday` module (e.g. `Faraday::ClientError`) or through the `Faraday::Error` class (e.g. `Faraday::Error::ClientError`).
The latter is no longer available and the former should be used instead, so check your `rescue`s.
* Introduces a new `Faraday::ServerError` (5xx status codes) alongside the existing `Faraday::ClientError` (4xx status codes).
Please note `Faraday::ClientError` was previously used for both.
* Introduces new Errors that describe the most common REST status codes:
  * Faraday::BadRequestError (400)
  * Faraday::UnauthorizedError (401)
  * Faraday::ForbiddenError (403)
  * Faraday::ProxyAuthError (407). Please note this raised a `Faraday::ConnectionFailed` before.
  * Faraday::UnprocessableEntityError (422)
2019-01-04 17:24:38 +00:00
Olle Jonsson
0e07aaee76 Travis: Drop old setting sudo: false (#840) 2018-12-29 16:00:00 +00:00
Olle Jonsson
dad29566dc Travis: Include Ruby 2.6 (#838) 2018-12-28 21:04:49 +00:00
Mattia
f1b2657523
Feature/#762 rspec (#832) 2018-11-26 17:11:35 +00:00
iMacTia
554780253f Merge branch 'master' of https://github.com/lostisland/faraday into 1.0 2018-11-26 15:58:58 +00:00
iMacTia
a37f8c5c37 Merge branch 'master' of https://github.com/lostisland/faraday into 1.0 2018-10-29 16:15:49 +00:00
Olle Jonsson
ec3ccb128c [1.0] UPGRADING.md: Mention Ruby 2.3+ (#829) 2018-10-19 16:22:52 +01:00
Olle Jonsson
3ff3dbc43e [1.0] Travis CI matrix: Drop 2.2: 2.3+ new min version required (#828) 2018-10-19 11:13:53 +01:00
Olle Jonsson
e77ac3d9e8 [1.0] [DOC] SSLOptions, Utils::Headers, Utils::ParamsHash (#826) 2018-10-19 09:20:33 +01:00
iMacTia
afe53e9020 Merge branch 'master' of https://github.com/lostisland/faraday into 1.0
# Conflicts:
#	.travis.yml
#	lib/faraday/options.rb
2018-09-21 09:29:29 +01:00
Olle Jonsson
7974c7a95c [1.0] YARD docs for error classes (#819) 2018-09-11 12:48:58 +01:00
Olle Jonsson
3b2b86a8e1 [1.0] Docs for middleware (#817) 2018-09-11 11:59:31 +01:00
Olle Jonsson
8309a875bb [1.0] Docs for more middlewares (#815) 2018-09-07 16:01:55 +01:00
Mattia Giuffrida
82a8a0bd13 Merge branch 'master' of https://github.com/lostisland/faraday into 1.0
# Conflicts:
#	lib/faraday/request.rb
2018-07-21 15:11:12 +01:00
Olle Jonsson
c63efc6472 README: logger middleware wording (#798)
- this wording was borrowed from a comment on #794
2018-05-16 09:08:36 +01:00
iMacTia
5ee253a9a3 Merge branch 'master' of https://github.com/lostisland/faraday into 1.0
# Conflicts:
#	lib/faraday/adapter/patron.rb
2018-05-10 10:09:43 +01:00
Olle Jonsson
89b3365896 YARD annotations; Git ignore .yardoc/ (#788) 2018-04-17 15:08:09 +01:00
Mattia Giuffrida
d9661c4567 Merge branch 'master' of https://github.com/lostisland/faraday into 1.0 2018-03-08 20:09:09 +00:00
Mattia Giuffrida
5f9314fba6 Merge branch 'master' of https://github.com/lostisland/faraday into 1.0 2018-02-10 13:14:17 +00:00
Olle Jonsson
452f04d342 [api docs] NestedParamsEncoder (#768) 2018-02-07 14:05:06 +00:00
Olle Jonsson
1793f9fd47 [1.0 docs] YARD docblocks for classes Env, Request (#763) 2018-02-02 16:54:07 +00:00
Olle Jonsson
33f771d0c4 [1.0] Remove deprecated arg to proxy reader (#765) 2018-01-31 15:48:54 +00:00
Olle Jonsson
5cdb17cf10 [1.0] YARD docblocks annotation - a beginning in a single file (#758) 2018-01-21 11:41:10 +00:00
Mattia Giuffrida
f2e0e22442 Merge branch 'master' of https://github.com/lostisland/faraday into 1.0
# Conflicts:
#	.travis.yml
2018-01-21 09:44:34 +00:00
Mattia
ea9309d7d3
Create UPGRADING.md 2017-11-22 13:57:51 +00:00
Mattia
8503baea4b
Changes the way adapters are managed (#750)
* Store adapter separately from other middleware
* Adapter can be set anywhere in the stack and will always be the last
* Use default adapter if no adapter set

fixes #47
fixes #121
2017-11-21 09:48:45 +00:00
Mattia Giuffrida
74941bdd46 Merge branch 'master' of https://github.com/lostisland/faraday into 1.0 2017-11-19 10:09:26 +00:00
iMacTia
5f8b09e843 Merge branch 'master' of https://github.com/lostisland/faraday into 1.0 2017-11-17 15:08:28 +00:00
Mattia
69932412cb
Fix min ruby to 2.2 Removes jruby and rbx. (#744) 2017-11-17 15:07:03 +00:00
Mattia Giuffrida
4ef728230c Merge branch 'master' of https://github.com/lostisland/faraday into 1.0
# Conflicts:
#	lib/faraday/adapter/typhoeus.rb
#	test/adapters/typhoeus_test.rb
2017-11-12 10:56:59 +00:00
Martin Mauch
ff94676369 Streaming requests for Net::HTTP (#604) 2017-08-30 08:12:01 +01:00
190 changed files with 13954 additions and 7648 deletions

View File

@ -1,6 +0,0 @@
LICENSE.md
README.md
bin/*
lib/**/*.rb
test/**/*.rb
.github/*.md

9
.editorconfig Normal file
View File

@ -0,0 +1,9 @@
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

View File

@ -1,52 +1,79 @@
## Contributing
You can run the test suite against a live server by running `script/test`. It
automatically starts a test server in background. Only tests in
`test/adapters/*_test.rb` require a server, though.
In Faraday we always welcome new ideas and features, however we also have to ensure
that the overall code quality stays on reasonable levels.
For this reason, before adding any contribution to Faraday, we highly recommend reading this
quick guide to ensure your PR can be reviewed and approved as quickly as possible.
``` sh
# setup development dependencies
$ script/bootstrap
We are past our 1.0 release, and follow [Semantic Versioning][semver]. If your
patch includes changes that break compatibility, note that in the Pull Request, so we can add it to
the [Changelog][].
# run the whole suite
$ script/test
# run only specific files
$ script/test excon patron
### Policy on inclusive language
# run tests using SSL
$ SSL=yes script/test
You have read our [Code of Conduct][], which includes a note about **inclusive language**. This section tries to make that actionable.
Faraday has a large and diverse userbase. To make Faraday a pleasant and effective experience for everyone, we use inclusive language.
These resources can help:
- Google's tutorial [Writing inclusive documentation](https://developers.google.com/style/inclusive-documentation) teaches by example, how to reword non-inclusive things.
- Linux kernel mailing list's [Coding Style: Inclusive Terminology](https://lkml.org/lkml/2020/7/4/229) said "Add no new instances of non-inclusive words, here is a list of words not include new ones of."
- Linguistic Society of America published [Guidelines for Inclusive Language](https://www.linguisticsociety.org/resource/guidelines-inclusive-language) which concluded: "We encourage all linguists to consider the possible reactions of their potential audience to their writing and, in so doing, to choose expository practices and content that is positive, inclusive, and respectful."
This project attempts to improve in these areas. Join us in doing that important work.
If you want to privately raise any breach to this policy with the Faraday team, feel free to reach out to [@iMacTia](https://ruby.social/@iMacTia) and [@olleolleolle](https://ruby.social/@olleolleolle) on the Mastodon instance ruby.social.
### Required Checks
Before pushing your code and opening a PR, we recommend you run the following checks to avoid
our GitHub Actions Workflow to block your contribution.
```bash
# Run unit tests and check code coverage
$ bundle exec rspec
# Check code style
$ bundle exec rubocop
```
### New Features
When adding a feature Faraday:
When adding a feature in Faraday:
1. also add tests to cover your new feature.
2. if the feature is for an adapter, the **attempt** must be made to add the same feature to all other adapters as well.
3. start opening an issue describing how the new feature will work, and only after receiving the green light by the core team start working on the PR.
### New Middlewares
We will accept middleware that:
1. is useful to a broader audience, but can be implemented relatively
simple; and
2. which isn't already present in [faraday_middleware][] project.
3. start opening an issue describing how the new feature will work, and only after receiving
the green light by the core team start working on the PR.
### New Adapters
### New Middleware & Adapters
We will accept adapters that:
We prefer new adapters and middlewares to be added **as separate gems**. We can link to such gems from this project.
This goes for the [faraday_middleware][] project as well.
We encourage adapters that:
1. support SSL & streaming;
1. are proven and may have better performance than existing ones; or
2. if they have features not present in included adapters.
1. have features not present in included adapters.
We are pushing towards a 1.0 release, when we will have to follow [Semantic
Versioning][semver]. If your patch includes changes to break compatibility,
note that so we can add it to the [Changelog][].
[semver]: http://semver.org/
[changelog]: https://github.com/lostisland/faraday/releases
[faraday_middleware]: https://github.com/lostisland/faraday_middleware/wiki
### Changes to the Faraday Docs
The Faraday Docs are included in the Faraday repository, under the `/docs` folder and deployed to [GitHub Pages][website].
If you want to apply changes to it, please test it locally before opening your PR.
You can find more information in the [Faraday Docs README][docs], including how to preview changes locally.
[semver]: https://semver.org/
[changelog]: https://github.com/lostisland/faraday/releases
[faraday_middleware]: https://github.com/lostisland/faraday_middleware
[website]: https://lostisland.github.io/faraday
[docs]: ../docs/README.md
[Code of Conduct]: ./CODE_OF_CONDUCT.md

14
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,14 @@
version: 2
updates:
- package-ecosystem: "bundler"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "npm"
directory: /
schedule:
interval: "weekly"

69
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,69 @@
name: CI
on:
pull_request:
push:
branches: [ main, 1.x, 0.1x ]
env:
GIT_COMMIT_SHA: ${{ github.sha }}
GIT_BRANCH: ${{ github.ref }}
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
linting:
runs-on: ubuntu-latest
env:
BUNDLE_WITH: lint
BUNDLE_WITHOUT: development:test
steps:
- uses: actions/checkout@v5
- name: Setup Ruby 3.x
uses: ruby/setup-ruby@v1
with:
ruby-version: 3
bundler-cache: true
- name: Rubocop
run: bundle exec rubocop --format progress
- name: Yard-Junk
run: bundle exec yard-junk --path lib
build:
needs: [ linting ]
runs-on: ubuntu-latest
name: build ${{ matrix.ruby }}
strategy:
fail-fast: false
matrix:
ruby: [ '3.0', '3.1', '3.2', '3.3', '3.4' ]
experimental: [false]
include:
- ruby: head
experimental: true
- ruby: truffleruby-head
experimental: true
steps:
- uses: actions/checkout@v5
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
- name: RSpec
continue-on-error: ${{ matrix.experimental }}
run: bundle exec rake
- name: Test External Adapters
continue-on-error: ${{ matrix.experimental }}
run: bundle exec bake test:external

26
.github/workflows/publish.yml vendored Normal file
View File

@ -0,0 +1,26 @@
name: Publish
on:
release:
types: [published]
jobs:
build:
name: Publish to Rubygems
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
steps:
- uses: actions/checkout@v5
- name: Setup Ruby 3.x
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
ruby-version: 3
- name: Publish to RubyGems
uses: rubygems/release-gem@v1

15
.github/workflows/refresh_team_page.yml vendored Normal file
View File

@ -0,0 +1,15 @@
name: Refresh Team Page
on:
push:
branches: [ main ]
permissions: {}
jobs:
build:
name: Refresh Contributors Stats
runs-on: ubuntu-latest
steps:
- name: Call GitHub API
run: |
curl "https://api.github.com/repos/${{ github.repository }}/stats/contributors"

8
.gitignore vendored
View File

@ -7,16 +7,22 @@ pkg/*
tmp
.rvmrc
.ruby-version
.yardoc
.DS_Store
## BUNDLER
bin
*.gem
.bundle
Gemfile.lock
vendor/bundle
external
## NPM
node_modules
## PROJECT::SPECIFIC
.rbx
## IDEs
.idea/
.yardoc/

3
.rspec Normal file
View File

@ -0,0 +1,3 @@
--require spec_helper
--format documentation
--color

200
.rubocop.yml Normal file
View File

@ -0,0 +1,200 @@
inherit_from: .rubocop_todo.yml
require:
- rubocop-packaging
- rubocop-performance
AllCops:
DisplayCopNames: true
DisplayStyleGuide: true
TargetRubyVersion: 3.0
# Custom config
Gemspec/RequireMFA: # we don't know if this works with auto-deployments yet
Enabled: false
Layout/LineLength:
Exclude:
- spec/**/*.rb
- examples/**/*.rb
Metrics/BlockLength:
Exclude:
- lib/faraday/options/env.rb
- spec/**/*.rb
- examples/**/*.rb
Metrics/ModuleLength:
Exclude:
- lib/faraday/options/env.rb
Style/Documentation:
Exclude:
- 'spec/**/*'
- 'examples/**/*'
Style/DoubleNegation:
Enabled: false
Style/IfUnlessModifier:
Enabled: false
# New cops
Gemspec/DeprecatedAttributeAssignment: # new in 1.30
Enabled: true
Layout/LineContinuationLeadingSpace: # new in 1.31
Enabled: true
Layout/LineContinuationSpacing: # new in 1.31
Enabled: true
Layout/LineEndStringConcatenationIndentation: # new in 1.18
Enabled: true
Layout/SpaceBeforeBrackets: # new in 1.7
Enabled: true
Lint/AmbiguousAssignment: # new in 1.7
Enabled: true
Lint/AmbiguousOperatorPrecedence: # new in 1.21
Enabled: true
Lint/AmbiguousRange: # new in 1.19
Enabled: true
Lint/ConstantOverwrittenInRescue: # new in 1.31
Enabled: true
Lint/DeprecatedConstants: # new in 1.8
Enabled: true
Lint/DuplicateBranch: # new in 1.3
Enabled: true
Lint/DuplicateRegexpCharacterClassElement: # new in 1.1
Enabled: true
Lint/EmptyBlock: # new in 1.1
Enabled: true
Lint/EmptyClass: # new in 1.3
Enabled: true
Lint/EmptyInPattern: # new in 1.16
Enabled: true
Lint/IncompatibleIoSelectWithFiberScheduler: # new in 1.21
Enabled: true
Lint/LambdaWithoutLiteralBlock: # new in 1.8
Enabled: true
Lint/NoReturnInBeginEndBlocks: # new in 1.2
Enabled: true
Lint/NonAtomicFileOperation: # new in 1.31
Enabled: true
Lint/NumberedParameterAssignment: # new in 1.9
Enabled: true
Lint/OrAssignmentToConstant: # new in 1.9
Enabled: true
Lint/RedundantDirGlobSort: # new in 1.8
Enabled: true
Lint/RefinementImportMethods: # new in 1.27
Enabled: true
Lint/RequireRangeParentheses: # new in 1.32
Enabled: true
Lint/RequireRelativeSelfPath: # new in 1.22
Enabled: true
Lint/SymbolConversion: # new in 1.9
Enabled: true
Lint/ToEnumArguments: # new in 1.1
Enabled: true
Lint/TripleQuotes: # new in 1.9
Enabled: true
Lint/UnexpectedBlockArity: # new in 1.5
Enabled: true
Lint/UnmodifiedReduceAccumulator: # new in 1.1
Enabled: true
Lint/UselessRuby2Keywords: # new in 1.23
Enabled: true
Naming/BlockForwarding: # new in 1.24
Enabled: true
Security/CompoundHash: # new in 1.28
Enabled: true
Security/IoMethods: # new in 1.22
Enabled: true
Style/ArgumentsForwarding: # new in 1.1
Enabled: true
Style/CollectionCompact: # new in 1.2
Enabled: true
Style/DocumentDynamicEvalDefinition: # new in 1.1
Enabled: true
Style/EmptyHeredoc: # new in 1.32
Enabled: true
Style/EndlessMethod: # new in 1.8
Enabled: true
Style/EnvHome: # new in 1.29
Enabled: true
Style/FetchEnvVar: # new in 1.28
Enabled: true
Style/FileRead: # new in 1.24
Enabled: true
Style/FileWrite: # new in 1.24
Enabled: true
Style/HashConversion: # new in 1.10
Enabled: true
Style/HashExcept: # new in 1.7
Enabled: true
Style/IfWithBooleanLiteralBranches: # new in 1.9
Enabled: true
Style/InPatternThen: # new in 1.16
Enabled: true
Style/MapCompactWithConditionalBlock: # new in 1.30
Enabled: true
Style/MapToHash: # new in 1.24
Enabled: true
Style/MultilineInPatternThen: # new in 1.16
Enabled: true
Style/NegatedIfElseCondition: # new in 1.2
Enabled: true
Style/NestedFileDirname: # new in 1.26
Enabled: true
Style/NilLambda: # new in 1.3
Enabled: true
Style/NumberedParameters: # new in 1.22
Enabled: true
Style/NumberedParametersLimit: # new in 1.22
Enabled: true
Style/ObjectThen: # new in 1.28
Enabled: true
Style/OpenStructUse: # new in 1.23
Enabled: true
Style/QuotedSymbols: # new in 1.16
Enabled: true
Style/RedundantArgument: # new in 1.4
Enabled: true
Style/RedundantInitialize: # new in 1.27
Enabled: true
Style/RedundantSelfAssignmentBranch: # new in 1.19
Enabled: true
Style/SelectByRegexp: # new in 1.22
Enabled: true
Style/StringChars: # new in 1.12
Enabled: true
Style/SwapValues: # new in 1.1
Enabled: true
Performance/AncestorsInclude: # new in 1.7
Enabled: true
Performance/BigDecimalWithNumericArgument: # new in 1.7
Enabled: true
Performance/BlockGivenWithExplicitBlock: # new in 1.9
Enabled: true
Performance/CollectionLiteralInLoop: # new in 1.8
Enabled: true
Performance/ConcurrentMonotonicTime: # new in 1.12
Enabled: true
Performance/ConstantRegexp: # new in 1.9
Enabled: true
Performance/MapCompact: # new in 1.11
Enabled: true
Performance/MethodObjectAsBlock: # new in 1.9
Enabled: true
Performance/RedundantEqualityComparisonBlock: # new in 1.10
Enabled: true
Performance/RedundantSortBlock: # new in 1.7
Enabled: true
Performance/RedundantSplitRegexpArgument: # new in 1.10
Enabled: true
Performance/RedundantStringChars: # new in 1.7
Enabled: true
Performance/ReverseFirst: # new in 1.7
Enabled: true
Performance/SortReverse: # new in 1.7
Enabled: true
Performance/Squeeze: # new in 1.7
Enabled: true
Performance/StringIdentifierArgument: # new in 1.13
Enabled: true
Performance/StringInclude: # new in 1.7
Enabled: true
Performance/Sum: # new in 1.8
Enabled: true

71
.rubocop_todo.yml Normal file
View File

@ -0,0 +1,71 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2023-12-27 11:12:52 UTC using RuboCop version 1.59.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
# Offense count: 6
# Configuration parameters: AllowedMethods.
# AllowedMethods: enums
Lint/ConstantDefinitionInBlock:
Exclude:
- 'spec/faraday/options/options_spec.rb'
- 'spec/faraday/rack_builder_spec.rb'
- 'spec/faraday/request/instrumentation_spec.rb'
# Offense count: 11
# Configuration parameters: AllowComments, AllowEmptyLambdas.
Lint/EmptyBlock:
Exclude:
- 'spec/faraday/connection_spec.rb'
- 'spec/faraday/rack_builder_spec.rb'
- 'spec/faraday/response_spec.rb'
# Offense count: 13
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
Metrics/AbcSize:
Max: 42
# Offense count: 3
# Configuration parameters: CountComments, CountAsOne.
Metrics/ClassLength:
Max: 230
# Offense count: 9
# Configuration parameters: AllowedMethods, AllowedPatterns.
Metrics/CyclomaticComplexity:
Max: 13
# Offense count: 27
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
Metrics/MethodLength:
Max: 33
# Offense count: 1
# Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
Metrics/ParameterLists:
Max: 6
# Offense count: 7
# Configuration parameters: AllowedMethods, AllowedPatterns.
Metrics/PerceivedComplexity:
Max: 14
# Offense count: 19
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AllowOnlyRestArgument, UseAnonymousForwarding, RedundantRestArgumentNames, RedundantKeywordRestArgumentNames, RedundantBlockArgumentNames.
# RedundantRestArgumentNames: args, arguments
# RedundantKeywordRestArgumentNames: kwargs, options, opts
# RedundantBlockArgumentNames: blk, block, proc
Style/ArgumentsForwarding:
Exclude:
- 'lib/faraday.rb'
- 'lib/faraday/rack_builder.rb'
# Offense count: 3
Style/DocumentDynamicEvalDefinition:
Exclude:
- 'lib/faraday/connection.rb'
- 'lib/faraday/options.rb'

View File

@ -1,47 +0,0 @@
sudo: false
language: ruby
script: bundle exec script/test
cache: bundler
rvm:
- 1.9.3
- 2.0.0
- 2.1
- 2.2
- 2.3
- 2.4
- 2.5.0
- ruby-head
- jruby-19mode
- jruby-20mode
- jruby-21mode
- jruby-head
matrix:
allow_failures:
# "A fatal error has been detected by the Java Runtime Environment:
# Internal Error (sharedRuntime.cpp:843)"
- rvm: jruby-19mode
- rvm: jruby-20mode
- rvm: jruby-21mode
- rvm: jruby-head
- rvm: ruby-head
fast_finish: true
env:
matrix:
- SSL=no
- SSL=yes
global:
- JRUBY_OPTS="$JRUBY_OPTS --debug"
deploy:
provider: rubygems
api_key:
secure: EqbOu9BQp5jkivJ8qvTo89f3J49KOByBueU3XulrJ2Kqm/ov4RDFsmp9/uHAnSLdmKSkzZaeq79t1AUNfKGX1ZqkKgq/Nw2BKGFnh5ZOjrkrRZR1Vm09OHxqiViEbtg+jZ8VOLY/iDFEkNIzuj9/H3iHGXC0XiKH2LTHOFH63Bs=
gem: faraday
on:
tags: true
repo: lostisland/faraday
rvm: 2.4
condition: '"$SSL" = "yes"'

12
.yardopts Normal file
View File

@ -0,0 +1,12 @@
--no-private
--exclude test
--exclude .github
--exclude coverage
--exclude doc
--exclude script
--markup markdown
--readme README.md
lib/**/*.rb
-
CHANGELOG.md

View File

@ -1,6 +1,558 @@
# Faraday Changelog
For newer changes, please see https://github.com/lostisland/faraday/releases
## The changelog has moved!
This file is not being updated anymore. Instead, please check the [Releases](https://github.com/lostisland/faraday/releases) page.
## [2.2.0](https://github.com/lostisland/faraday/compare/v2.1.0...v2.2.0) (2022-02-03)
* Reintroduce the possibility to register middleware with symbols, strings or procs in [#1391](https://github.com/lostisland/faraday/pull/1391)
## [2.1.0](https://github.com/lostisland/faraday/compare/v2.0.1...v2.1.0) (2022-01-15)
* Fix test adapter thread safety by @iMacTia in [#1380](https://github.com/lostisland/faraday/pull/1380)
* Add default adapter options by @hirasawayuki in [#1382](https://github.com/lostisland/faraday/pull/1382)
* CI: Add Ruby 3.1 to matrix by @petergoldstein in [#1374](https://github.com/lostisland/faraday/pull/1374)
* docs: fix regex pattern in logger.md examples by @hirasawayuki in [#1378](https://github.com/lostisland/faraday/pull/1378)
## [2.0.1](https://github.com/lostisland/faraday/compare/v2.0.0...v2.0.1) (2022-01-05)
* Re-add `faraday-net_http` as default adapter by @iMacTia in [#1366](https://github.com/lostisland/faraday/pull/1366)
* Updated sample format in UPGRADING.md by @vimutter in [#1361](https://github.com/lostisland/faraday/pull/1361)
* docs: Make UPGRADING examples more copyable by @olleolleolle in [#1363](https://github.com/lostisland/faraday/pull/1363)
## [2.0.0](https://github.com/lostisland/faraday/compare/v1.8.0...v2.0.0) (2022-01-04)
The next major release is here, and it comes almost 2 years after the release of v1.0!
This release changes the way you use Faraday and embraces a new paradigm of Faraday as an ecosystem, rather than a library.
What does that mean? It means that Faraday is less of a bundled tool and more of a framework for the community to build on top of.
As a result, all adapters and some middleware have moved out and are now shipped as standalone gems 🙌!
But this doesn't mean that upgrading from Faraday 1.x to Faraday 2.0 should be hard, in fact we've listed everything you need to do in the [UPGRADING.md](https://github.com/lostisland/faraday/blob/main/UPGRADING.md) doc.
Moreover, we've setup a new [awesome-faraday](https://github.com/lostisland/awesome-faraday) repository that will showcase a curated list of adapters and middleware 😎.
This release was the result of the efforts of the core team and all the contributors, new and old, that have helped achieve this milestone 👏.
## What's Changed
* Autoloading, dependency loading and middleware registry cleanup by @iMacTia in [#1301](https://github.com/lostisland/faraday/pull/1301)
* Move JSON middleware (request and response) from faraday_middleware by @iMacTia in [#1300](https://github.com/lostisland/faraday/pull/1300)
* Remove deprecated `Faraday::Request#method` by @olleolleolle in [#1303](https://github.com/lostisland/faraday/pull/1303)
* Remove deprecated `Faraday::UploadIO` by @iMacTia in [#1307](https://github.com/lostisland/faraday/pull/1307)
* [1.x] Deprecate Authorization helpers in `Faraday::Connection` by @iMacTia in [#1306](https://github.com/lostisland/faraday/pull/1306)
* Drop deprecated auth helpers from Connection and refactor auth middleware by @iMacTia in [#1308](https://github.com/lostisland/faraday/pull/1308)
* Add Faraday 1.x examples in authentication.md docs by @iMacTia in [#1320](https://github.com/lostisland/faraday/pull/1320)
* Fix passing a URL with embedded basic auth by @iMacTia in [#1324](https://github.com/lostisland/faraday/pull/1324)
* Register JSON middleware by @mollerhoj in [#1331](https://github.com/lostisland/faraday/pull/1331)
* Retry middleware should handle string exception class name consistently by @jrochkind in [#1334](https://github.com/lostisland/faraday/pull/1334)
* Improve request info in exceptions raised by RaiseError Middleware by @willianzocolau in [#1335](https://github.com/lostisland/faraday/pull/1335)
* Remove net-http adapter and update docs by @iMacTia in [#1336](https://github.com/lostisland/faraday/pull/1336)
* Explain plan for faraday_middleware in UPGRADING.md by @iMacTia in [#1339](https://github.com/lostisland/faraday/pull/1339)
* Scripts folder cleanup by @iMacTia in [#1340](https://github.com/lostisland/faraday/pull/1340)
* Replace `Hash#merge` with `Utils#deep_merge` for connection options by @xkwd in [#1343](https://github.com/lostisland/faraday/pull/1343)
* Callable authorizers by @sled in [#1345](https://github.com/lostisland/faraday/pull/1345)
* Default value for exc error by @DariuszMusielak in [#1351](https://github.com/lostisland/faraday/pull/1351)
* Don't call `retry_block` unless a retry is going to happen by @jrochkind in [#1350](https://github.com/lostisland/faraday/pull/1350)
* Improve documentation for v2 by @iMacTia in [#1353](https://github.com/lostisland/faraday/pull/1353)
* Remove default `default_adapter` (yes, you read that right) by @iMacTia in [#1354](https://github.com/lostisland/faraday/pull/1354)
* Remove retry middleware by @iMacTia in [#1356](https://github.com/lostisland/faraday/pull/1356)
* Remove multipart middleware and all its documentation and tests by @iMacTia in [#1357](https://github.com/lostisland/faraday/pull/1357)
## [1.9.3](https://github.com/lostisland/faraday/compare/v1.9.2...v1.9.3) (2022-01-06)
* Re-add support for Ruby 2.4+ by @iMacTia in [#1371](https://github.com/lostisland/faraday/pull/1371)
## [1.9.2](https://github.com/lostisland/faraday/compare/v1.9.1...v1.9.2) (2022-01-06)
* Add alias with legacy name to gemified middleware by @iMacTia in [#1372](https://github.com/lostisland/faraday/pull/1372)
## [1.9.1](https://github.com/lostisland/faraday/compare/v1.9.0...v1.9.1) (2022-01-06)
* Update adapter dependencies in Gemspec by @iMacTia in [#1370](https://github.com/lostisland/faraday/pull/1370)
## [1.9.0](https://github.com/lostisland/faraday/compare/v1.8.0...v1.9.0) (2022-01-06)
* Use external multipart and retry middleware by @iMacTia in [#1367](https://github.com/lostisland/faraday/pull/1367)
## [1.8.0](https://github.com/lostisland/faraday/releases/tag/v1.8.0) (2021-09-18)
### Features
* Backport authorization procs (#1322, @jarl-dk)
## [v1.7.0](https://github.com/lostisland/faraday/releases/tag/v1.7.0) (2021-08-09)
### Features
* Add strict_mode to Test::Stubs (#1298, @yykamei)
## [v1.6.0](https://github.com/lostisland/faraday/releases/tag/v1.6.0) (2021-08-01)
### Misc
* Use external Rack adapter (#1296, @iMacTia)
## [v1.5.1](https://github.com/lostisland/faraday/releases/tag/v1.5.1) (2021-07-11)
### Fixes
* Fix JRuby incompatibility after moving out EM adapters (#1294, @ahorek)
### Documentation
* Update YARD to follow RackBuilder (#1292, @kachick)
## [v1.5.0](https://github.com/lostisland/faraday/releases/tag/v1.5.0) (2021-07-04)
### Misc
* Use external httpclient adapter (#1289, @iMacTia)
* Use external patron adapter (#1290, @iMacTia)
## [v1.4.3](https://github.com/lostisland/faraday/releases/tag/v1.4.3) (2021-06-24)
### Fixes
* Silence warning (#1286, @gurgeous)
* Always dup url_prefix in Connection#build_exclusive_url (#1288, @alexeyds)
## [v1.4.2](https://github.com/lostisland/faraday/releases/tag/v1.4.2) (2021-05-22)
### Fixes
* Add proxy setting when url_prefix is changed (#1276, @ci)
* Default proxy scheme to http:// if necessary, fixes #1282 (#1283, @gurgeous)
### Documentation
* Improve introduction page (#1273, @gurgeous)
* Docs: add more middleware examples (#1277, @gurgeous)
### Misc
* Use external `em_http` and `em_synchrony` adapters (#1274, @iMacTia)
## [v1.4.1](https://github.com/lostisland/faraday/releases/tag/v1.4.1) (2021-04-18)
### Fixes
* Fix dependencies from external adapter gems (#1269, @iMacTia)
## [v1.4.0](https://github.com/lostisland/faraday/releases/tag/v1.4.0) (2021-04-16)
### Highlights
With this release, we continue the work of gradually moving out adapters into their own gems 🎉
Thanks to @MikeRogers0 for helping the Faraday team in progressing with this quest 👏
And thanks to @olleolleolle efforts, Faraday is becoming more inclusive than ever 🤗
Faraday's `master` branch has been renamed into `main`, we have an official policy on inclusive language and even a rubocop plugin to check for non-inclusive words ❤️!
Checkout the "Misc" section below for more details 🙌 !
### Fixes
* Fix NoMethodError undefined method 'coverage' (#1255, @Maroo-b)
### Documentation
* Some docs on EventMachine adapters. (#1232, @damau)
* CONTRIBUTING: Fix grammar and layout (#1261, @olleolleolle)
### Misc
* Replacing Net::HTTP::Persistent with faraday-net_http_persistent (#1250, @MikeRogers0)
* CI: Configure the regenerated Coveralls token (#1256, @olleolleolle)
* Replace Excon adapter with Faraday::Excon gem, and fix autoloading issue with Faraday::NetHttpPersistent (#1257, @iMacTia)
* Drop CodeClimate (#1259, @olleolleolle)
* CI: Rename default branch to main (#1263, @olleolleolle)
* Drop RDoc support file .document (#1264, @olleolleolle, @iMacTia)
* CONTRIBUTING: add a policy on inclusive language (#1262, @olleolleolle)
* Add rubocop-inclusivity (#1267, @olleolleolle, @iMacTia)
## [v1.3.1](https://github.com/lostisland/faraday/releases/tag/v1.3.1) (2021-04-16)
### Fixes
* Escape colon in path segment (#1237, @yarafan)
* Handle IPv6 address String on Faraday::Connection#proxy_from_env (#1252, @cosmo0920)
### Documentation
* Fix broken Rubydoc.info links (#1236, @nickcampbell18)
* Add httpx to list of external adapters (#1246, @HoneyryderChuck)
### Misc
* Refactor CI to remove duplicated line (#1230, @tricknotes)
* Gemspec: Pick a good ruby2_keywords release (#1241, @olleolleolle)
## [v1.3.0](https://github.com/lostisland/faraday/releases/tag/v1.3.0) (2020-12-31)
### Highlights
Faraday v1.3.0 is the first release to officially support Ruby 3.0 in the CI pipeline 🎉 🍾!
This is also the first release with a previously "included" adapter (Net::HTTP) being isolated into a [separate gem](https://github.com/lostisland/faraday-net_http) 🎊!
The new adapter is added to Faraday as a dependency for now, so that means full backwards-compatibility, but just to be safe be careful when upgrading!
This is a huge step towards are Faraday v2.0 objective of pushing adapters and middleware into separate gems.
Many thanks to the Faraday Team, @JanDintel and everyone who attended the [ROSS Conf remote event](https://www.rossconf.io/event/remote/)
### Features
* Improves consistency with Faraday::Error and Faraday::RaiseError (#1229, @qsona, @iMacTia)
### Fixes
* Don't assign to global ::Timer (#1227, @bpo)
### Documentation
* CHANGELOG: add releases after 1.0 (#1225, @olleolleolle)
* Improves retry middleware documentation. (#1228, @iMacTia)
### Misc
* Move out Net::HTTP adapter (#1222, @JanDintel, @iMacTia)
* Adds Ruby 3.0 to CI Matrix (#1226, @iMacTia)
## [v1.2.0](https://github.com/lostisland/faraday/releases/tag/v1.2.0) (2020-12-23)
### Features
* Introduces `on_request` and `on_complete` methods in `Faraday::Middleware`. (#1194, @iMacTia)
### Fixes
* Require 'date' to avoid retry exception (#1206, @rustygeldmacher)
* Fix rdebug recursion issue (#1205, @native-api)
* Update call to `em_http_ssl_patch` (#1202, @kylekeesling)
* `EmHttp` adapter: drop superfluous loaded? check (#1213, @olleolleolle)
* Avoid 1 use of keyword hackery (#1211, @grosser)
* Fix #1219 `Net::HTTP` still uses env proxy (#1221, @iMacTia)
### Documentation
* Add comment in gemspec to explain exposure of `examples` and `spec` folders. (#1192, @iMacTia)
* Adapters, how to create them (#1193, @olleolleolle)
* Update documentation on using the logger (#1196, @tijmenb)
* Adjust the retry documentation and spec to align with implementation (#1198, @nbeyer)
### Misc
* Test against ruby head (#1208, @grosser)
## [v1.1.0](https://github.com/lostisland/faraday/releases/tag/v1.1.0) (2020-10-17)
### Features
* Makes parameters sorting configurable (#1162 @wishdev)
* Introduces `flat_encode` option for multipart adapter. (#1163 @iMacTia)
* Include request info in exceptions raised by RaiseError Middleware (#1181 @SandroDamilano)
### Fixes
* Avoid `last arg as keyword param` warning when building user middleware on Ruby 2.7 (#1153 @dgholz)
* Limits net-http-persistent version to < 4.0 (#1156 @iMacTia)
* Update `typhoeus` to new stable version (`1.4`) (#1159 @AlexWayfer)
* Properly fix test failure with Rack 2.1+. (#1171 @voxik)
### Documentation
* Improves documentation on how to contribute to the site by using Docker. (#1175 @iMacTia)
* Remove retry_change_requests from documentation (#1185 @stim371)
### Misc
* Link from GitHub Actions badge to CI workflow (#1141 @olleolleolle)
* Return tests of `Test` adapter (#1147 @AlexWayfer)
* Add 1.0 release to wording in CONTRIBUTING (#1155 @olleolleolle)
* Fix linting bumping Rubocop to 0.90.0 (#1182 @iMacTia)
* Drop `git ls-files` in gemspec (#1183 @utkarsh2102)
* Upgrade CI to ruby/setup-ruby (#1187 @gogainda)
## [v1.0.1](https://github.com/lostisland/faraday/releases/tag/v1.0.1) (2020-03-29)
### Fixes
* Use Net::HTTP#start(&block) to ensure closed TCP connections (#1117)
* Fully qualify constants to be checked (#1122)
* Allows `parse` method to be private/protected in response middleware (#1123)
* Encode Spaces in Query Strings as '%20' Instead of '+' (#1125)
* Limits rack to v2.0.x (#1127)
* Adapter Registry reads also use mutex (#1136)
### Documentation
* Retry middleware documentation fix (#1109)
* Docs(retry): precise usage of retry-after (#1111)
* README: Link the logo to the website (#1112)
* Website: add search bar (#1116)
* Fix request/response mix-up in docs text (#1132)
## [v1.0](https://github.com/lostisland/faraday/releases/tag/v1.0.0) (2020-01-22)
Features:
* Add #trace support to Faraday::Connection #861 (@technoweenie)
* Add the log formatter that is easy to override and safe to inherit #889 (@prikha)
* Support standalone adapters #941 (@iMacTia)
* Introduce Faraday::ConflictError for 409 response code #979 (@lucasmoreno)
* Add support for setting `read_timeout` option separately #1003 (@springerigor)
* Refactor and cleanup timeout settings across adapters #1022 (@technoweenie)
* Create ParamPart class to allow multipart posts with JSON content and file upload at the same time #1017 (@jeremy-israel)
* Copy UploadIO const -> FilePart for consistency with ParamPart #1018, #1021 (@technoweenie)
* Implement streaming responses in the Excon adapter #1026 (@technoweenie)
* Add default implementation of `Middleware#close`. #1069 (@ioquatix)
* Add `Adapter#close` so that derived classes can call super. #1091 (@ioquatix)
* Add log_level option to logger default formatter #1079 (@amrrbakry)
* Fix empty array for FlatParamsEncoder `{key: []} -> "key="` #1084 (@mrexox)
Bugs:
* Explicitly require date for DateTime library in Retry middleware #844 (@nickpresta)
* Refactor Adapter as final endpoints #846 (@iMacTia)
* Separate Request and Response bodies in Faraday::Env #847 (@iMacTia)
* Implement Faraday::Connection#options to make HTTP requests with the OPTIONS verb. #857 (@technoweenie)
* Multipart: Drop Ruby 1.8 String behavior compat #892 (@olleolleolle)
* Fix Ruby warnings in Faraday::Options.memoized #962 (@technoweenie)
* Allow setting min/max SSL version for a Net::HTTP::Persistent connection #972, #973 (@bdewater, @olleolleolle)
* Fix instances of frozen empty string literals #1040 (@BobbyMcWho)
* remove temp_proxy and improve proxy tests #1063 (@technoweenie)
* improve error initializer consistency #1095 (@technoweenie)
Misc:
* Convert minitest suite to RSpec #832 (@iMacTia, with help from @gaynetdinov, @Insti, @technoweenie)
* Major effort to update code to RuboCop standards. #854 (@olleolleolle, @iMacTia, @technoweenie, @htwroclau, @jherdman, @Drenmi, @Insti)
* Rubocop #1044, #1047 (@BobbyMcWho, @olleolleolle)
* Documentation tweaks (@adsteel, @Hubro, @iMacTia, @olleolleolle, @technoweenie)
* Update license year #981 (@Kevin-Kawai)
* Configure Jekyll plugin jekyll-remote-theme to support Docker usage #999 (@Lewiscowles1986)
* Fix Ruby 2.7 warnings #1009 (@tenderlove)
* Cleanup adapter connections #1023 (@technoweenie)
* Describe clearing cached stubs #1045 (@viraptor)
* Add project metadata to the gemspec #1046 (@orien)
## v0.17.4
Fixes:
* NetHttp adapter: wrap Errno::EADDRNOTAVAIL (#1114, @embs)
* Fix === for subclasses of deprecated classes (#1243, @mervync)
## v0.17.3
Fixes:
* Reverts changes in error classes hierarchy. #1092 (@iMacTia)
* Fix Ruby 1.9 syntax errors and improve Error class testing #1094 (@BanzaiMan,
@mrexox, @technoweenie)
Misc:
* Stops using `&Proc.new` for block forwarding. #1083 (@olleolleolle)
* Update CI to test against ruby 2.0-2.7 #1087, #1099 (@iMacTia, @olleolleolle,
@technoweenie)
* require FARADAY_DEPRECATE=warn to show Faraday v1.0 deprecation warnings
#1098 (@technoweenie)
## v0.17.1
Final release before Faraday v1.0, with important fixes for Ruby 2.7.
Fixes:
* RaiseError response middleware raises exception if HTTP client returns a nil
status. #1042 (@jonnyom, @BobbyMcWho)
Misc:
* Fix Ruby 2.7 warnings (#1009)
* Add `Faraday::Deprecate` to warn about upcoming v1.0 changes. (#1054, #1059,
#1076, #1077)
* Add release notes up to current in CHANGELOG.md (#1066)
* Port minimal rspec suite from main branch to run backported tests. (#1058)
## v0.17.0
This release is the same as v0.15.4. It was pushed to cover up releases
v0.16.0-v0.16.2.
## v0.15.4
* Expose `pool_size` as a option for the NetHttpPersistent adapter (#834)
## v0.15.3
* Make Faraday::Request serialisable with Marshal. (#803)
* Add DEFAULT_EXCEPTIONS constant to Request::Retry (#814)
* Add support for Ruby 2.6 Net::HTTP write_timeout (#824)
## v0.15.2
* Prevents `Net::HTTP` adapters to retry request internally by setting `max_retries` to 0 if available (Ruby 2.5+). (#799)
* Fixes `NestedParamsEncoder` handling of empty array values (#801)
## v0.15.1
* NetHttpPersistent adapter better reuse of SSL connections (#793)
* Refactor: inline cached_connection (#797)
* Logger middleware: use $stdout instead of STDOUT (#794)
* Fix: do not memoize/reuse Patron session (#796)
Also in this release:
* Allow setting min/max ssl version for Net::HTTP (#792)
* Allow setting min/max ssl version for Excon (#795)
## v0.15.0
Features:
* Added retry block option to retry middleware. (#770)
* Retry middleware improvements (honour Retry-After header, retry statuses) (#773)
* Improve response logger middleware output (#784)
Fixes:
* Remove unused class error (#767)
* Fix minor typo in README (#760)
* Reuse persistent connections when using net-http-persistent (#778)
* Fix Retry middleware documentation (#781)
* Returns the http response when giving up on retrying by status (#783)
## v0.14.0
Features:
* Allow overriding env proxy #754 (@iMacTia)
* Remove legacy Typhoeus adapter #715 (@olleolleolle)
* External Typhoeus Adapter Compatibility #748 (@iMacTia)
* Warn about missing adapter when making a request #743 (@antstorm)
* Faraday::Adapter::Test stubs now support entire urls (with host) #741 (@erik-escobedo)
Fixes:
* If proxy is manually provided, this takes priority over `find_proxy` #724 (@iMacTia)
* Fixes the behaviour for Excon's open_timeout (not setting write_timeout anymore) #731 (@apachelogger)
* Handle all connection timeout messages in Patron #687 (@stayhero)
## v0.13.1
* Fixes an incompatibility with Addressable::URI being used as uri_parser
## v0.13.0
Features:
* Dynamically reloads the proxy when performing a request on an absolute domain (#701)
* Adapter support for Net::HTTP::Persistent v3.0.0 (#619)
Fixes:
* Prefer #hostname over #host. (#714)
* Fixes an edge-case issue with response headers parsing (missing HTTP header) (#719)
## v0.12.2
* Parse headers from aggregated proxy requests/responses (#681)
* Guard against invalid middleware configuration with warning (#685)
* Do not use :insecure option by default in Patron (#691)
* Fixes an issue with HTTPClient not raising a `Faraday::ConnectionFailed` (#702)
* Fixes YAML serialization/deserialization for `Faraday::Utils::Headers` (#690)
* Fixes an issue with Options having a nil value (#694)
* Fixes an issue with Faraday.default_connection not using Faraday.default_connection_options (#698)
* Fixes an issue with Options.merge! and Faraday instrumentation middleware (#710)
## v0.12.1
* Fix an issue with Patron tests failing on jruby
* Fix an issue with new `rewind_files` feature that was causing an exception when the body was not an Hash
* Expose wrapped_exception in all client errors
* Add Authentication Section to the ReadMe
## v0.12.0.1
* Hotfix release to address an issue with TravisCI deploy on Rubygems
## v0.12.0
Features:
* Proxy feature now relies on Ruby `URI::Generic#find_proxy` and can use `no_proxy` ENV variable (not compatible with ruby < 2.0)
* Adds support for `context` request option to pass arbitrary information to middlewares
Fixes:
* Fix an issue with options that was causing new options to override defaults ones unexpectedly
* Rewind `UploadIO`s on retry to fix a compatibility issue
* Make multipart boundary unique
* Improvements in `README.md`
## v0.11.0
Features:
* Add `filter` method to Logger middleware
* Add support for Ruby2.4 and Minitest 6
* Introduce block syntax to customise the adapter
Fixes:
* Fix an issue that was allowing to override `default_connection_options` from a connection instance
* Fix a bug that was causing newline escape characters ("\n") to be used when building the Authorization header
## v0.10.1
- Fix an issue with HTTPClient adapter that was causing the SSL to be reset on every request
- Rescue `IOError` instead of specific subclass
- `Faraday::Utils::Headers` can now be successfully serialised in YAML
- Handle `default_connection_options` set with hash
## v0.10.0
Breaking changes:
- Drop support for Ruby 1.8
Features:
- Include wrapped exception/response in ClientErrors
- Add `response.reason_phrase`
- Provide option to selectively skip logging request/response headers
- Add regex support for pattern matching in `test` adapter
Fixes:
- Add `Faraday.respond_to?` to find methods managed by `method_missing`
- em-http: `request.host` instead of `connection.host` should be taken for SSL validations
- Allow `default_connection_options` to be merged when options are passed as url parameter
- Improve splitting key-value pairs in raw HTTP headers
## v0.9.2
Adapters:
- Enable gzip compression for httpclient
- Fixes default certificate store for httpclient not having default paths.
- Make excon adapter compatible with 0.44 excon version
- Add compatibility with Patron 0.4.20
- Determine default port numbers in Net::HTTP adapters (Addressable compatibility)
- em-http: wrap "connection closed by server" as ConnectionFailed type
- Wrap Errno::ETIMEDOUT in Faraday::Error::TimeoutError
Utils:
- Add Rack-compatible support for parsing `a[][b]=c` nested queries
- Encode nil values in queries different than empty strings. Before: `a=`; now: `a`.
- Have `Faraday::Utils::Headers#replace` clear internal key cache
- Dup the internal key cache when a Headers hash is copied
Env and middleware:
- Ensure `env` stored on middleware response has reference to the response
- Ensure that Response properties are initialized during `on_complete` (VCR compatibility)
- Copy request options in Faraday::Connection#dup
- Env custom members should be copied by Env.from(env)
- Honour per-request `request.options.params_encoder`
- Fix `interval_randomness` data type for Retry middleware
- Add maximum interval option for Retry middleware
## v0.9.1

42
Gemfile
View File

@ -1,27 +1,29 @@
# frozen_string_literal: true
source 'https://rubygems.org'
ruby RUBY_VERSION
# Even though we don't officially support JRuby, this dependency makes Faraday
# compatible with it, so we're leaving it in for jruby users to use it.
gem 'jruby-openssl', '~> 0.11.0', platforms: :jruby
gem 'ffi-ncurses', '~> 0.3', :platforms => :jruby
gem 'jruby-openssl', '~> 0.8.8', :platforms => :jruby
gem 'rake'
group :test do
gem 'coveralls', :require => false
gem 'em-http-request', '>= 1.1', :require => 'em-http'
gem 'em-synchrony', '>= 1.0.3', :require => ['em-synchrony', 'em-synchrony/em-http']
gem 'addressable', '< 2.4.0'
gem 'excon', '>= 0.27.4'
gem 'httpclient', '>= 2.2'
gem 'mime-types', '~> 1.25', :platforms => [:jruby, :ruby_18]
gem 'minitest', '>= 5.0.5'
gem 'net-http-persistent'
gem 'patron', '>= 0.4.2', :platforms => :ruby
gem 'rack-test', '>= 0.6', :require => 'rack/test'
gem 'rest-client', '~> 1.6.0', :platforms => [:jruby, :ruby_18]
group :development, :test do
gem 'bake-test-external'
gem 'coveralls_reborn', require: false
gem 'pry'
gem 'rack', '~> 3.0'
gem 'rake'
gem 'rspec', '~> 3.7'
gem 'rspec_junit_formatter', '~> 0.4'
gem 'simplecov'
gem 'sinatra', '~> 1.3'
gem 'typhoeus', '~> 1.3', :require => 'typhoeus'
gem 'webmock', '~> 3.4'
end
group :development, :lint do
gem 'racc', '~> 1.7' # for RuboCop, on Ruby 3.3
gem 'rubocop'
gem 'rubocop-packaging', '~> 0.5'
gem 'rubocop-performance', '~> 1.0'
gem 'yard-junk'
end
gemspec

View File

@ -1,4 +1,4 @@
Copyright (c) 2009-2017 Rick Olson, Zack Hobson
Copyright (c) 2009-2023 Rick Olson, Zack Hobson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

382
README.md
View File

@ -1,353 +1,46 @@
# Faraday
# [![Faraday](./docs/_media/home-logo.svg)][website]
[![Gem Version](https://badge.fury.io/rb/faraday.svg)](https://rubygems.org/gems/faraday)
[![Build Status](https://travis-ci.org/lostisland/faraday.svg)](https://travis-ci.org/lostisland/faraday)
[![Coverage Status](https://coveralls.io/repos/github/lostisland/faraday/badge.svg?branch=master)](https://coveralls.io/github/lostisland/faraday?branch=master)
[![Code Climate](https://codeclimate.com/github/lostisland/faraday/badges/gpa.svg)](https://codeclimate.com/github/lostisland/faraday)
[![Gitter](https://badges.gitter.im/lostisland/faraday.svg)](https://gitter.im/lostisland/faraday?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[![GitHub Actions CI](https://github.com/lostisland/faraday/workflows/CI/badge.svg)](https://github.com/lostisland/faraday/actions?query=workflow%3ACI)
[![GitHub Discussions](https://img.shields.io/github/discussions/lostisland/faraday?logo=github)](https://github.com/lostisland/faraday/discussions)
Faraday is an HTTP client library abstraction layer that provides a common interface over many
adapters (such as Net::HTTP) and embraces the concept of Rack middleware when processing the request/response cycle.
Take a look at [Awesome Faraday][awesome] for a list of available adapters and middleware.
Faraday is an HTTP client lib that provides a common interface over many
adapters (such as Net::HTTP) and embraces the concept of Rack middleware when
processing the request/response cycle.
## Why use Faraday?
Faraday supports these adapters out of the box:
Faraday gives you the power of Rack middleware for manipulating HTTP requests and responses,
making it easier to build sophisticated API clients or web service libraries that abstract away
the details of how HTTP requests are made.
* [Net::HTTP][net_http] _(default)_
* [Net::HTTP::Persistent][persistent]
* [Excon][]
* [Patron][]
* [EventMachine][]
* [HTTPClient][]
Faraday comes with a lot of features out of the box, such as:
* Support for multiple adapters (Net::HTTP, Typhoeus, Patron, Excon, HTTPClient, and more)
* Persistent connections (keep-alive)
* Parallel requests
* Automatic response parsing (JSON, XML, YAML)
* Customization of the request/response cycle with middleware
* Support for streaming responses
* Support for uploading files
* And much more!
Adapters are slowly being moved into their own gems, or bundled with HTTP clients:
## Getting Started
* [Typhoeus][]
The best starting point is the [Faraday Website][website], with its introduction and explanation.
It also includes a Rack adapter for hitting loaded Rack applications through
Rack::Test, and a Test adapter for stubbing requests by hand.
## API documentation
Available at [rubydoc.info](http://www.rubydoc.info/gems/faraday).
## Usage
### Basic Use
```ruby
response = Faraday.get 'http://sushi.com/nigiri/sake.json'
```
A simple `get` request can be performed by using the syntax described above. This works if you don't need to set up anything; you can roll with just the default middleware
stack and default adapter (see [Faraday::RackBuilder#initialize](https://github.com/lostisland/faraday/blob/master/lib/faraday/rack_builder.rb)).
A more flexible way to use Faraday is to start with a Connection object. If you want to keep the same defaults, you can use this syntax:
```ruby
conn = Faraday.new(:url => 'http://www.example.com')
response = conn.get '/users' # GET http://www.example.com/users'
```
Connections can also take an options hash as a parameter or be configured by using a block. Checkout the section called [Advanced middleware usage](#advanced-middleware-usage) for more details about how to use this block for configurations.
Since the default middleware stack uses url\_encoded middleware and default adapter, use them on building your own middleware stack.
```ruby
conn = Faraday.new(:url => 'http://sushi.com') do |faraday|
faraday.request :url_encoded # form-encode POST params
faraday.response :logger # log requests to $stdout
faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
end
# Filter sensitive information from logs with a regex matcher
conn = Faraday.new(:url => 'http://sushi.com/api_key=s3cr3t') do |faraday|
faraday.request :url_encoded # form-encode POST params
faraday.response :logger do | logger |
logger.filter(/(api_key=)(\w+)/,'\1[REMOVED]')
end
faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
end
```
Once you have the connection object, use it to make HTTP requests. You can pass parameters to it in a few different ways:
```ruby
## GET ##
response = conn.get '/nigiri/sake.json' # GET http://sushi.com/nigiri/sake.json
response.body
conn.get '/nigiri', { :name => 'Maguro' } # GET http://sushi.com/nigiri?name=Maguro
conn.get do |req| # GET http://sushi.com/search?page=2&limit=100
req.url '/search', :page => 2
req.params['limit'] = 100
end
## POST ##
conn.post '/nigiri', { :name => 'Maguro' } # POST "name=maguro" to http://sushi.com/nigiri
```
Some configuration options can be adjusted per request:
```ruby
# post payload as JSON instead of "www-form-urlencoded" encoding:
conn.post do |req|
req.url '/nigiri'
req.headers['Content-Type'] = 'application/json'
req.body = '{ "name": "Unagi" }'
end
## Per-request options ##
conn.get do |req|
req.url '/search'
req.options.timeout = 5 # open/read timeout in seconds
req.options.open_timeout = 2 # connection open timeout in seconds
end
```
And you can inject arbitrary data into the request using the `context` option:
```ruby
# Anything you inject using context option will be available in the env on all middlewares
conn.get do |req|
req.url '/search'
req.options.context = {
foo: 'foo',
bar: 'bar'
}
end
```
### Changing how parameters are serialized
Sometimes you need to send the same URL parameter multiple times with different
values. This requires manually setting the parameter encoder and can be done on
either per-connection or per-request basis.
```ruby
# per-connection setting
conn = Faraday.new :request => { :params_encoder => Faraday::FlatParamsEncoder }
conn.get do |req|
# per-request setting:
# req.options.params_encoder = my_encoder
req.params['roll'] = ['california', 'philadelphia']
end
# GET 'http://sushi.com?roll=california&roll=philadelphia'
```
The value of Faraday `params_encoder` can be any object that responds to:
* `encode(hash) #=> String`
* `decode(string) #=> Hash`
The encoder will affect both how query strings are processed and how POST bodies
get serialized. The default encoder is Faraday::NestedParamsEncoder.
## Authentication
Basic and Token authentication are handled by Faraday::Request::BasicAuthentication and Faraday::Request::TokenAuthentication respectively. These can be added as middleware manually or through the helper methods.
```ruby
Faraday.new(...) do |conn|
conn.basic_auth('username', 'password')
end
Faraday.new(...) do |conn|
conn.token_auth('authentication-token')
end
```
## Proxy
Faraday will try to automatically infer the proxy settings from your system using `URI#find_proxy`.
This will retrieve them from environment variables such as http_proxy, ftp_proxy, no_proxy, etc.
If for any reason you want to disable this behaviour, you can do so by setting the global varibale `ignore_env_proxy`:
```ruby
Faraday.ignore_env_proxy = true
```
You can also specify a custom proxy when initializing the connection
```ruby
Faraday.new('http://www.example.com', :proxy => 'http://proxy.com')
```
## Advanced middleware usage
The order in which middleware is stacked is important. Like with Rack, the
first middleware on the list wraps all others, while the last middleware is the
innermost one, so that must be the adapter.
```ruby
Faraday.new(...) do |conn|
# POST/PUT params encoders:
conn.request :multipart
conn.request :url_encoded
# Last middleware must be the adapter:
conn.adapter :net_http
end
```
This request middleware setup affects POST/PUT requests in the following way:
1. `Request::Multipart` checks for files in the payload, otherwise leaves
everything untouched;
2. `Request::UrlEncoded` encodes as "application/x-www-form-urlencoded" if not
already encoded or of another type
Swapping middleware means giving the other priority. Specifying the
"Content-Type" for the request is explicitly stating which middleware should
process it.
Examples:
```ruby
# uploading a file:
payload[:profile_pic] = Faraday::UploadIO.new('/path/to/avatar.jpg', 'image/jpeg')
# "Multipart" middleware detects files and encodes with "multipart/form-data":
conn.put '/profile', payload
```
## Writing middleware
Middleware are classes that implement a `call` instance method. They hook into
the request/response cycle.
```ruby
def call(request_env)
# do something with the request
# request_env[:request_headers].merge!(...)
@app.call(request_env).on_complete do |response_env|
# do something with the response
# response_env[:response_headers].merge!(...)
end
end
```
It's important to do all processing of the response only in the `on_complete`
block. This enables middleware to work in parallel mode where requests are
asynchronous.
The `env` is a hash with symbol keys that contains info about the request and,
later, response. Some keys are:
```
# request phase
:method - :get, :post, ...
:url - URI for the current request; also contains GET parameters
:body - POST parameters for :post/:put requests
:request_headers
# response phase
:status - HTTP response status code, such as 200
:body - the response body
:response_headers
```
## Ad-hoc adapters customization
Faraday is intended to be a generic interface between your code and the adapter. However, sometimes you need to access a feature specific to one of the adapters that is not covered in Faraday's interface.
When that happens, you can pass a block when specifying the adapter to customize it. The block parameter will change based on the adapter you're using. See below for some examples.
### NetHttp
```ruby
conn = Faraday.new(...) do |f|
f.adapter :net_http do |http| # yields Net::HTTP
http.idle_timeout = 100
http.verify_callback = lambda do | preverify_ok, cert_store |
# do something here...
end
end
end
```
### NetHttpPersistent
```ruby
conn = Faraday.new(...) do |f|
f.adapter :net_http_persistent, pool_size: 5 do |http| # yields Net::HTTP::Persistent
http.idle_timeout = 100
http.retry_change_requests = true
end
end
```
### Patron
```ruby
conn = Faraday.new(...) do |f|
f.adapter :patron do |session| # yields Patron::Session
session.max_redirects = 10
end
end
```
### HTTPClient
```ruby
conn = Faraday.new(...) do |f|
f.adapter :httpclient do |client| # yields HTTPClient
client.keep_alive_timeout = 20
client.ssl_config.timeout = 25
end
end
```
## Using Faraday for testing
```ruby
# It's possible to define stubbed request outside a test adapter block.
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
stub.get('/tamago') { |env| [200, {}, 'egg'] }
end
# You can pass stubbed request to the test adapter or define them in a block
# or a combination of the two.
test = Faraday.new do |builder|
builder.adapter :test, stubs do |stub|
stub.get('/ebi') { |env| [ 200, {}, 'shrimp' ]}
end
end
# It's also possible to stub additional requests after the connection has
# been initialized. This is useful for testing.
stubs.get('/uni') { |env| [ 200, {}, 'urchin' ]}
resp = test.get '/tamago'
resp.body # => 'egg'
resp = test.get '/ebi'
resp.body # => 'shrimp'
resp = test.get '/uni'
resp.body # => 'urchin'
resp = test.get '/else' #=> raises "no such stub" error
# If you like, you can treat your stubs as mocks by verifying that all of
# the stubbed calls were made. NOTE that this feature is still fairly
# experimental: It will not verify the order or count of any stub, only that
# it was called once during the course of the test.
stubs.verify_stubbed_calls
```
Need more details? See the [Faraday API Documentation][apidoc] to see how it works internally, or take a look at [Advanced techniques for calling HTTP APIs in Ruby](https://mattbrictson.com/blog/advanced-http-techniques-in-ruby) blog post from [@mattbrictson](https://github.com/mattbrictson) 🚀
## Supported Ruby versions
This library aims to support and is [tested against][travis] the following Ruby
implementations:
* Ruby 1.9.3+
* [JRuby][] 1.7+
* [Rubinius][] 2+
This library aims to support and is [tested against][actions] the currently officially supported Ruby
implementations. This means that, even without a major release, we could add or drop support for Ruby versions,
following their [EOL](https://endoflife.date/ruby).
Currently that means we support Ruby 3.0+
If something doesn't work on one of these Ruby versions, it's a bug.
This library may inadvertently work (or seem to work) on other Ruby
implementations, however support will only be provided for the versions listed
implementations and versions, however support will only be provided for the versions listed
above.
If you would like this library to support another Ruby version, you may
@ -361,21 +54,14 @@ of a major release, support for that Ruby version may be dropped.
Do you want to contribute to Faraday?
Open the issues page and check for the `help wanted` label!
But before you start coding, please read our [Contributing Guide](https://github.com/lostisland/faraday/blob/master/.github/CONTRIBUTING.md)
But before you start coding, please read our [Contributing Guide][contributing]
## Copyright
Copyright (c) 2009-2017 [Rick Olson](mailto:technoweenie@gmail.com), Zack Hobson.
See [LICENSE][] for details.
&copy; 2009 - 2023, the Faraday Team. Website and branding design by [Elena Lo Piccolo](https://elelopic.design).
[net_http]: http://ruby-doc.org/stdlib/libdoc/net/http/rdoc/Net/HTTP.html
[persistent]: https://github.com/drbrain/net-http-persistent
[travis]: https://travis-ci.org/lostisland/faraday
[excon]: https://github.com/excon/excon#readme
[patron]: http://toland.github.io/patron/
[eventmachine]: https://github.com/igrigorik/em-http-request#readme
[httpclient]: https://github.com/nahi/httpclient
[typhoeus]: https://github.com/typhoeus/typhoeus/blob/master/lib/typhoeus/adapters/faraday.rb
[jruby]: http://jruby.org/
[rubinius]: http://rubini.us/
[license]: LICENSE.md
[awesome]: https://github.com/lostisland/awesome-faraday/#adapters
[website]: https://lostisland.github.io/faraday
[contributing]: https://github.com/lostisland/faraday/blob/main/.github/CONTRIBUTING.md
[apidoc]: https://www.rubydoc.info/github/lostisland/faraday
[actions]: https://github.com/lostisland/faraday/actions

View File

@ -1,8 +1,12 @@
require 'rake/testtask'
# frozen_string_literal: true
task :default => :test
require 'rspec/core/rake_task'
require 'bundler'
desc "Run all tests"
task :test do
exec 'script/test'
Bundler::GemHelper.install_tasks
RSpec::Core::RakeTask.new(:spec) do |task|
task.ruby_opts = %w[-W]
end
task default: :spec

185
UPGRADING.md Normal file
View File

@ -0,0 +1,185 @@
## Faraday 2.0
### Adapters have moved!
With this release, we've officially moved all adapters, except for the `net_http` one, out of Faraday.
What that means, is that they won't be available out-of-the-box anymore,
and you'll instead need to add them to your Gemfile.
**NOTE: the `net_http` adapter was originally removed as well in version `2.0`, but quickly reintroduced in version `2.0.1`.
We strongly suggest you to skip version `2.0` and instead use version `2.0.1` or greater.**
#### Why was this decision made?
We've taken this decision for the following technical reasons:
* We wanted the Faraday gem to focus on providing a clean, standardized, middleware-stack-based API.
* We wanted to free the core team from maintaining all the different adapters, relying more on the community to
maintain them based on the broad interest. This will allow the core team to focus on implementing features
focused on the Faraday API more quickly, without having to push it on all adapters immediately.
* With the community creating more and more adapters, we wanted to avoid having first and second-class adapters
by having some of them included with the gem and others available externally.
* Moving adapters into separate gems solve the dependency issues once and for all.
Faraday will remain a dependency-free gem, while adapter gems will be able to automatically pull
any necessary dependency, without having to rely on the developer to do so.
#### So what will this mean for me?
We did our best to make this transition as painless as possible for you, so here is what we did.
* All adapters, except for the `net_http` one, have already been moved out and released as separate gems.
They've then been re-added into Faraday's v1 dependencies so that you wouldn't notice.
This means that immediately after v2.0 will be released, all the adapters that were previously available will be
already compatible with Faraday 2.0!
* We've setup an [Awesome Faraday](https://github.com/lostisland/awesome-faraday) repository, where you can find and discover adapters.
We also highlighted their unique features and level of compliance with Faraday's features.
#### That's great! What should I change in my code immediately after upgrading?
* If you just use the default `net_http` adapter, then you don't need to do anything!
* Otherwise, add the corresponding adapter gem to your Gemfile (e.g. `faraday-net_http_persistent`). Then, simply require them after you require `faraday`.
```ruby
# Gemfile
gem 'faraday'
gem 'faraday-net_http_persistent'
# Code
require 'faraday'
require 'faraday/net_http_persistent'
```
### Faraday Middleware Deprecation
In case you never used it, [Faraday Middleware](https://github.com/lostisland/faraday_middleware) is a handy collection of middleware that have so far been maintained by the Faraday core team.
With Faraday 2.0 focusing on becoming an ecosystem, rather than an out-of-the-box solution, it only made sense to take the same approach for middleware as we did for adapters. For this reason, `faraday_middleware` will not be updated to support Faraday 2.0.
Instead, we'll support the transition from centralised-repo collection of middleware to individual middleware gems, effectively replicating what we did with adapters. Each middleware will have its own repository and gem, and it will allow developers to only add the ones they require to their Gemfile.
So don't fret yet! We're doing our best to support our `faraday_middleware` users out there, so here are the steps we've taken to make this work:
* We've promoted the highly popular JSON middleware (both request encoding and response parsing) to a core middleware and it will now be shipped together with Faraday. We expect many `faraday_middleware` users will be able to just stop using the extra dependency thanks to this.
* We've created a [faraday-middleware-template](https://github.com/lostisland/faraday-middleware-template) repository that will make creating a new middleware gem simple and straightforward.
* We've added a middleware section to the [awesome-faraday](https://github.com/lostisland/awesome-faraday) repo, so you can easily find available middleware when you need it.
It will obviously take time for some of the middleware in `faraday_middleware` to make its way into a separate gem, so we appreciate this might be an upgrade obstacle for some. However this is part of an effort to focus the core team resources tackling the most requested features.
We'll be listening to the community and prioritize middleware that are most used, and will be welcoming contributors who want to become owners of the middleware when these become separate from the `faraday_middleware` repo.
### Bundled middleware moved out
Moving middleware into its own gem makes sense not only for `faraday_middleware`, but also for middleware bundled with Faraday.
As of v2.0, the `retry` and `multipart` middleware have been moved to separate `faraday-retry` and `faraday-multipart` gems.
These have been identified as good candidates due to their complexity and external dependencies.
Thanks to this change, we were able to make Faraday 2.0 completely dependency free 🎉 (the only exception being `ruby2_keywords`, which will be necessary only while we keep supporting Ruby 2.6).
#### So what should I do if I currently use the `retry` or `multipart` middleware?
Upgrading is pretty simple, because the middleware was simply moved out to external gems.
All you need to do is to add them to your gemfile (either `faraday-retry` or `faraday-multipart` and require them before usage:
```ruby
# Gemfile
gem 'faraday-multipart'
gem 'faraday-retry'
# Connection initializer
require 'faraday/retry'
require 'faraday/multipart'
conn = Faraday.new(url) do |f|
f.request :multipart
f.request :retry
# ...
end
```
### Autoloading and dependencies
Faraday has until now provided and relied on a complex dynamic dependencies system.
This would allow to reference classes and require dependencies only when needed (e.g. when running the first request) based
on the middleware/adapters used.
As part of Faraday v2.0, we've removed all external dependencies, which means we don't really need this anymore.
This change should not affect you directly, but if you're registering middleware then be aware of the new syntax:
```ruby
# `name` here can be anything you want.
# `klass` is your custom middleware class.
# This method can also be called on `Faraday::Adapter`, `Faraday::Request` and `Faraday::Response`
Faraday::Middleware.register_middleware(name: klass)
```
The `register_middleware` method also previously allowed to provide a symbol, string, proc, or array
but this has been removed from the v2.0 release to simplify the interface.
(EDIT: symbol/string/proc have subsequently been reintroduced in v2.2, but not the array).
### Authentication helper methods in Connection have been removed
You were previously able to call `authorization`, `basic_auth` and `token_auth` against the `Connection` object, but this helper methods have now been dropped.
Instead, you should be using the equivalent middleware, as explained in [this page](https://lostisland.github.io/faraday/#/middleware/included/authentication).
For more details, see https://github.com/lostisland/faraday/pull/1306
### The `dependency` method in middlewares has been removed
In Faraday 1, a deferred require was used with the `dependency` method.
In Faraday 2, that method has been removed. In your middleware gems, use a regular `require` at the top of the file,
### Others
* Rename `Faraday::Request#method` to `#http_method`.
* Remove `Faraday::Response::Middleware`. You can now use the new `on_complete` callback provided by `Faraday::Middleware`.
* `Faraday.default_connection_options` will now be deep-merged into new connections to avoid overriding them (e.g. headers).
* `Faraday::Builder#build` method is not exposed through `Faraday::Connection` anymore and does not reset the handlers if called multiple times. This method should be used internally only.
## Faraday 1.0
### Errors
* Removes sub-class constants definition from `Faraday::Error`. A sub-class (e.g. `ClientError`) was previously accessible
either through the `Faraday` module (e.g. `Faraday::ClientError`) or through the `Faraday::Error` class (e.g. `Faraday::Error::ClientError`).
The latter is no longer available and the former should be used instead, so check your `rescue`s.
* Introduces a new `Faraday::ServerError` (5xx status codes) alongside the existing `Faraday::ClientError` (4xx status codes).
Please note `Faraday::ClientError` was previously used for both.
* Introduces new Errors that describe the most common REST status codes:
* Faraday::BadRequestError (400)
* Faraday::UnauthorizedError (401)
* Faraday::ForbiddenError (403)
* Faraday::ProxyAuthError (407). Please note this raised a `Faraday::ConnectionFailed` before.
* Faraday::ConflictError (409)
* Faraday::UnprocessableEntityError (422)
* The following error classes have changed the hierarchy to better mirror their real-world usage and semantic meaning:
* TimeoutError < ServerError (was < ClientError)
* ConnectionFailed < Error (was < ClientError)
* SSLError < Error (was < ClientError)
* ParsingError < Error (was < ClientError)
* RetriableResponse < Error (was < ClientError)
### Custom adapters
If you have written a custom adapter, please be aware that `env.body` is now an alias to the two new properties `request_body` and `response_body`.
This should work without you noticing if your adapter inherits from `Faraday::Adapter` and calls `save_response`, but if it doesn't, then please ensure you set the `status` BEFORE the `body` while processing the response.
### Others
* Dropped support for jruby and Rubinius.
* Officially supports Ruby 2.4+
* In order to specify the adapter you now MUST use the `#adapter` method on the connection builder. If you don't do so and your adapter inherits from `Faraday::Adapter` then Faraday will raise an exception. Otherwise, Faraday will automatically push the default adapter at the end of the stack causing your request to be executed twice.
```ruby
class OfficialAdapter < Faraday::Adapter
...
end
class MyAdapter
...
end
# This will raise an exception
conn = Faraday.new(...) do |f|
f.use OfficialAdapter
end
# This will cause Faraday inserting the default adapter at the end of the stack
conn = Faraday.new(...) do |f|
f.use MyAdapter
end
# You MUST use `adapter` method
conn = Faraday.new(...) do |f|
f.adapter AnyAdapter
end
```

15
bin/console Executable file
View File

@ -0,0 +1,15 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
require 'bundler/setup'
require 'faraday'
# You can add fixtures and/or initialization code here to make experimenting
# with your gem easier. You can also use a different console, if you like.
# (If you use this, don't forget to add pry to your Gemfile!)
# require "pry"
# Pry.start
require 'irb'
IRB.start(__FILE__)

7
bin/setup Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
set -vx
gem install bundler
bundle install --jobs 4

7
bin/test Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
set -vx
bundle exec rubocop -a --format progress
bundle exec rspec

3
config/external.yaml Normal file
View File

@ -0,0 +1,3 @@
faraday-net_http:
url: https://github.com/lostisland/faraday-net_http.git
command: bundle exec rspec

0
docs/.nojekyll Normal file
View File

21
docs/README.md Normal file
View File

@ -0,0 +1,21 @@
# Faraday Docs
Faraday Docs are powered by [Docsify](https://docsify.js.org/#/).
## Development
### Setup
From the Faraday project root, run the following:
```bash
npm install # this will install the necessary dependencies
```
### Running the Docs Locally
To preview your changes locally, run the following:
```bash
npm run docs
```

BIN
docs/_media/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 700 B

34
docs/_media/home-logo.svg Normal file
View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="1240px" height="300px" viewBox="0 0 1240 300" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 55.1 (78136) - https://sketchapp.com -->
<title>Custom Preset</title>
<desc>Created with Sketch.</desc>
<defs>
<linearGradient x1="0%" y1="50.0025809%" x2="113.816993%" y2="50.0025809%" id="linearGradient-1">
<stop stop-color="#F59D2A" offset="0%"></stop>
<stop stop-color="#F59A2C" offset="1%"></stop>
<stop stop-color="#EE6A4B" offset="21%"></stop>
<stop stop-color="#EA4D5F" offset="36%"></stop>
<stop stop-color="#E94266" offset="45%"></stop>
<stop stop-color="#D54F76" offset="54%"></stop>
<stop stop-color="#A0719F" offset="74%"></stop>
<stop stop-color="#52A3DB" offset="100%"></stop>
</linearGradient>
<linearGradient x1="0%" y1="50%" x2="183.555899%" y2="50%" id="linearGradient-2">
<stop stop-color="#F59D2A" offset="0%"></stop>
<stop stop-color="#F59A2C" offset="1%"></stop>
<stop stop-color="#EE6A4B" offset="21%"></stop>
<stop stop-color="#EA4D5F" offset="36%"></stop>
<stop stop-color="#E94266" offset="45%"></stop>
<stop stop-color="#D54F76" offset="54%"></stop>
<stop stop-color="#A0719F" offset="74%"></stop>
<stop stop-color="#52A3DB" offset="100%"></stop>
</linearGradient>
</defs>
<g id="Custom-Preset" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Group" transform="translate(20.000000, 19.000000)">
<path d="M345.711907,185.953203 L345.711907,130.649668 L409.242825,130.649668 L409.242825,149.259747 L359.313152,149.259747 L359.313152,185.953203 L345.711907,185.953203 Z M345.711907,81.4653477 L345.711907,78.0438675 L409.242825,78.0438675 L409.242825,96.9280012 L359.313152,96.9280012 L345.711907,81.4653477 Z M475.145406,167.86656 L466.738303,185.953203 L448.442753,185.953203 L497.884985,78.0438675 L530.897775,150.066099 L512.352129,150.066099 L497.884985,118.376317 L483.302413,150.066099 L475.145406,167.86656 Z M547.118435,185.953203 L528.384219,185.953203 L520.084002,167.069069 L538.700762,167.069069 L547.118435,185.953203 Z M622.335524,147.242759 L641.738952,185.953203 L623.642586,185.953203 L596.194284,131.865422 L610.277417,131.998972 C614.530023,132.025452 618.575201,130.097023 621.323011,126.733283 C624.471929,123.282595 626.173163,118.679375 626.054208,113.931554 C626.151915,109.261236 624.44918,104.743216 621.323011,101.377847 C618.575201,98.0141076 614.530023,96.0856782 610.277417,96.1121585 L578.687017,96.1121585 L576.846084,94.0898288 L568.745982,78.0438675 L610.277417,78.0438675 C618.81961,77.9969308 626.950801,81.8406095 632.51588,88.5570399 C638.594115,95.489278 641.88686,104.566395 641.720542,113.931554 C641.851711,121.132427 639.930635,128.213452 636.197745,134.288402 C632.956055,139.967305 628.120172,144.486477 622.335524,147.242759 Z M721.15875,167.86656 L712.751646,185.953203 L694.456097,185.953203 L743.898329,78.0438675 L776.911118,150.066099 L758.365472,150.066099 L743.898329,118.376317 L729.315756,150.066099 L721.15875,167.86656 Z M791.780057,185.953203 L773.04584,185.953203 L764.745623,167.069069 L783.362384,167.069069 L791.780057,185.953203 Z M920.187937,132.046034 C920.259924,139.158187 918.908812,146.217512 916.207905,152.841002 C913.588118,159.130051 909.866145,164.94257 905.203116,170.026926 C900.598652,174.890932 895.040024,178.836169 888.845184,181.636972 C882.637851,184.502668 875.833361,185.978299 868.945023,185.953203 L835.03515,185.953203 L852.049787,167.850042 L869.044524,167.850042 C873.624514,167.867696 878.155982,166.94988 882.337831,165.157581 C886.48057,163.290008 890.178954,160.625132 893.203319,157.328438 C896.305844,153.940452 898.776475,150.064602 900.506678,145.871155 C904.056306,136.940326 904.042131,127.065943 900.466878,118.144531 C898.744294,113.921677 896.228329,110.0382 893.044118,106.687249 C889.978019,103.434133 886.289393,100.776289 882.17863,98.8581057 C878.034816,97.0756201 873.545852,96.1516664 869.004724,96.1465488 L852.009987,96.1465488 L835.03515,78.0438675 L869.044524,78.0438675 C875.931423,78.0308282 882.733032,79.5058345 888.944685,82.3596188 C895.081854,85.1969559 900.594424,89.1382728 905.183216,93.9696651 C909.934465,99.0482971 913.701736,104.900743 916.307405,111.251066 C918.974333,117.880965 920.291628,124.940081 920.187937,132.046034 Z M986.096196,167.86656 L977.689093,185.953203 L959.393543,185.953203 L1008.83578,78.0438675 L1041.84857,150.066099 L1023.30292,150.066099 L1008.83578,118.376317 L994.253203,150.066099 L986.096196,167.86656 Z M1058.06923,185.953203 L1039.3621,185.953203 L1031.03479,167.069069 L1049.62463,167.069069 L1058.06923,185.953203 Z M1150.72976,146.72732 L1150.72976,146.593769 L1122.56982,185.953203 L1101.32432,185.953203 L1140.28084,131.998535 L1101.34363,78.0438675 L1122.58913,78.0438675 L1150.74907,117.42238 L1179.0249,78.0438675 L1200,78.0438675 L1161.37182,131.998535 L1150.72976,146.72732 Z M1149.9863,146.987685 L1121.60014,185.953203 L1149.9863,146.836069 L1149.9863,146.987685 Z" id="Shape" fill="url(#linearGradient-1)" fill-rule="nonzero"></path>
<path d="M126.085885,259.671354 L62.1555891,196.228083 L129.023404,129.824126 L195.924855,196.228083 L132.016984,259.671354 C131.230558,260.452312 130.163785,260.89107 129.051434,260.89107 C127.939083,260.89107 126.87231,260.452312 126.085885,259.671354 Z M1.18617949,134.865638 C0.416659626,134.073078 -0.00984556455,133.003843 0.000172577645,131.893267 C0.0109185487,130.782692 0.457336942,129.721798 1.24153626,128.944087 L127.510327,1.33410005 C128.285004,0.549370018 129.33657,0.108388479 130.433165,0.108388479 C131.529759,0.108388479 132.581326,0.549370018 133.356002,1.33410005 L259.569436,128.944087 C260.346251,129.729247 260.782681,130.794302 260.782681,131.904862 C260.782681,133.015423 260.346251,134.080478 259.569436,134.865638 L211.11012,183.861156 L130.388879,102.246734 L49.6565668,183.87235 L1.18617949,134.865638 L1.18617949,134.865638 Z" id="Shape" fill="url(#linearGradient-2)"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
docs/_media/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
docs/_media/middleware.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

BIN
docs/_media/overview.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

BIN
docs/_media/repo-card.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 KiB

33
docs/_sidebar.md Normal file
View File

@ -0,0 +1,33 @@
* Getting Started
* [Quick Start](getting-started/quick-start.md)
* [The Env Object](getting-started/env-object.md)
* [Dealing with Errors](getting-started/errors.md)
* [Migrating from rest-client](getting-started/rest-client-migration.md)
* Customization
* [Configuration](customization/index.md)
* [Connection Options](customization/connection-options.md)
* [Request Options](customization/request-options.md)
* [SSL Options](customization/ssl-options.md)
* [Proxy Options](customization/proxy-options.md)
* Middleware
* [Overview](middleware/index.md)
* [Included](middleware/included/index.md)
* [Authentication](middleware/included/authentication.md)
* [URL Encoding](middleware/included/url-encoding.md)
* [JSON Encoding/Decoding](middleware/included/json.md)
* [Instrumentation](middleware/included/instrumentation.md)
* [Logging](middleware/included/logging.md)
* [Raising Errors](middleware/included/raising-errors.md)
* [Writing custom middleware](middleware/custom-middleware.md)
* Adapters
* [Overview](adapters/index.md)
* [Net::HTTP](adapters/net-http.md)
* [Test Adapter](adapters/test-adapter.md)
* Writing custom adapters
* [Overview](adapters/custom/index.md)
* [Parallel Requests](adapters/custom/parallel-requests.md)
* [Streaming Responses](adapters/custom/streaming.md)
* [Test your adapter](adapters/custom/testing.md)
* Advanced Features
* [Parallel Requests](advanced/parallel-requests.md)
* [Streaming Responses](advanced/streaming-responses.md)

View File

@ -0,0 +1,161 @@
# Writing custom adapters
!> A template for writing your own middleware is available in the [faraday-adapter-template](https://github.com/lostisland/faraday-adapter-template) repository.
Adapters have methods that can help you implement support for a new backend.
This example will use a fictional HTTP backend gem called `FlorpHttp`. It doesn't
exist. Its only function is to make this example more concrete.
## An Adapter _is_ a Middleware
When you subclass `Faraday::Adapter`, you get helpful methods defined and all you need to do is to
extend the `call` method (remember to call `super` inside it!):
```ruby
module Faraday
class Adapter
class FlorpHttp < Faraday::Adapter
def call(env)
super
# Perform the request and call `save_response`
end
end
end
end
```
Now, there are only two things which are actually mandatory for an adapter middleware to function:
- a `#call` implementation
- a call to `#save_response` inside `#call`, which will keep the Response around.
These are the only two things, the rest of this text is about methods which make the authoring easier.
Like any other middleware, the `env` parameter passed to `#call` is an instance of [Faraday::Env][env-object].
This object will contain all the information about the request, as well as the configuration of the connection.
Your adapter is expected to deal with SSL and Proxy settings, as well as any other configuration options.
## Connection options and configuration block
Users of your adapter have two main ways of configuring it:
* connection options: these can be passed to your adapter initializer and are automatically stored into an instance variable `@connection_options`.
* configuration block: this can also be provided to your adapter initializer and it's stored into an instance variable `@config_block`.
Both of these are automatically managed by `Faraday::Adapter#initialize`, so remember to call it with `super` if you create an `initialize` method in your adapter.
You can then use them in your adapter code as you wish, since they're pretty flexible.
Below is an example of how they can be used:
```ruby
# You can use @connection_options and @config_block in your adapter code
class FlorpHttp < Faraday::Adapter
def call(env)
# `connection` internally calls `build_connection` and yields the result
connection do |conn|
# perform the request using configured `conn`
end
end
def build_connection(env)
conn = FlorpHttp::Client.new(pool_size: @connection_options[:pool_size] || 10)
@config_block&.call(conn)
conn
end
end
# Then your users can provide them when initializing the connection
Faraday.new(...) do |f|
# ...
# in this example, { pool_size: 5 } will be provided as `connection_options`
f.adapter :florp_http, pool_size: 5 do |client|
# this block is useful to set properties unique to HTTP clients that are not
# manageable through the Faraday API
client.some_fancy_florp_http_property = 10
end
end
```
## Implementing `#close`
Just like middleware, adapters can implement a `#close` method. It will be called when the connection is closed.
In this method, you should close any resources that you opened in `#initialize` or `#call`, like sockets or files.
```ruby
class FlorpHttp < Faraday::Adapter
def close
@socket.close if @socket
end
end
```
## Helper methods
`Faraday::Adapter` provides some helper methods to make it easier to implement adapters.
### `#save_response`
The most important helper method and the only one you're expected to call from your `#call` method.
This method is responsible for, among other things, the following:
* Take the `env` object and save the response into it.
* Set the `:response` key in the `env` object.
* Parse headers using `Utils::Headers` and set the `:response_headers` key in the `env` object.
* Call `#finish` on the `Response` object, triggering the `#on_complete` callbacks in the middleware stack.
```ruby
class FlorpHttp < Faraday::Adapter
def call(env)
super
# Perform the request using FlorpHttp.
# Returns a FlorpHttp::Response object.
response = FlorpHttp.perform_request(...)
save_response(env, response.status, response.body, response.headers, response.reason_phrase)
end
end
```
`#save_response` also accepts a `finished` keyword argument, which defaults to `true`, but that you can set to false
if you don't want it to call `#finish` on the `Response` object.
### `#request_timeout`
Most HTTP libraries support different types of timeouts, like `:open_timeout`, `:read_timeout` and `:write_timeout`.
Faraday let you set individual values for each of these, as well as a more generic `:timeout` value on the request options.
This helper method knows about supported timeout types, and falls back to `:timeout` if they are not set.
You can use those when building the options you need for your backend's instantiation.
```ruby
class FlorpHttp < Faraday::Adapter
def call(env)
super
# Perform the request using FlorpHttp.
# Returns a FlorpHttp::Response object.
response = FlorpHttp.perform_request(
# ... other options ...,
open_timeout: request_timeout(:open, env[:request]),
read_timeout: request_timeout(:read, env[:request]),
write_timeout: request_timeout(:write, env[:request])
)
# Call save_response
end
end
```
## Register your adapter
Like middleware, you may register a nickname for your adapter.
People can then refer to your adapter with that name when initializing their connection.
You do that using `Faraday::Adapter.register_middleware`, like this:
```ruby
class FlorpHttp < Faraday::Adapter
# ...
end
Faraday::Adapter.register_middleware(florp_http: FlorpHttp)
```
[env-object]: /getting-started/env-object.md

View File

@ -0,0 +1,75 @@
# Adding support for parallel requests
!> This is slightly more involved, and this section is not fully formed.
Vague example, excerpted from [the test suite about parallel requests](https://github.com/lostisland/faraday/blob/main/spec/support/shared_examples/request_method.rb#L179)
```ruby
response_1 = nil
response_2 = nil
conn.in_parallel do
response_1 = conn.get('/about')
response_2 = conn.get('/products')
end
puts response_1.status
puts response_2.status
```
First, in your class definition, you can tell Faraday that your backend supports parallel operation:
```ruby
class FlorpHttp < ::Faraday::Adapter
dependency do
require 'florp_http'
end
self.supports_parallel = true
end
```
Then, implement a method which returns a ParallelManager:
```ruby
class FlorpHttp < ::Faraday::Adapter
dependency do
require 'florp_http'
end
self.supports_parallel = true
def self.setup_parallel_manager(_options = nil)
FlorpParallelManager.new # NB: we will need to define this
end
def call(env)
# NB: you can call `in_parallel?` here to check if the current request
# is part of a parallel batch. Useful if you need to collect all requests
# into the ParallelManager before running them.
end
end
class FlorpParallelManager
# The execute method will be passed the same block as `in_parallel`,
# so you can either collect the requests or just wrap them into a wrapper,
# depending on how your adapter works.
def execute(&block)
run_async(&block)
end
end
```
### A note on the old, deprecated interface
Prior to the introduction of the `execute` method, the `ParallelManager` was expected to implement a `run` method
and the execution of the block was done by the Faraday connection BEFORE calling that method.
This approach made the `ParallelManager` implementation harder and forced you to keep state around.
The new `execute` implementation allows to avoid this shortfall and support different flows.
As of Faraday 2.0, `run` is still supported in case `execute` is not implemented by the `ParallelManager`,
but this method should be considered deprecated.
For reference, please see an example using `run` from [em-synchrony](https://github.com/lostisland/faraday-em_synchrony/blob/main/lib/faraday/adapter/em_synchrony.rb)
and its [ParallelManager implementation](https://github.com/lostisland/faraday-em_synchrony/blob/main/lib/faraday/adapter/em_synchrony/parallel_manager.rb).

View File

@ -0,0 +1,79 @@
# Adding support for streaming
Faraday supports streaming responses, which means that the response body is not loaded into memory all at once,
but instead it is read in chunks. This can be particularly useful when dealing with large responses.
Not all HTTP clients support this, so it is not required for adapters to support it.
However, if you do want to support it in your adapter, you can do so by leveraging helpers provided by the env object.
Let's see an example implementation first with some comments, and then we'll explain it in more detail:
```ruby
module Faraday
class Adapter
class FlorpHttp < Faraday::Adapter
def call(env)
super
if env.stream_response? # check if the user wants to stream the response
# start a streaming response.
# on_data is a block that will let users consume the response body
http_response = env.stream_response do |&on_data|
# perform the request using FlorpHttp
# the block will be called for each chunk of data
FlorpHttp.perform_request(...) do |chunk|
on_data.call(chunk)
end
end
# the body is already consumed by the block
# so it's good practice to set it to nil
http_response.body = nil
else
# perform the request normally, no streaming.
http_response = FlorpHttp.perform_request(...)
end
save_response(env, http_response.status, http_response.body, http_response.headers, http_response.reason_phrase)
end
end
end
end
```
## How it works
### `#stream_response?`
The first helper method we use is `#stream_response?`. This method is provided by the env object and it returns true
if the user wants to stream the response. This is controlled by the presence of an `on_data` callback in the request options.
### `#stream_response`
The second helper is `#stream_response`. This method is also provided by the env object and it takes a block.
The block will be called with a single argument, which is a callback that the user can use to consume the response body.
All your adapter needs to do, is to call this callback with each chunk of data that you receive from the server.
The `on_data` callback will internally call the callback provided by the user, so you don't need to worry about that.
It will also keep track of the number of bytes that have been read, and pass that information to the user's callback.
To see how this all works together, let's see an example of how a user would use this feature:
```ruby
# A buffer to store the streamed data
streamed = []
conn = Faraday.new('http://httpbingo.org')
conn.get('/stream/100') do |req|
# Set a callback which will receive tuples of chunk Strings,
# the sum of characters received so far, and the response environment.
# The latter will allow access to the response status, headers and reason, as well as the request info.
req.options.on_data = proc do |chunk, overall_received_bytes, env|
puts "Received #{overall_received_bytes} characters"
streamed << chunk
end
end
# Joins all response chunks together
streamed.join
```
For more details on the user experience, check the [Streaming Responses] page.
[Streaming Responses]: /advanced/streaming-responses.md

View File

@ -0,0 +1,60 @@
# Test your custom adapter
Faraday puts a lot of expectations on adapters, but it also provides you with useful tools to test your adapter
against those expectations. This guide will walk you through the process of testing your adapter.
## The adapter test suite
Faraday provides a test suite that you can use to test your adapter.
The test suite is located in the `spec/external_adapters/faraday_specs_setup.rb`.
All you need to do is to `require 'faraday_specs_setup'` in your adapter's `spec_helper.rb` file.
This will load the `an adapter` shared example group that you can use to test your adapter.
```ruby
require 'faraday_specs_setup'
RSpec.describe Faraday::Adapter::FlorpHttp do
it_behaves_like 'an adapter'
# You can then add any other test specific to this adapter here...
end
```
## Testing optional features
By default, `an adapter` will test your adapter against the required behaviour for an adapter.
However, there are some optional "features" that your adapter can implement, like parallel requests or streaming.
If your adapter implements any of those optional features, you can test it against those extra expectations
by calling the `features` method:
```ruby
RSpec.describe Faraday::Adapter::MyAdapter do
# Since not all adapters support all the features Faraday has to offer, you can use
# the `features` method to turn on only the ones you know you can support.
features :request_body_on_query_methods,
:compression,
:streaming
# Runs the tests provide by Faraday, according to the features specified above.
it_behaves_like 'an adapter'
# You can then add any other test specific to this adapter here...
end
```
### Available features
| Feature | Description |
|----------------------------------|----------------------------------------------------------------------------------------------------------|
| `:compression` | Tests that your adapter can handle `gzip` and `deflate` compressions. |
| `:local_socket_binding` | Tests that your adapter supports binding to a local socket via the `:bind` request option. |
| `:parallel` | Tests that your adapter supports parallel requests. See [Parallel requests][parallel] for more details. |
| `:reason_phrase_parse` | Tests that your adapter supports parsing the `reason_phrase` from the response. |
| `:request_body_on_query_methods` | Tests that your adapter supports sending a request body on `GET`, `HEAD`, `DELETE` and `TRACE` requests. |
| `:streaming` | Tests that your adapter supports streaming responses. See [Streaming][streaming] for more details. |
| `:trace_method` | Tests your adapter against the `TRACE` HTTP method. |
[streaming]: /adapters/custom/streaming.md
[parallel]: /adapters/custom/parallel-requests.md

46
docs/adapters/index.md Normal file
View File

@ -0,0 +1,46 @@
# Adapters
The Faraday Adapter interface determines how a Faraday request is turned into
a Faraday response object. Adapters are typically implemented with common Ruby
HTTP clients, but can have custom implementations. Adapters can be configured
either globally or per Faraday Connection through the configuration block.
For example, consider using `httpclient` as an adapter. Note that [faraday-httpclient](https://github.com/lostisland/faraday-httpclient) must be installed beforehand.
If you want to configure it globally, do the following:
```ruby
require 'faraday'
require 'faraday/httpclient'
Faraday.default_adapter = :httpclient
```
If you want to configure it per Faraday Connection, do the following:
```ruby
require 'faraday'
require 'faraday/httpclient'
conn = Faraday.new do |f|
f.adapter :httpclient
end
```
## Fantastic adapters and where to find them
Except for the default [Net::HTTP][net_http] adapter and the [Test Adapter][testing] adapter, which is for _test purposes only_,
adapters are distributed separately from Faraday and need to be manually installed.
They are usually available as gems, or bundled with HTTP clients.
While most adapters use a common Ruby HTTP client library, adapters can also
have completely custom implementations.
If you're just getting started you can find a list of featured adapters in [Awesome Faraday][awesome].
Anyone can create a Faraday adapter and distribute it. If you're interested learning more, check how to [build your own][build_adapters]!
[testing]: /adapters/test-adapter.md
[net_http]: /adapters/net-http.md
[awesome]: https://github.com/lostisland/awesome-faraday/#adapters
[build_adapters]: /adapters/custom/index.md

12
docs/adapters/net-http.md Normal file
View File

@ -0,0 +1,12 @@
# Net::HTTP Adapter
Faraday's Net::HTTP adapter is the default adapter. It uses the `Net::HTTP`
library that ships with Ruby's standard library.
Unless you have a specific reason to use a different adapter, this is probably
the adapter you want to use.
With the release of Faraday 2.0, the Net::HTTP adapter has been moved into a [separate gem][faraday-net_http],
but it has also been added as a dependency of Faraday.
That means you can use it without having to install it or require it explicitly.
[faraday-net_http]: https://github.com/lostisland/faraday-net_http

View File

@ -0,0 +1,117 @@
# Test Adapter
The built-in Faraday Test adapter lets you define stubbed HTTP requests. This can
be used to mock out network services in an application's unit tests.
The easiest way to do this is to create the stubbed requests when initializing
a `Faraday::Connection`. Stubbing a request by path yields a block with a
`Faraday::Env` object. The stub block expects an Array return value with three
values: an Integer HTTP status code, a Hash of key/value headers, and a
response body.
```ruby
conn = Faraday.new do |builder|
builder.adapter :test do |stub|
# block returns an array with 3 items:
# - Integer response status
# - Hash HTTP headers
# - String response body
stub.get('/ebi') do |env|
[
200,
{ 'Content-Type': 'text/plain', },
'shrimp'
]
end
# test exceptions too
stub.get('/boom') do
raise Faraday::ConnectionFailed
end
end
end
```
You can define the stubbed requests outside of the test adapter block:
```ruby
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
stub.get('/tamago') { |env| [200, {}, 'egg'] }
end
```
This Stubs instance can be passed to a new Connection:
```ruby
conn = Faraday.new do |builder|
builder.adapter :test, stubs do |stub|
stub.get('/ebi') { |env| [ 200, {}, 'shrimp' ]}
end
end
```
It's also possible to stub additional requests after the connection has been
initialized. This is useful for testing.
```ruby
stubs.get('/uni') { |env| [ 200, {}, 'urchin' ]}
```
You can also stub the request body with a string or a proc.
It would be useful to pass a proc if it's OK only to check the parts of the request body are passed.
```ruby
stubs.post('/kohada', 'where=sea&temperature=24') { |env| [ 200, {}, 'spotted gizzard shad' ]}
stubs.post('/anago', -> (request_body) { JSON.parse(request_body).slice('name') == { 'name' => 'Wakamoto' } }) { |env| [200, {}, 'conger eel'] }
```
If you want to stub requests that exactly match a path, parameters, and headers,
`strict_mode` would be useful.
```ruby
stubs = Faraday::Adapter::Test::Stubs.new(strict_mode: true) do |stub|
stub.get('/ikura?nori=true', 'X-Soy-Sauce' => '5ml' ) { |env| [200, {}, 'ikura gunkan maki'] }
end
```
This stub expects the connection will be called like this:
```ruby
conn.get('/ikura', { nori: 'true' }, { 'X-Soy-Sauce' => '5ml' } )
```
If there are other parameters or headers included, the Faraday Test adapter
will raise `Faraday::Test::Stubs::NotFound`. It also raises the error
if the specified parameters (`nori`) or headers (`X-Soy-Sauce`) are omitted.
You can also enable `strict_mode` after initializing the connection.
In this case, all requests, including ones that have been already stubbed,
will be handled in a strict way.
```ruby
stubs.strict_mode = true
```
Finally, you can treat your stubs as mocks by verifying that all of the stubbed
calls were made. NOTE: this feature is still fairly experimental. It will not
verify the order or count of any stub.
```ruby
stubs.verify_stubbed_calls
```
After the test case is completed (possibly in an `after` hook), you should clear
the default connection to prevent it from being cached between different tests.
This allows for each test to have its own set of stubs
```ruby
Faraday.default_connection = nil
```
## Examples
Working [RSpec] and [test/unit] examples for a fictional JSON API client are
available.
[RSpec]: https://github.com/lostisland/faraday/blob/main/examples/client_spec.rb
[test/unit]: https://github.com/lostisland/faraday/blob/main/examples/client_test.rb

View File

@ -0,0 +1,58 @@
# Parallel Requests
Some adapters support running requests in parallel.
This can be achieved using the `#in_parallel` method on the connection object.
```ruby
# Install the Typhoeus adapter with `gem install faraday-typhoeus` first.
require 'faraday/typhoeus'
conn = Faraday.new('http://httpbingo.org') do |faraday|
faraday.adapter :typhoeus
end
now = Time.now
conn.in_parallel do
conn.get('/delay/3')
conn.get('/delay/3')
end
# This should take about 3 seconds, not 6.
puts "Time taken: #{Time.now - now}"
```
## A note on Async
You might have heard about [Async] and its native integration with Ruby 3.0.
The good news is that you can already use Async with Faraday (thanks to the [async-http-faraday] gem)
and this does not require the use of `#in_parallel` to run parallel requests.
Instead, you only need to wrap your Faraday code into an Async block:
```ruby
# Install the Async adapter with `gem install async-http-faraday` first.
require 'async/http/faraday'
conn = Faraday.new('http://httpbingo.org') do |faraday|
faraday.adapter :async_http
end
now = Time.now
# NOTE: This is not limited to a single connection anymore!
# You can run parallel requests spanning multiple connections.
Async do
Async { conn.get('/delay/3') }
Async { conn.get('/delay/3') }
end
# This should take about 3 seconds, not 6.
puts "Time taken: #{Time.now - now}"
```
The big advantage of using Async is that you can now run parallel requests *spanning multiple connections*,
whereas the `#in_parallel` method only works for requests that are made through the same connection.
[Async]: https://github.com/socketry/async
[async-http-faraday]: https://github.com/socketry/async-http-faraday

View File

@ -0,0 +1,35 @@
# Streaming Responses
Sometimes you might need to receive a streaming response.
You can do this with the `on_data` request option.
The `on_data` callback is a receives tuples of chunk Strings, and the total
of received bytes so far.
This example implements such a callback:
```ruby
# A buffer to store the streamed data
streamed = []
conn = Faraday.new('http://httpbingo.org')
conn.get('/stream/100') do |req|
# Set a callback which will receive tuples of chunk Strings,
# the sum of characters received so far, and the response environment.
# The latter will allow access to the response status, headers and reason, as well as the request info.
req.options.on_data = Proc.new do |chunk, overall_received_bytes, env|
puts "Received #{overall_received_bytes} characters"
streamed << chunk
end
end
# Joins all response chunks together
streamed.join
```
The `on_data` streaming is currently only supported by some adapters.
To see which ones, please refer to [Awesome Faraday][awesome] comparative table or check the adapter documentation.
Moreover, the `env` parameter was only recently added, which means some adapters may only have partial support
(i.e. only `chunk` and `overall_received_bytes` will be passed to your block).
[awesome]: https://github.com/lostisland/awesome-faraday/#adapters

View File

@ -0,0 +1,48 @@
# Connection Options
When initializing a new Faraday connection with `Faraday.new`, you can pass a hash of options to customize the connection.
All these options are optional.
| Option | Type | Default | Description |
|---------------------|-------------------|-----------------|---------------------------------------------------------------------------------------------------------------|
| `:request` | Hash | nil | Hash of request options. Will be use to build [RequestOptions]. |
| `:proxy` | URI, String, Hash | nil | Proxy options, either as a URL or as a Hash of [ProxyOptions]. |
| `:ssl` | Hash | nil | Hash of SSL options. Will be use to build [SSLOptions]. |
| `:url` | URI, String | nil | URI or String base URL. This can also be passed as positional argument. |
| `:parallel_manager` | | nil | Default parallel manager to use. This is normally set by the adapter, but you have the option to override it. |
| `:params` | Hash | nil | URI query unencoded key/value pairs. |
| `:headers` | Hash | nil | Hash of unencoded HTTP header key/value pairs. |
| `:builder_class` | Class | RackBuilder | A custom class to use as the middleware stack builder. |
| `:builder` | Object | Rackbuilder.new | An instance of a custom class to use as the middleware stack builder. |
## Example
```ruby
options = {
request: {
open_timeout: 5,
timeout: 5
},
proxy: {
uri: 'https://proxy.com',
user: 'proxy_user',
password: 'proxy_password'
},
ssl: {
ca_file: '/path/to/ca_file',
ca_path: '/path/to/ca_path',
verify: true
},
url: 'https://example.com',
params: { foo: 'bar' },
headers: { 'X-Api-Key' => 'secret', 'X-Api-Version' => '2' }
}
conn = Faraday.new(options) do |faraday|
# ...
end
```
[RequestOptions]: /customization/request-options.md
[ProxyOptions]: /customization/proxy-options.md
[SSLOptions]: /customization/ssl-options.md

105
docs/customization/index.md Normal file
View File

@ -0,0 +1,105 @@
# Configuration
Faraday is highly configurable and allows you to customize the way requests are made.
This applies to both the connection and the request, but can also cover things like SSL and proxy settings.
Below are some examples of how to customize Faraday requests.
Configuration can be set up with the connection and/or adjusted per request.
As connection options:
```ruby
conn = Faraday.new('http://httpbingo.org', request: { timeout: 5 })
conn.get('/ip')
```
Or as per-request options:
```ruby
conn.get do |req|
req.url '/ip'
req.options.timeout = 5
end
```
You can also inject arbitrary data into the request using the `context` option.
This will be available in the `env` on all middleware.
```ruby
conn.get do |req|
req.url '/get'
req.options.context = {
foo: 'foo',
bar: 'bar'
}
end
```
## Changing how parameters are serialized
Sometimes you need to send the same URL parameter multiple times with different values.
This requires manually setting the parameter encoder and can be done on
either per-connection or per-request basis.
This applies to all HTTP verbs.
Per-connection setting:
```ruby
conn = Faraday.new request: { params_encoder: Faraday::FlatParamsEncoder }
conn.get('', { roll: ['california', 'philadelphia'] })
```
Per-request setting:
```ruby
conn.get do |req|
req.options.params_encoder = Faraday::FlatParamsEncoder
req.params = { roll: ['california', 'philadelphia'] }
end
```
### Custom serializers
You can build your custom encoder, if you like.
The value of Faraday `params_encoder` can be any object that responds to:
* `#encode(hash) #=> String`
* `#decode(string) #=> Hash`
The encoder will affect both how Faraday processes query strings and how it
serializes POST bodies.
The default encoder is `Faraday::NestedParamsEncoder`.
### Order of parameters
By default, parameters are sorted by name while being serialized.
Since this is really useful to provide better cache management and most servers don't really care about parameters order, this is the default behaviour.
However you might find yourself dealing with a server that requires parameters to be in a specific order.
When that happens, you can configure the encoder to skip sorting them.
This configuration is supported by both the default `Faraday::NestedParamsEncoder` and `Faraday::FlatParamsEncoder`:
```ruby
Faraday::NestedParamsEncoder.sort_params = false
# or
Faraday::FlatParamsEncoder.sort_params = false
```
## Proxy
Faraday will try to automatically infer the proxy settings from your system using [`URI#find_proxy`][ruby-find-proxy].
This will retrieve them from environment variables such as http_proxy, ftp_proxy, no_proxy, etc.
If for any reason you want to disable this behaviour, you can do so by setting the global variable `ignore_env_proxy`:
```ruby
Faraday.ignore_env_proxy = true
```
You can also specify a custom proxy when initializing the connection:
```ruby
conn = Faraday.new('http://www.example.com', proxy: 'http://proxy.com')
```
[ruby-find-proxy]: https://ruby-doc.org/stdlib-2.6.3/libdoc/uri/rdoc/URI/Generic.html#method-i-find_proxy

View File

@ -0,0 +1,30 @@
# Proxy Options
Proxy options can be provided to the connection constructor or set on a per-request basis via [RequestOptions](/customization/request-options.md).
All these options are optional.
| Option | Type | Default | Description |
|-------------|-------------|---------|-----------------|
| `:uri` | URI, String | nil | Proxy URL. |
| `:user` | String | nil | Proxy user. |
| `:password` | String | nil | Proxy password. |
## Example
```ruby
# Proxy options can be passed to the connection constructor and will be applied to all requests.
proxy_options = {
uri: 'http://proxy.example.com:8080',
user: 'username',
password: 'password'
}
conn = Faraday.new(proxy: proxy_options) do |faraday|
# ...
end
# You can then override them on a per-request basis.
conn.get('/foo') do |req|
req.options.proxy.update(uri: 'http://proxy2.example.com:8080')
end
```

View File

@ -0,0 +1,39 @@
# Request Options
Request options can be provided to the connection constructor or set on a per-request basis.
All these options are optional.
| Option | Type | Default | Description |
|-------------------|-------------------|----------------------------------------------------------------|-------------------------------------------------------------------------|
| `:params_encoder` | Class | `Faraday::Utils.nested_params_encoder` (`NestedParamsEncoder`) | A custom class to use as the params encoder. |
| `:proxy` | URI, String, Hash | nil | Proxy options, either as a URL or as a Hash of [ProxyOptions]. |
| `:bind` | Hash | nil | Hash of bind options. Requires the `:host` and `:port` keys. |
| `:timeout` | Integer, Float | nil (adapter default) | The max number of seconds to wait for the request to complete. |
| `:open_timeout` | Integer, Float | nil (adapter default) | The max number of seconds to wait for the connection to be established. |
| `:read_timeout` | Integer, Float | nil (adapter default) | The max number of seconds to wait for one block to be read. |
| `:write_timeout` | Integer, Float | nil (adapter default) | The max number of seconds to wait for one block to be written. |
| `:boundary` | String | nil | The boundary string for multipart requests. |
| `:context` | Hash | nil | Arbitrary data that you can pass to your request. |
| `:on_data` | Proc | nil | A callback that will be called when data is received. See [Streaming] |
## Example
```ruby
# Request options can be passed to the connection constructor and will be applied to all requests.
request_options = {
params_encoder: Faraday::FlatParamsEncoder,
timeout: 5
}
conn = Faraday.new(request: request_options) do |faraday|
# ...
end
# You can then override them on a per-request basis.
conn.get('/foo') do |req|
req.options.timeout = 10
end
```
[ProxyOptions]: /customization/proxy-options.md
[SSLOptions]: /advanced/streaming-responses.md

View File

@ -0,0 +1,35 @@
# SSL Options
Faraday supports a number of SSL options, which can be provided while initializing the connection.
| Option | Type | Default | Description |
|--------------------|----------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------|
| `:verify` | Boolean | true | Verify SSL certificate. Defaults to `true`. |
| `:verify_hostname` | Boolean | true | Verify SSL certificate hostname. Defaults to `true`. |
| `:hostname` | String | nil | Server hostname for SNI (see [SSL docs](https://ruby-doc.org/3.2.2/exts/openssl/OpenSSL/SSL/SSLSocket.html#method-i-hostname-3D)). |
| `:ca_file` | String | nil | Path to a CA file in PEM format. |
| `:ca_path` | String | nil | Path to a CA directory. |
| `:verify_mode` | Integer | nil | Any `OpenSSL::SSL::` constant (see [SSL docs](https://ruby-doc.org/3.2.2/exts/openssl/OpenSSL/SSL.html)). |
| `:cert_store` | OpenSSL::X509::Store | nil | OpenSSL certificate store. |
| `:client_cert` | OpenSSL::X509::Certificate | nil | Client certificate. |
| `:client_key` | OpenSSL::PKey::RSA, OpenSSL::PKey::DSA | nil | Client private key. |
| `:certificate` | OpenSSL::X509::Certificate | nil | Certificate (Excon only). |
| `:private_key` | OpenSSL::PKey::RSA | nil | Private key (Excon only). |
| `:verify_depth` | Integer | nil | Maximum depth for the certificate chain verification. |
| `:version` | Integer | nil | SSL version (see [SSL docs](https://ruby-doc.org/3.2.2/exts/openssl/OpenSSL/SSL/SSLContext.html#method-i-ssl_version-3D)). |
| `:min_version` | Integer | nil | Minimum SSL version (see [SSL docs](https://ruby-doc.org/3.2.2/exts/openssl/OpenSSL/SSL/SSLContext.html#method-i-min_version-3D)). |
| `:max_version` | Integer | nil | Maximum SSL version (see [SSL docs](https://ruby-doc.org/3.2.2/exts/openssl/OpenSSL/SSL/SSLContext.html#method-i-max_version-3D)). |
| `:ciphers` | String | nil | Ciphers supported (see [SSL docs](https://ruby-doc.org/3.2.2/exts/openssl/OpenSSL/SSL/SSLContext.html#method-i-ciphers-3D)). |
## Example
```ruby
ssl_options = {
ca_file: '/path/to/ca_file',
min_version: :TLS1_2
}
conn = Faraday.new(ssl: options) do |faraday|
# ...
end
```

View File

@ -0,0 +1,51 @@
# The Env Object
Inspired by Rack, Faraday uses an `env` object to pass data between middleware.
This object is initialized at the beginning of the request and passed down the middleware stack.
The adapter is then responsible to run the HTTP request and set the `response` property on the `env` object,
which is then passed back up the middleware stack.
You can read more about how the `env` object is used in the [Middleware - How it works](/middleware/index?id=how-it-works) section.
Because of its nature, the `env` object is a complex structure that holds a lot of information and can
therefore be a bit intimidating at first. This page will try to explain the different properties of the `env` object.
## Properties
Please also note that these properties are not all available at the same time: while configuration
and request properties are available at the beginning of the request, response properties are only
available after the request has been performed (i.e. in the `on_complete` callback of middleware).
| Property | Type | Request | Response | Description |
|---------------------|----------------------------|:------------------:|:------------------:|-----------------------------|
| `:method` | `Symbol` | :heavy_check_mark: | :heavy_check_mark: | The HTTP method to use. |
| `:request_body` | `String` | :heavy_check_mark: | :heavy_check_mark: | The request body. |
| `:url` | `URI` | :heavy_check_mark: | :heavy_check_mark: | The request URL. |
| `:request` | `Faraday::RequestOptions` | :heavy_check_mark: | :heavy_check_mark: | The request options. |
| `:request_headers` | `Faraday::Utils::Headers` | :heavy_check_mark: | :heavy_check_mark: | The request headers. |
| `:ssl` | `Faraday::SSLOptions` | :heavy_check_mark: | :heavy_check_mark: | The SSL options. |
| `:parallel_manager` | `Faraday::ParallelManager` | :heavy_check_mark: | :heavy_check_mark: | The parallel manager. |
| `:params` | `Hash` | :heavy_check_mark: | :heavy_check_mark: | The request params. |
| `:response` | `Faraday::Response` | :x: | :heavy_check_mark: | The response. |
| `:response_headers` | `Faraday::Utils::Headers` | :x: | :heavy_check_mark: | The response headers. |
| `:status` | `Integer` | :x: | :heavy_check_mark: | The response status code. |
| `:reason_phrase` | `String` | :x: | :heavy_check_mark: | The response reason phrase. |
| `:response_body` | `String` | :x: | :heavy_check_mark: | The response body. |
## Helpers
The `env` object also provides some helper methods to make it easier to work with the properties.
| Method | Description |
|-------------------------|--------------------------------------------------------------------------------------------------|
| `#body`/`#current_body` | Returns the request or response body, based on the presence of `#status`. |
| `#success?` | Returns `true` if the response status is in the 2xx range. |
| `#needs_body?` | Returns `true` if there's no body yet, and the method is in the set of `Env::MethodsWithBodies`. |
| `#clear_body` | Clears the body, if it's present. That includes resetting the `Content-Length` header. |
| `#parse_body?` | Returns `true` unless the status indicates otherwise (e.g. 204, 304). |
| `#parallel?` | Returns `true` if a parallel manager is available. |
| `#stream_response?` | Returns `true` if the `on_data` streaming callback has been provided. |
| `#stream_response` | Helper method to implement streaming in adapters. See [Support streaming in your adapter]. |
[Support streaming in your adapter]: /adapters/custom/streaming.md

View File

@ -0,0 +1,17 @@
# Dealing with Errors
As an abstraction layer between the user and the underlying HTTP library,
it's important that Faraday provides a consistent interface for dealing with errors.
This is especially important when dealing with multiple adapters, as each adapter may raise different errors.
Below is a list of errors that Faraday may raise, and that you should be prepared to handle.
| Error | Description |
|-----------------------------|--------------------------------------------------------------------------------|
| `Faraday::Error` | Base class for all Faraday errors, also used for generic or unexpected errors. |
| `Faraday::ConnectionFailed` | Raised when the connection to the remote server failed. |
| `Faraday::TimeoutError` | Raised when the connection to the remote server timed out. |
| `Faraday::SSLError` | Raised when the connection to the remote server failed due to an SSL error. |
If you add the `raise_error` middleware, Faraday will also raise additional errors for 4xx and 5xx responses.
You can find the full list of errors in the [raise_error middleware](/middleware/included/raising-errors) page.

View File

@ -0,0 +1,266 @@
# Quick Start
## Installation
Add this line to your applications `Gemfile`:
```ruby
gem 'faraday'
```
And then execute:
```bash
$ bundle
```
Or install it yourself as:
```bash
$ gem install faraday
```
## Usage
### Quick requests
Let's fetch the home page for the wonderful [httpbingo.org](https://httpbingo.org) service.
You can make a simple `GET` request using `Faraday.get`:
```ruby
response = Faraday.get('http://httpbingo.org')
```
This returns a `Faraday::Response` object with the response status, headers, and body.
```ruby
response.status
# => 200
response.headers
# => {"server"=>"Fly/c375678 (2021-04-23)", "content-type"=> ...
response.body
# => "<!DOCTYPE html><html> ...
```
### Faraday Connection
The recommended way to use Faraday, especially when integrating to 3rd party services and APIs, is to create
a `Faraday::Connection`. The connection initializer allows you to set:
- default request headers & query parameters
- network settings like proxy or timeout
- common URL base path
- Faraday adapter & middleware (see below)
Create a `Faraday::Connection` by calling `Faraday.new`. You can then call each HTTP verb
(`get`, `post`, ...) on your `Faraday::Connection` to perform a request:
```ruby
conn = Faraday.new(
url: 'http://httpbingo.org',
params: {param: '1'},
headers: {'Content-Type' => 'application/json'}
)
response = conn.post('/post') do |req|
req.params['limit'] = 100
req.body = {query: 'chunky bacon'}.to_json
end
# => POST http://httpbingo.org/post?param=1&limit=100
```
### GET, HEAD, DELETE, TRACE
Faraday supports the following HTTP verbs that typically don't include a request body:
- `get(url, params = nil, headers = nil)`
- `head(url, params = nil, headers = nil)`
- `delete(url, params = nil, headers = nil)`
- `trace(url, params = nil, headers = nil)`
You can specify URI query parameters and HTTP headers when making a request.
```ruby
response = conn.get('get', { boom: 'zap' }, { 'User-Agent' => 'myapp' })
# => GET http://httpbingo.org/get?boom=zap
```
### POST, PUT, PATCH
Faraday also supports HTTP verbs with bodies. Instead of query parameters, these
accept a request body:
- `post(url, body = nil, headers = nil)`
- `put(url, body = nil, headers = nil)`
- `patch(url, body = nil, headers = nil)`
```ruby
# POST 'application/x-www-form-urlencoded' content
response = conn.post('post', 'boom=zap')
# POST JSON content
response = conn.post('post', '{"boom": "zap"}',
"Content-Type" => "application/json")
```
#### Posting Forms
Faraday will automatically convert key/value hashes into proper form bodies
thanks to the `url_encoded` middleware included in the default connection.
```ruby
# POST 'application/x-www-form-urlencoded' content
response = conn.post('post', boom: 'zap')
# => POST 'boom=zap' to http://httpbingo.org/post
```
### Detailed HTTP Requests
Faraday supports a longer style for making requests. This is handy if you need
to change many of the defaults, or if the details of the HTTP request change
according to method arguments. Each of the HTTP verb helpers can yield a
`Faraday::Request` that can be modified before being sent.
This example shows a hypothetical search endpoint that accepts a JSON request
body as the actual search query.
```ruby
response = conn.post('post') do |req|
req.params['limit'] = 100
req.headers['Content-Type'] = 'application/json'
req.body = {query: 'chunky bacon'}.to_json
end
# => POST http://httpbingo.org/post?limit=100
```
### Using Middleware
Configuring your connection or request with predefined headers and parameters is a good start,
but the real power of Faraday comes from its middleware stack.
Middleware are classes that allow you to hook into the request/response cycle and modify the request.
They can help you with things like:
* adding authentication headers
* parsing JSON responses
* logging requests and responses
* raise errors on 4xx and 5xx responses
* and much more!
For example, let's say you want to call an API that:
* requires an authentication token in the `Authorization` header
* expects JSON request bodies
* returns JSON responses
and on top of that, you want to automatically raise errors on 4xx and 5xx responses,
as well as log all requests and responses.
You can easily achieve all of the above by adding the necessary middleware to your connection:
```ruby
conn = Faraday.new(url: 'http://httpbingo.org') do |builder|
# Calls MyAuthStorage.get_auth_token on each request to get the auth token
# and sets it in the Authorization header with Bearer scheme.
builder.request :authorization, 'Bearer', -> { MyAuthStorage.get_auth_token }
# Sets the Content-Type header to application/json on each request.
# Also, if the request body is a Hash, it will automatically be encoded as JSON.
builder.request :json
# Parses JSON response bodies.
# If the response body is not valid JSON, it will raise a Faraday::ParsingError.
builder.response :json
# Raises an error on 4xx and 5xx responses.
builder.response :raise_error
# Logs requests and responses.
# By default, it only logs the request method and URL, and the request/response headers.
builder.response :logger
end
# A simple example implementation for MyAuthStorage
class MyAuthStorage
def self.get_auth_token
rand(36 ** 8).to_s(36)
end
end
```
The connection can now be used to make requests.
```ruby
begin
response = conn.post('post', { payload: 'this ruby hash will become JSON' })
rescue Faraday::Error => e
# You can handle errors here (4xx/5xx responses, timeouts, etc.)
puts e.response[:status]
puts e.response[:body]
end
# At this point, you can assume the request was successful
puts response.body
# I, [2023-06-30T14:27:11.776511 #35368] INFO -- request: POST http://httpbingo.org/post
# I, [2023-06-30T14:27:11.776646 #35368] INFO -- request: User-Agent: "Faraday v2.7.8"
# Authorization: "Bearer wibzjgyh"
# Content-Type: "application/json"
# I, [2023-06-30T14:27:12.063897 #35368] INFO -- response: Status 200
# I, [2023-06-30T14:27:12.064260 #35368] INFO -- response: access-control-allow-credentials: "true"
# access-control-allow-origin: "*"
# content-type: "application/json; encoding=utf-8"
# date: "Fri, 30 Jun 2023 13:27:12 GMT"
# content-encoding: "gzip"
# transfer-encoding: "chunked"
# server: "Fly/a0b91024 (2023-06-13)"
# via: "1.1 fly.io"
# fly-request-id: "01H467RYRHA0YK4TQSZ7HS8ZFT-lhr"
# cf-team: "19ae1592b8000003bbaedcf400000001"
```
Faraday ships with a number of useful middleware, and you can also write your own.
To learn more about middleware, please check the [Middleware] section.
### Swapping Adapters
Faraday does not make HTTP requests itself, but instead relies on a Faraday adapter to do so.
By default, it will use the `Net::HTTP` adapter, which is part of the Ruby standard library.
Although `Net::HTTP` is the only adapter that ships with Faraday, there are [many other adapters
available as separate gems](https://github.com/lostisland/awesome-faraday#adapters).
Once you have installed an adapter, you can use it by passing the `adapter` option to `Faraday.new`:
```ruby
conn = Faraday.new(url: 'http://httpbingo.org') do |builder|
builder.adapter :async_http
end
```
To learn more about adapters, including how to write your own, please check the [Adapters] section.
### Default Connection, Default Adapter
Remember how we said that Faraday will automatically encode key/value hash
bodies into form bodies? Internally, the top level shortcut methods
`Faraday.get`, `post`, etc. use a simple default `Faraday::Connection`. The only
middleware used for the default connection is `:url_encoded`, which encodes
those form hashes, and the `default_adapter`.
You can change the default adapter or connection. Be careful because they're set globally.
```ruby
Faraday.default_adapter = :async_http # defaults to :net_http
# The default connection has only `:url_encoded` middleware.
# Note that if you create your own connection with middleware, it won't encode
# form bodies unless you too include the :url_encoded middleware!
Faraday.default_connection = Faraday.new do |conn|
conn.request :url_encoded
conn.response :logger
conn.adapter Faraday.default_adapter
end
```
[Adapters]: /adapters/index.md
[Middleware]: /middleware/index.md

View File

@ -0,0 +1,225 @@
# Migrating from `rest-client` to `Faraday`
The `rest-client` gem is in maintenance mode, and developers are encouraged to migrate to actively maintained alternatives like [`faraday`](https://github.com/lostisland/faraday). This guide highlights common usage patterns in `rest-client` and how to migrate them to `faraday`.
---
## Quick Comparison
| Task | rest-client example | faraday example |
| ----------------- | -------------------------------------------------------- | -------------------------------------------------------------------------- |
| Simple GET | `RestClient.get("https://httpbingo.org/get")` | `Faraday.get("https://httpbingo.org/get")` |
| GET with params | `RestClient.get(url, params: { id: 1 })` | `Faraday.get(url, { id: 1 })` |
| POST form data | `RestClient.post(url, { a: 1 })` | `Faraday.post(url, { a: 1 })` |
| POST JSON | `RestClient.post(url, obj.to_json, content_type: :json)` | `Faraday.post(url, obj.to_json, { 'Content-Type' => 'application/json' })` |
| Custom headers | `RestClient.get(url, { Authorization: 'Bearer token' })` | `Faraday.get(url, nil, { 'Authorization' => 'Bearer token' })` |
| Get response body | `response.body` | `response.body` |
| Get status code | `response.code` | `response.status` |
| Get headers | `response.headers` (returns `Hash<Symbol, String>`) | `response.headers` (returns `Hash<String, String>`) |
---
## Installation
In your `Gemfile`, replace `rest-client` with:
```ruby
gem "faraday"
```
Then run:
```sh
bundle install
```
---
## Basic HTTP Requests
### GET request
**rest-client:**
```ruby
RestClient.get("https://httpbingo.org/get")
```
**faraday:**
```ruby
Faraday.get("https://httpbingo.org/get")
```
---
### GET with Params
**rest-client:**
```ruby
RestClient.get("https://httpbingo.org/get", params: { id: 1, foo: "bar" })
```
**faraday:**
```ruby
Faraday.get("https://httpbingo.org/get", { id: 1, foo: "bar" })
```
---
### POST Requests
**rest-client:**
```ruby
RestClient.post("https://httpbingo.org/post", { foo: "bar" })
```
**faraday:**
```ruby
Faraday.post("https://httpbingo.org/post", { foo: "bar" })
```
---
### Sending JSON
**rest-client:**
```ruby
RestClient.post("https://httpbingo.org/post", { foo: "bar" }.to_json, content_type: :json)
```
**faraday (manual):**
```ruby
Faraday.post("https://httpbingo.org/post", { foo: "bar" }.to_json, { 'Content-Type' => 'application/json' })
```
**faraday (with middleware):**
```ruby
conn = Faraday.new(url: "https://httpbingo.org") do |f|
f.request :json # encode request body as JSON and set Content-Type
f.response :json # parse response body as JSON
end
conn.post("/post", { foo: "bar" })
```
---
## Handling Responses
**rest-client:**
```ruby
response = RestClient.get("https://httpbingo.org/headers")
response.code # => 200
response.body # => "..."
response.headers # => { content_type: "application/json", ... }
```
**faraday:**
> notice headers Hash keys are stringified, not symbolized like in rest-client
```ruby
response = Faraday.get("https://httpbingo.org/headers")
response.status # => 200
response.body # => "..."
response.headers # => { "content-type" => "application/json", ... }
```
---
## Error Handling
**rest-client:**
```ruby
begin
RestClient.get("https://httpbingo.org/status/404")
rescue RestClient::NotFound => e
puts e.response.code # 404
end
```
**faraday:**
> By default, Faraday does **not** raise exceptions for HTTP errors (like 404 or 500); it simply returns the response. If you want exceptions to be raised on HTTP error responses, include the `:raise_error` middleware.
>
> With `:raise_error`, Faraday will raise `Faraday::ResourceNotFound` for 404s and other exceptions for other 4xx/5xx responses.
>
> See also:
>
> * [Dealing with Errors](getting-started/errors.md)
> * [Raising Errors](middleware/included/raising-errors.md)
```ruby
conn = Faraday.new(url: "https://httpbingo.org") do |f|
f.response :raise_error
end
begin
conn.get("/status/404")
rescue Faraday::ResourceNotFound => e
puts e.response[:status] # 404
end
```
---
## Advanced Request Configuration
**rest-client:**
```ruby
RestClient::Request.execute(method: :get, url: "https://httpbingo.org/get", timeout: 10)
```
**faraday:**
```ruby
conn = Faraday.new(url: "https://httpbingo.org", request: { timeout: 10 })
conn.get("/get")
```
---
## Headers
**rest-client:**
```ruby
RestClient.get("https://httpbingo.org/headers", { Authorization: "Bearer token" })
```
**faraday:**
> Notice headers Hash expects stringified keys.
```ruby
Faraday.get("https://httpbingo.org/headers", nil, { "Authorization" => "Bearer token" })
```
---
## Redirects
**rest-client:**
Automatically follows GET/HEAD redirects by default.
**faraday:**
Use the `follow_redirects` middleware (not included by default):
```ruby
require "faraday/follow_redirects"
conn = Faraday.new(url: "https://httpbingo.org") do |f|
f.response :follow_redirects
end
```

121
docs/index.html Normal file
View File

@ -0,0 +1,121 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" type="image/x-icon" href="_media/favicon.png">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<!-- HTML Meta Tags -->
<title>Faraday Docs</title>
<meta name="description" content="Faraday is an HTTP client library abstraction layer that provides a common interface over many adapters (such as Net::HTTP) and embraces the concept of Rack middleware when processing the request/response cycle.">
<!-- OpenGraph Meta Tags -->
<meta property="og:url" content="https://lostisland.github.io/faraday/#/">
<meta property="og:type" content="website">
<meta property="og:title" content="Faraday Docs">
<meta property="og:description" content="Faraday is an HTTP client library abstraction layer that provides a common interface over many adapters (such as Net::HTTP) and embraces the concept of Rack middleware when processing the request/response cycle.">
<meta property="og:image" content="https://lostisland.github.io/faraday/_media/repo-card.png">
<!-- Twitter Meta Tags -->
<meta name="twitter:card" content="summary_large_image">
<meta property="twitter:domain" content="lostisland.github.io">
<meta property="twitter:url" content="https://lostisland.github.io/faraday/#/">
<meta name="twitter:title" content="Faraday Docs">
<meta name="twitter:description" content="Faraday is an HTTP client library abstraction layer that provides a common interface over many adapters (such as Net::HTTP) and embraces the concept of Rack middleware when processing the request/response cycle.">
<meta name="twitter:image" content="https://lostisland.github.io/faraday/_media/repo-card.png">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<link
rel="stylesheet"
href="//cdn.jsdelivr.net/npm/docsify-darklight-theme@latest/dist/style.min.css"
title="docsify-darklight-theme"
type="text/css"
/>
<link
rel="stylesheet"
href="//cdn.jsdelivr.net/npm/prism-themes/themes/prism-material-light.min.css"
id="prism-theme"
type="text/css"
/>
</head>
<body>
<div id="app"></div>
<!-- Docsify plugins -->
<script src="//cdn.jsdelivr.net/npm/docsify-edit-on-github"></script>
<!-- Docsify config -->
<script>
window.$docsify = {
name: 'Faraday',
repo: 'lostisland/faraday',
logo: '_media/home-logo.svg',
homepage: 'index.md',
search: true,
loadSidebar: true,
subMaxLevel: 4,
auto2top: true,
darklightTheme: {
dark: {
accent: '#EE4266',
prismTheme: 'prism-material-dark'
},
light: {
accent: '#EE4266',
prismTheme: 'prism-material-light'
}
},
plugins: [
EditOnGithubPlugin.create(
'https://github.com/lostisland/faraday/blob/main/docs/',
null,
'Edit this page on GitHub'
),
function pageFooter(hook, _vm) {
var footer = [
'<hr/>',
'<footer>',
'<span>© 2009 - 2023, the Faraday Team. </span>',
'<span>Website and branding design by <a href="https://elelopic.design" target="_blank" rel="noopener">Elena Lo Piccolo</a>.</span>',
'</footer>',
].join('');
hook.afterEach(function (html) {
return html + footer;
});
},
function prismThemeSwitcher(hook, _vm) {
// Switch Prism theme based on docsify-darklight-theme setting
let lightTheme = '//cdn.jsdelivr.net/npm/prism-themes/themes/prism-one-light.min.css';
let darkTheme = '//cdn.jsdelivr.net/npm/prism-themes/themes/prism-one-dark.min.css';
let switchTheme = () => {
console.log('Theme changed');
let theme = localStorage.getItem('DARK_LIGHT_THEME')
let link = document.getElementById('prism-theme');
link.setAttribute('href', theme === 'dark' ? darkTheme : lightTheme);
}
hook.ready(() => {
document.getElementById('main').addEventListener('click', switchTheme);
switchTheme();
});
},
]
}
</script>
<!-- Docsify v4 -->
<script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
<!-- Docsify Darklight Theme -->
<script
src="//cdn.jsdelivr.net/npm/docsify-darklight-theme@latest/dist/index.min.js"
type="text/javascript">
</script>
<!-- Prism Ruby highlight -->
<script src="//cdn.jsdelivr.net/npm/prismjs@v1.x/components/prism-ruby.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/prismjs@v1.x/plugins/autoloader/prism-autoloader.min.js"></script>
<!-- Other Plugins -->
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/docsify-copy-code/dist/docsify-copy-code.min.js"></script>
</body>
</html>

28
docs/index.md Normal file
View File

@ -0,0 +1,28 @@
# ![Faraday](_media/home-logo.svg)
Faraday is an HTTP client library abstraction layer that provides a common interface over many
adapters (such as Net::HTTP) and embraces the concept of Rack middleware when processing the request/response cycle.
## Why use Faraday?
Faraday gives you the power of Rack middleware for manipulating HTTP requests and responses,
making it easier to build sophisticated API clients or web service libraries that abstract away
the details of how HTTP requests are made.
Faraday comes with a lot of features out of the box, such as:
* Support for multiple adapters (Net::HTTP, Typhoeus, Patron, Excon, HTTPClient, and more)
* Persistent connections (keep-alive)
* Parallel requests
* Automatic response parsing (JSON, XML, YAML)
* Customization of the request/response cycle with middleware
* Support for streaming responses
* Support for uploading files
* And much more!
## Who uses Faraday?
Faraday is used by many popular Ruby libraries, such as:
* [Signet](https://github.com/googleapis/signet)
* [Octokit](https://github.com/octokit/octokit.rb)
* [Oauth2](https://bestgems.org/gems/oauth2)
* [Elasticsearch](https://github.com/elastic/elasticsearch-ruby)

View File

@ -0,0 +1,84 @@
# Writing custom middleware
!> A template for writing your own middleware is available in the [faraday-middleware-template](https://github.com/lostisland/faraday-middleware-template) repository.
The recommended way to write middleware is to make your middleware subclass `Faraday::Middleware`.
`Faraday::Middleware` simply expects your subclass to implement two methods: `#on_request(env)` and `#on_complete(env)`.
* `#on_request` is called when the request is being built and is given the `env` representing the request.
* `#on_complete` is called after the response has been received (that's right, it already supports parallel mode!) and receives the `env` of the response.
For both `env` parameters, please refer to the [Env Object](getting-started/env-object.md) page.
```ruby
class MyMiddleware < Faraday::Middleware
def on_request(env)
# do something with the request
# env[:request_headers].merge!(...)
end
def on_complete(env)
# do something with the response
# env[:response_headers].merge!(...)
end
end
```
## Having more control
For the majority of middleware, it's not necessary to override the `#call` method. You can instead use `#on_request` and `#on_complete`.
However, in some cases you may need to wrap the call in a block, or work around it somehow (think of a begin-rescue, for example).
When that happens, then you can override `#call`. When you do so, remember to call either `app.call(env)` or `super` to avoid breaking the middleware stack call!
```ruby
def call(request_env)
# do something with the request
# request_env[:request_headers].merge!(...)
@app.call(request_env).on_complete do |response_env|
# do something with the response
# response_env[:response_headers].merge!(...)
end
end
```
It's important to do all processing of the response only in the `#on_complete`
block. This enables middleware to work in parallel mode where requests are
asynchronous.
The `request_env` and `response_env` are both [Env Objects](getting-started/env-object.md) but note the amount of
information available in each one will differ based on the request/response lifecycle.
## Accepting configuration options
`Faraday::Middleware` also allows your middleware to accept configuration options.
These are passed in when the middleware is added to the stack, and can be accessed via the `options` getter.
```ruby
class MyMiddleware < Faraday::Middleware
def on_request(_env)
# access the foo option
puts options[:foo]
end
end
conn = Faraday.new(url: 'http://httpbingo.org') do |faraday|
faraday.use MyMiddleware, foo: 'bar'
end
```
## Registering your middleware
Users can use your middleware using the class directly, but you can also register it with Faraday so that
it can be used with the `use`, `request` or `response` methods as well.
```ruby
# Register for `use`
Faraday::Middleware.register_middleware(my_middleware: MyMiddleware)
# Register for `request`
Faraday::Request.register_middleware(my_middleware: MyMiddleware)
# Register for `response`
Faraday::Response.register_middleware(my_middleware: MyMiddleware)
```

View File

@ -0,0 +1,65 @@
# Authentication
The `Faraday::Request::Authorization` middleware allows you to automatically add an `Authorization` header
to your requests. It also features a handy helper to manage Basic authentication.
**Please note the way you use this middleware in Faraday 1.x is different**,
examples are available at the bottom of this page.
```ruby
Faraday.new(...) do |conn|
conn.request :authorization, 'Bearer', 'authentication-token'
end
```
### With a proc
You can also provide a proc, which will be evaluated on each request:
```ruby
Faraday.new(...) do |conn|
conn.request :authorization, 'Bearer', -> { MyAuthStorage.get_auth_token }
end
```
If the proc takes an argument, it will receive the forwarded `env` (see [The Env Object](getting-started/env-object.md)):
```ruby
Faraday.new(...) do |conn|
conn.request :authorization, 'Bearer', ->(env) { MyAuthStorage.get_auth_token(env) }
end
```
### Basic Authentication
The middleware will automatically Base64 encode your Basic username and password:
```ruby
Faraday.new(...) do |conn|
conn.request :authorization, :basic, 'username', 'password'
end
```
### Faraday 1.x usage
In Faraday 1.x, the way you use this middleware is slightly different:
```ruby
# Basic Auth request
# Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
Faraday.new(...) do |conn|
conn.request :basic_auth, 'username', 'password'
end
# Token Auth request
# `options` are automatically converted into `key=value` format
# Authorization: Token authentication-token <options>
Faraday.new(...) do |conn|
conn.request :token_auth, 'authentication-token', **options
end
# Generic Auth Request
# Authorization: Bearer authentication-token
Faraday.new(...) do |conn|
conn.request :authorization, 'Bearer', 'authentication-token'
end
```

View File

@ -0,0 +1,37 @@
# Included middleware
Faraday ships with some useful middleware that you can use to customize your request/response lifecycle.
Middleware are separated into two macro-categories: **Request Middleware** and **Response Middleware**.
The former usually deal with the request, encoding the parameters or setting headers.
The latter instead activate after the request is completed and a response has been received, like
parsing the response body, logging useful info or checking the response status.
### Request Middleware
**Request middleware** can modify Request details before the Adapter runs. Most
middleware set Header values or transform the request body based on the
content type.
* [`Authorization`][authentication] allows you to automatically add an Authorization header to your requests.
* [`UrlEncoded`][url_encoded] converts a `Faraday::Request#body` hash of key/value pairs into a url-encoded request body.
* [`Json Request`][json-request] converts a `Faraday::Request#body` hash of key/value pairs into a JSON request body.
* [`Instrumentation`][instrumentation] allows to instrument requests using different tools.
### Response Middleware
**Response middleware** receives the response from the adapter and can modify its details
before returning it.
* [`Json Response`][json-response] parses response body into a hash of key/value pairs.
* [`Logger`][logger] logs both the request and the response body and headers.
* [`RaiseError`][raise_error] checks the response HTTP code and raises an exception if it is a 4xx or 5xx code.
[authentication]: middleware/included/authentication.md
[url_encoded]: middleware/included/url-encoding
[json-request]: middleware/included/json#json-requests
[instrumentation]: middleware/included/instrumentation
[json-response]: middleware/included/json#json-responses
[logger]: middleware/included/logging
[raise_error]: middleware/included/raising-errors

View File

@ -0,0 +1,34 @@
# Instrumentation
The `Instrumentation` middleware allows to instrument requests using different tools.
Options for this middleware include the instrumentation `name` and the `instrumenter` you want to use.
They default to `request.faraday` and `ActiveSupport::Notifications` respectively, but you can provide your own:
```ruby
conn = Faraday.new(...) do |f|
f.request :instrumentation, name: 'custom_name', instrumenter: MyInstrumenter
...
end
```
### Example Usage
The `Instrumentation` middleware will use `ActiveSupport::Notifications` by default as instrumenter,
allowing you to subscribe to the default event name and instrument requests:
```ruby
conn = Faraday.new('http://example.com') do |f|
f.request :instrumentation
...
end
ActiveSupport::Notifications.subscribe('request.faraday') do |name, starts, ends, _, env|
url = env[:url]
http_method = env[:method].to_s.upcase
duration = ends - starts
$stdout.puts '[%s] %s %s (%.3f s)' % [url.host, http_method, url.request_uri, duration]
end
conn.get('/search', { a: 1, b: 2 })
#=> [example.com] GET /search?a=1&b=2 (0.529 s)
```

View File

@ -0,0 +1,81 @@
# JSON Encoding/Decoding
## JSON Requests
The `JSON` request middleware converts a `Faraday::Request#body` hash of key/value pairs into a JSON request body.
The middleware also automatically sets the `Content-Type` header to `application/json`,
processes only requests with matching Content-Type or those without a type and
doesn't try to encode bodies that already are in string form.
### Example Usage
```ruby
conn = Faraday.new(...) do |f|
f.request :json
...
end
conn.post('/', { a: 1, b: 2 })
# POST with
# Content-Type: application/json
# Body: {"a":1,"b":2}
```
### Using custom JSON encoders
By default, middleware utilizes Ruby's `json` to generate JSON strings.
Other encoders can be used by specifying `encoder` option for the middleware:
* a module/class which implements `dump`
* a module/class-method pair to be used
```ruby
require 'oj'
Faraday.new(...) do |f|
f.request :json, encoder: Oj
end
Faraday.new(...) do |f|
f.request :json, encoder: [Oj, :dump]
end
```
## JSON Responses
The `JSON` response middleware parses response body into a hash of key/value pairs.
The behaviour can be customized with the following options:
* **parser_options:** options that will be sent to the JSON.parse method. Defaults to {}.
* **content_type:** Single value or Array of response content-types that should be processed. Can be either strings or Regex. Defaults to `/\bjson$/`.
* **preserve_raw:** If set to true, the original un-parsed response will be stored in the `response.env[:raw_body]` property. Defaults to `false`.
### Example Usage
```ruby
conn = Faraday.new('http://httpbingo.org') do |f|
f.response :json, **options
end
conn.get('json').body
# => {"slideshow"=>{"author"=>"Yours Truly", "date"=>"date of publication", "slides"=>[{"title"=>"Wake up to WonderWidgets!", "type"=>"all"}, {"items"=>["Why <em>WonderWidgets</em> are great", "Who <em>buys</em> WonderWidgets"], "title"=>"Overview", "type"=>"all"}], "title"=>"Sample Slide Show"}}
```
### Using custom JSON decoders
By default, middleware utilizes Ruby's `json` to parse JSON strings.
Other decoders can be used by specifying `decoder` parser option for the middleware:
* a module/class which implements `load`
* a module/class-method pair to be used
```ruby
require 'oj'
Faraday.new(...) do |f|
f.response :json, parser_options: { decoder: Oj }
end
Faraday.new(...) do |f|
f.response :json, parser_options: { decoder: [Oj, :load] }
end
```

View File

@ -0,0 +1,114 @@
# Logging
The `Logger` middleware logs both the request and the response body and headers.
It is highly customizable and allows to mask confidential information if necessary.
### Basic Usage
```ruby
conn = Faraday.new(url: 'http://httpbingo.org') do |faraday|
faraday.response :logger # log requests and responses to $stdout
end
conn.get
# => INFO -- request: GET http://httpbingo.org/
# => DEBUG -- request: User-Agent: "Faraday v1.0.0"
# => INFO -- response: Status 301
# => DEBUG -- response: date: "Sun, 19 May 2019 16:05:40 GMT"
```
### Customize the logger
By default, the `Logger` middleware uses the Ruby `Logger.new($stdout)`.
You can customize it to use any logger you want by providing it when you add the middleware to the stack:
```ruby
conn = Faraday.new(url: 'http://httpbingo.org') do |faraday|
faraday.response :logger, MyLogger.new($stdout)
end
```
### Include and exclude headers/bodies
By default, the `logger` middleware logs only headers for security reasons, however, you can configure it
to log bodies and errors as well, or disable headers logging if you need to.
To do so, simply provide a configuration hash when you add the middleware to the stack:
```ruby
conn = Faraday.new(url: 'http://httpbingo.org') do |faraday|
faraday.response :logger, nil, { headers: true, bodies: true, errors: true }
end
```
You can also configure the `logger` middleware with a little more complex settings
like "do not log the request bodies, but log the response bodies".
```ruby
conn = Faraday.new(url: 'http://httpbingo.org') do |faraday|
faraday.response :logger, nil, { bodies: { request: false, response: true } }
end
```
Please note this only works with the default formatter.
### Filter sensitive information
You can filter sensitive information from Faraday logs using a regex matcher:
```ruby
conn = Faraday.new(url: 'http://httpbingo.org') do |faraday|
faraday.response :logger do | logger |
logger.filter(/(api_key=)([^&]+)/, '\1[REMOVED]')
end
end
conn.get('/', api_key: 'secret')
# => INFO -- request: GET http://httpbingo.org/?api_key=[REMOVED]
# => DEBUG -- request: User-Agent: "Faraday v1.0.0"
# => INFO -- response: Status 301
# => DEBUG -- response: date: "Sun, 19 May 2019 16:12:36 GMT"
```
### Change log level
By default, the `logger` middleware logs on the `info` log level. It is possible to configure
the severity by providing the `log_level` option:
```ruby
conn = Faraday.new(url: 'http://httpbingo.org') do |faraday|
faraday.response :logger, nil, { bodies: true, log_level: :debug }
end
```
### Customize the formatter
You can also provide a custom formatter to control how requests, responses and errors are logged.
Any custom formatter MUST implement the `request` and `response` method, with one argument which
will be passed being the Faraday environment.
Any custom formatter CAN implement the `exception` method,
with one argument which will be passed being the exception (StandardError).
If you make your formatter inheriting from `Faraday::Logging::Formatter`,
then the methods `debug`, `info`, `warn`, `error` and `fatal` are automatically delegated to the logger.
```ruby
class MyFormatter < Faraday::Logging::Formatter
def request(env)
# Build a custom message using `env`
info('Request') { 'Sending Request' }
end
def response(env)
# Build a custom message using `env`
info('Response') { 'Response Received' }
end
def exception(exc)
# Build a custom message using `exc`
info('Error') { 'Error Raised' }
end
end
conn = Faraday.new(url: 'http://httpbingo.org/api_key=s3cr3t') do |faraday|
faraday.response :logger, nil, formatter: MyFormatter
end
```

View File

@ -0,0 +1,90 @@
# Raising Errors
The `RaiseError` middleware raises a `Faraday::Error` exception if an HTTP
response returns with a 4xx or 5xx status code.
This greatly increases the ease of use of Faraday, as you don't have to check
the response status code manually.
These errors add to the list of default errors [raised by Faraday](getting-started/errors.md).
All exceptions are initialized with a hash containing the response `status`, `headers`, and `body`.
```ruby
conn = Faraday.new(url: 'http://httpbingo.org') do |faraday|
faraday.response :raise_error # raise Faraday::Error on status code 4xx or 5xx
end
begin
conn.get('/wrong-url') # => Assume this raises a 404 response
rescue Faraday::ResourceNotFound => e
e.response_status #=> 404
e.response_headers #=> { ... }
e.response_body #=> "..."
end
```
Specific exceptions are raised based on the HTTP Status code of the response.
## 4xx Errors
An HTTP status in the 400-499 range typically represents an error
by the client. They raise error classes inheriting from `Faraday::ClientError`.
| Status Code | Exception Class |
|---------------------------------------------------------------------|-------------------------------------|
| [400](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400) | `Faraday::BadRequestError` |
| [401](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401) | `Faraday::UnauthorizedError` |
| [403](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403) | `Faraday::ForbiddenError` |
| [404](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404) | `Faraday::ResourceNotFound` |
| [407](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/407) | `Faraday::ProxyAuthError` |
| [408](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/408) | `Faraday::RequestTimeoutError` |
| [409](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/409) | `Faraday::ConflictError` |
| [422](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/422) | `Faraday::UnprocessableEntityError` |
| [429](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429) | `Faraday::TooManyRequestsError` |
| 4xx (any other) | `Faraday::ClientError` |
## 5xx Errors
An HTTP status in the 500-599 range represents a server error, and raises a
`Faraday::ServerError` exception.
It's important to note that this exception is only returned if we receive a response and the
HTTP status in such response is in the 500-599 range.
Other kind of errors normally attributed to errors in the 5xx range (such as timeouts, failure to connect, etc...)
are raised as specific exceptions inheriting from `Faraday::Error`.
See [Faraday Errors](getting-started/errors.md) for more information on these.
### Missing HTTP status
The HTTP response status may be nil due to a malformed HTTP response from the
server, or a bug in the underlying HTTP library. This is considered a server error
and raised as `Faraday::NilStatusError`, which inherits from `Faraday::ServerError`.
## Middleware Options
The behavior of this middleware can be customized with the following options:
| Option | Default | Description |
|----------------------|---------|-------------|
| **include_request** | true | When true, exceptions are initialized with request information including `method`, `url`, `url_path`, `params`, `headers`, and `body`. |
| **allowed_statuses** | [] | An array of status codes that should not raise an error. |
### Example Usage
```ruby
conn = Faraday.new(url: 'http://httpbingo.org') do |faraday|
faraday.response :raise_error, include_request: true, allowed_statuses: [404]
end
begin
conn.get('/wrong-url') # => Assume this raises a 404 response
conn.get('/protected-url') # => Assume this raises a 401 response
rescue Faraday::UnauthorizedError => e
e.response[:status] # => 401
e.response[:headers] # => { ... }
e.response[:body] # => "..."
e.response[:request][:url_path] # => "/protected-url"
end
```
In this example, a `Faraday::UnauthorizedError` exception is raised for the `/protected-url` request, while the
`/wrong-url` request does not raise an error because the status code `404` is in the `allowed_statuses` array.

View File

@ -0,0 +1,31 @@
# URL Encoding
The `UrlEncoded` middleware converts a `Faraday::Request#body` hash of key/value pairs into a url-encoded request body.
The middleware also automatically sets the `Content-Type` header to `application/x-www-form-urlencoded`.
The way parameters are serialized can be customized in the [Request Options](customization/request-options.md).
### Example Usage
```ruby
conn = Faraday.new(...) do |f|
f.request :url_encoded
...
end
conn.post('/', { a: 1, b: 2 })
# POST with
# Content-Type: application/x-www-form-urlencoded
# Body: a=1&b=2
```
Complex structures can also be passed
```ruby
conn.post('/', { a: [1, 3], b: { c: 2, d: 4} })
# POST with
# Content-Type: application/x-www-form-urlencoded
# Body: a%5B%5D=1&a%5B%5D=3&b%5Bc%5D=2&b%5Bd%5D=4
```
[customize]: ../usage/customize#changing-how-parameters-are-serialized

200
docs/middleware/index.md Normal file
View File

@ -0,0 +1,200 @@
# Middleware
Under the hood, Faraday uses a Rack-inspired middleware stack for making
requests. Much of Faraday's power is unlocked with custom middleware. Some
middleware is included with Faraday, and others are in external gems.
Here are some of the features that middleware can provide:
- authentication
- caching responses on disk or in memory
- cookies
- following redirects
- JSON encoding/decoding
- logging
To use these great features, create a `Faraday::Connection` with `Faraday.new`
and add the correct middleware in a block. For example:
```ruby
require 'faraday'
conn = Faraday.new do |f|
f.request :json # encode req bodies as JSON
f.response :logger # logs request and responses
f.response :json # decode response bodies as JSON
f.adapter :net_http # Use the Net::HTTP adapter
end
response = conn.get("http://httpbingo.org/get")
```
### How it Works
A `Faraday::Connection` uses a `Faraday::RackBuilder` to assemble a
Rack-inspired middleware stack for making HTTP requests. Each middleware runs
and passes an Env object around to the next one. After the final middleware has
run, Faraday will return a `Faraday::Response` to the end user.
The order in which middleware is stacked is important. Like with Rack, the first
middleware on the list wraps all others, while the last middleware is the
innermost one. If you want to use a custom [adapter](adapters/index.md), it must
therefore be last.
![Middleware](../_media/middleware.png)
This is what makes things like the "retry middleware" possible.
It doesn't really matter if the middleware was registered as a request or a response one, the only thing that matter is how they're added to the stack.
Say you have the following:
```ruby
Faraday.new(...) do |conn|
conn.request :authorization
conn.response :json
conn.response :parse_dates
end
```
This will result into a middleware stack like this:
```ruby
authorization do
# authorization request hook
json do
# json request hook
parse_dates do
# parse_dates request hook
response = adapter.perform(request)
# parse_dates response hook
end
# json response hook
end
# authorization response hook
end
```
In this example, you can see that `parse_dates` is the LAST middleware processing the request, and the FIRST middleware processing the response.
This is why it's important for the adapter to always be at the end of the middleware list.
### Using Middleware
Calling `use` is the most basic way to add middleware to your stack, but most
middleware is conveniently registered in the `request`, `response` or `adapter`
namespaces. All four methods are equivalent apart from the namespacing.
For example, the `Faraday::Request::UrlEncoded` middleware registers itself in
`Faraday::Request` so it can be added with `request`. These two are equivalent:
```ruby
# add by symbol, lookup from Faraday::Request,
# Faraday::Response and Faraday::Adapter registries
conn = Faraday.new do |f|
f.request :url_encoded
f.response :logger
f.adapter :net_http
end
```
or:
```ruby
# identical, but add the class directly instead of using lookups
conn = Faraday.new do |f|
f.use Faraday::Request::UrlEncoded
f.use Faraday::Response::Logger
f.use Faraday::Adapter::NetHttp
end
```
This is also the place to pass options. For example:
```ruby
conn = Faraday.new do |f|
f.request :logger, bodies: true
end
```
### DEFAULT_OPTIONS
`DEFAULT_OPTIONS` improve the flexibility and customizability of new and existing middleware. Class-level `DEFAULT_OPTIONS` and the ability to set these defaults at the application level compliment existing functionality in which options can be passed into middleware on a per-instance basis.
#### Using DEFAULT_OPTIONS
Using `RaiseError` as an example, you can see that `DEFAULT_OPTIONS` have been defined at the top of the class:
```ruby
DEFAULT_OPTIONS = { include_request: true }.freeze
```
These options will be set at the class level upon instantiation and referenced as needed within the class. From our same example:
```ruby
def response_values(env)
...
return response unless options[:include_request]
...
```
If the default value provides the desired functionality, no further consideration is needed.
#### Setting Alternative Options per Application
In the case where it is desirable to change the default option for all instances within an application, it can be done by configuring the options in a `/config/initializers` file. For example:
```ruby
# config/initializers/faraday_config.rb
Faraday::Response::RaiseError.default_options = { include_request: false }
```
After app initialization, all instances of the middleware will have the newly configured option(s). They can still be overridden on a per-instance bases (if handled in the middleware), like this:
```ruby
Faraday.new do |f|
...
f.response :raise_error, include_request: true
...
end
```
### Available Middleware
The following pages provide detailed configuration for the middleware that ships with Faraday:
* [Authentication](middleware/included/authentication.md)
* [URL Encoding](middleware/included/url-encoding.md)
* [JSON Encoding/Decoding](middleware/included/json.md)
* [Instrumentation](middleware/included/instrumentation.md)
* [Logging](middleware/included/logging.md)
* [Raising Errors](middleware/included/raising-errors.md)
The [Awesome Faraday](https://github.com/lostisland/awesome-faraday/) project
has a complete list of useful, well-maintained Faraday middleware. Middleware is
often provided by external gems, like the
[faraday-retry](https://github.com/lostisland/faraday-retry) gem.
### Detailed Example
Here's a more realistic example:
```ruby
Faraday.new(...) do |conn|
# POST/PUT params encoder
conn.request :url_encoded
# Logging of requests/responses
conn.response :logger
# Last middleware must be the adapter
conn.adapter :net_http
end
```
This request middleware setup affects POST/PUT requests in the following way:
1. `Request::UrlEncoded` encodes as "application/x-www-form-urlencoded" if not
already encoded or of another type.
2. `Response::Logger` logs request and response headers, can be configured to log bodies as well.
Swapping middleware means giving the other priority. Specifying the
"Content-Type" for the request is explicitly stating which middleware should
process it.

119
examples/client_spec.rb Normal file
View File

@ -0,0 +1,119 @@
# frozen_string_literal: true
# Requires Ruby with rspec and faraday gems.
# rspec client_spec.rb
require 'faraday'
require 'json'
# Example API client
class Client
def initialize(conn)
@conn = conn
end
def httpbingo(jname, params: {})
res = @conn.get("/#{jname}", params)
data = JSON.parse(res.body)
data['origin']
end
def foo(params)
res = @conn.post('/foo', JSON.dump(params))
res.status
end
end
RSpec.describe Client do
let(:stubs) { Faraday::Adapter::Test::Stubs.new }
let(:conn) { Faraday.new { |b| b.adapter(:test, stubs) } }
let(:client) { Client.new(conn) }
it 'parses origin' do
stubs.get('/ip') do |env|
# optional: you can inspect the Faraday::Env
expect(env.url.path).to eq('/ip')
[
200,
{ 'Content-Type': 'application/javascript' },
'{"origin": "127.0.0.1"}'
]
end
# uncomment to trigger stubs.verify_stubbed_calls failure
# stubs.get('/unused') { [404, {}, ''] }
expect(client.httpbingo('ip')).to eq('127.0.0.1')
stubs.verify_stubbed_calls
end
it 'handles 404' do
stubs.get('/api') do
[
404,
{ 'Content-Type': 'application/javascript' },
'{}'
]
end
expect(client.httpbingo('api')).to be_nil
stubs.verify_stubbed_calls
end
it 'handles exception' do
stubs.get('/api') do
raise Faraday::ConnectionFailed
end
expect { client.httpbingo('api') }.to raise_error(Faraday::ConnectionFailed)
stubs.verify_stubbed_calls
end
context 'When the test stub is run in strict_mode' do
let(:stubs) { Faraday::Adapter::Test::Stubs.new(strict_mode: true) }
it 'verifies the all parameter values are identical' do
stubs.get('/api?abc=123') do
[
200,
{ 'Content-Type': 'application/javascript' },
'{"origin": "127.0.0.1"}'
]
end
# uncomment to raise Stubs::NotFound
# expect(client.httpbingo('api', params: { abc: 123, foo: 'Kappa' })).to eq('127.0.0.1')
expect(client.httpbingo('api', params: { abc: 123 })).to eq('127.0.0.1')
stubs.verify_stubbed_calls
end
end
context 'When the Faraday connection is configured with FlatParamsEncoder' do
let(:conn) { Faraday.new(request: { params_encoder: Faraday::FlatParamsEncoder }) { |b| b.adapter(:test, stubs) } }
it 'handles the same multiple URL parameters' do
stubs.get('/api?a=x&a=y&a=z') { [200, { 'Content-Type' => 'application/json' }, '{"origin": "127.0.0.1"}'] }
# uncomment to raise Stubs::NotFound
# expect(client.httpbingo('api', params: { a: %w[x y] })).to eq('127.0.0.1')
expect(client.httpbingo('api', params: { a: %w[x y z] })).to eq('127.0.0.1')
stubs.verify_stubbed_calls
end
end
context 'When you want to test the body, you can use a proc as well as string' do
it 'tests with a string' do
stubs.post('/foo', '{"name":"YK"}') { [200, {}, ''] }
expect(client.foo(name: 'YK')).to eq 200
stubs.verify_stubbed_calls
end
it 'tests with a proc' do
check = ->(request_body) { JSON.parse(request_body).slice('name') == { 'name' => 'YK' } }
stubs.post('/foo', check) { [200, {}, ''] }
expect(client.foo(name: 'YK', created_at: Time.now)).to eq 200
stubs.verify_stubbed_calls
end
end
end

144
examples/client_test.rb Normal file
View File

@ -0,0 +1,144 @@
# frozen_string_literal: true
# Requires Ruby with test-unit and faraday gems.
# ruby client_test.rb
require 'faraday'
require 'json'
require 'test/unit'
# Example API client
class Client
def initialize(conn)
@conn = conn
end
def httpbingo(jname, params: {})
res = @conn.get("/#{jname}", params)
data = JSON.parse(res.body)
data['origin']
end
def foo(params)
res = @conn.post('/foo', JSON.dump(params))
res.status
end
end
# Example API client test
class ClientTest < Test::Unit::TestCase
def test_httpbingo_name
stubs = Faraday::Adapter::Test::Stubs.new
stubs.get('/api') do |env|
# optional: you can inspect the Faraday::Env
assert_equal '/api', env.url.path
[
200,
{ 'Content-Type': 'application/javascript' },
'{"origin": "127.0.0.1"}'
]
end
# uncomment to trigger stubs.verify_stubbed_calls failure
# stubs.get('/unused') { [404, {}, ''] }
cli = client(stubs)
assert_equal '127.0.0.1', cli.httpbingo('api')
stubs.verify_stubbed_calls
end
def test_httpbingo_not_found
stubs = Faraday::Adapter::Test::Stubs.new
stubs.get('/api') do
[
404,
{ 'Content-Type': 'application/javascript' },
'{}'
]
end
cli = client(stubs)
assert_nil cli.httpbingo('api')
stubs.verify_stubbed_calls
end
def test_httpbingo_exception
stubs = Faraday::Adapter::Test::Stubs.new
stubs.get('/api') do
raise Faraday::ConnectionFailed
end
cli = client(stubs)
assert_raise Faraday::ConnectionFailed do
cli.httpbingo('api')
end
stubs.verify_stubbed_calls
end
def test_strict_mode
stubs = Faraday::Adapter::Test::Stubs.new(strict_mode: true)
stubs.get('/api?abc=123') do
[
200,
{ 'Content-Type': 'application/javascript' },
'{"origin": "127.0.0.1"}'
]
end
cli = client(stubs)
assert_equal '127.0.0.1', cli.httpbingo('api', params: { abc: 123 })
# uncomment to raise Stubs::NotFound
# assert_equal '127.0.0.1', cli.httpbingo('api', params: { abc: 123, foo: 'Kappa' })
stubs.verify_stubbed_calls
end
def test_non_default_params_encoder
stubs = Faraday::Adapter::Test::Stubs.new(strict_mode: true)
stubs.get('/api?a=x&a=y&a=z') do
[
200,
{ 'Content-Type': 'application/javascript' },
'{"origin": "127.0.0.1"}'
]
end
conn = Faraday.new(request: { params_encoder: Faraday::FlatParamsEncoder }) do |builder|
builder.adapter :test, stubs
end
cli = Client.new(conn)
assert_equal '127.0.0.1', cli.httpbingo('api', params: { a: %w[x y z] })
# uncomment to raise Stubs::NotFound
# assert_equal '127.0.0.1', cli.httpbingo('api', params: { a: %w[x y] })
stubs.verify_stubbed_calls
end
def test_with_string_body
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
stub.post('/foo', '{"name":"YK"}') { [200, {}, ''] }
end
cli = client(stubs)
assert_equal 200, cli.foo(name: 'YK')
stubs.verify_stubbed_calls
end
def test_with_proc_body
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
check = ->(request_body) { JSON.parse(request_body).slice('name') == { 'name' => 'YK' } }
stub.post('/foo', check) { [200, {}, ''] }
end
cli = client(stubs)
assert_equal 200, cli.foo(name: 'YK', created_at: Time.now)
stubs.verify_stubbed_calls
end
def client(stubs)
conn = Faraday.new do |builder|
builder.adapter :test, stubs
end
Client.new(conn)
end
end

View File

@ -1,22 +1,39 @@
lib = "faraday"
lib_file = File.expand_path("../lib/#{lib}.rb", __FILE__)
File.read(lib_file) =~ /\bVERSION\s*=\s*["'](.+?)["']/
version = $1
# frozen_string_literal: true
require_relative 'lib/faraday/version'
Gem::Specification.new do |spec|
spec.name = lib
spec.version = version
spec.name = 'faraday'
spec.version = Faraday::VERSION
spec.summary = "HTTP/REST API client library."
spec.summary = 'HTTP/REST API client library.'
spec.authors = ["Rick Olson"]
spec.authors = ['@technoweenie', '@iMacTia', '@olleolleolle']
spec.email = 'technoweenie@gmail.com'
spec.homepage = 'https://github.com/lostisland/faraday'
spec.homepage = 'https://lostisland.github.io/faraday'
spec.licenses = ['MIT']
spec.required_ruby_version = '>= 1.9'
spec.required_ruby_version = '>= 3.0'
spec.add_dependency 'multipart-post', '>= 1.2', '< 3'
# faraday-net_http is the "default adapter", but being a Faraday dependency it can't
# control which version of faraday it will be pulled from.
# To avoid releasing a major version every time there's a new Faraday API, we should
# always fix its required version to the next MINOR version.
# This way, we can release minor versions of the adapter with "breaking" changes for older versions of Faraday
# and then bump the version requirement on the next compatible version of faraday.
spec.add_dependency 'faraday-net_http', '>= 2.0', '< 3.5'
spec.add_dependency 'json'
spec.add_dependency 'logger'
spec.files = `git ls-files -z lib LICENSE.md README.md`.split("\0")
# Includes `examples` and `spec` to allow external adapter gems to run Faraday unit and integration tests
spec.files = Dir['CHANGELOG.md', '{examples,lib,spec}/**/*', 'LICENSE.md', 'Rakefile', 'README.md']
spec.require_paths = %w[lib spec/external_adapters]
spec.metadata = {
'homepage_uri' => 'https://lostisland.github.io/faraday',
'changelog_uri' =>
"https://github.com/lostisland/faraday/releases/tag/v#{spec.version}",
'source_code_uri' => 'https://github.com/lostisland/faraday',
'bug_tracker_uri' => 'https://github.com/lostisland/faraday/issues',
'rubygems_mfa_required' => 'true'
}
end

View File

@ -1,248 +1,158 @@
require 'thread'
require 'cgi'
# frozen_string_literal: true
require 'cgi/escape'
require 'cgi/util' if RUBY_VERSION < '3.5'
require 'date'
require 'set'
require 'forwardable'
# Public: This is the main namespace for Faraday. You can either use it to
# create Faraday::Connection objects, or access it directly.
require 'faraday/version'
require 'faraday/methods'
require 'faraday/error'
require 'faraday/middleware_registry'
require 'faraday/utils'
require 'faraday/options'
require 'faraday/connection'
require 'faraday/rack_builder'
require 'faraday/parameters'
require 'faraday/middleware'
require 'faraday/adapter'
require 'faraday/request'
require 'faraday/response'
require 'faraday/net_http'
# This is the main namespace for Faraday.
#
# Examples
# It provides methods to create {Connection} objects, and HTTP-related
# methods to use directly.
#
# @example Helpful class methods for easy usage
# Faraday.get "http://faraday.com"
#
# @example Helpful class method `.new` to create {Connection} objects.
# conn = Faraday.new "http://faraday.com"
# conn.get '/'
#
module Faraday
VERSION = "0.15.3"
CONTENT_TYPE = 'Content-Type'
class << self
# Public: Gets or sets the root path that Faraday is being loaded from.
# This is the root from where the libraries are auto-loaded from.
# The root path that Faraday is being loaded from.
#
# This is the root from where the libraries are auto-loaded.
#
# @return [String]
attr_accessor :root_path
# Public: Gets or sets the path that the Faraday libs are loaded from.
# Gets or sets the path that the Faraday libs are loaded from.
# @return [String]
attr_accessor :lib_path
# Public: Gets or sets the Symbol key identifying a default Adapter to use
# for the default Faraday::Connection.
# @overload default_adapter
# Gets the Symbol key identifying a default Adapter to use
# for the default {Faraday::Connection}. Defaults to `:net_http`.
# @return [Symbol] the default adapter
# @overload default_adapter=(adapter)
# Updates default adapter while resetting {.default_connection}.
# @return [Symbol] the new default_adapter.
attr_reader :default_adapter
# Public: Sets the default Faraday::Connection for simple scripts that
# access the Faraday constant directly.
#
# Faraday.get "https://faraday.com"
# Option for the default_adapter
# @return [Hash] default_adapter options
attr_accessor :default_adapter_options
# Documented below, see default_connection
attr_writer :default_connection
# Public: Tells faraday to ignore the environment proxy (http_proxy).
# Tells Faraday to ignore the environment proxy (http_proxy).
# Defaults to `false`.
# @return [Boolean]
attr_accessor :ignore_env_proxy
# Public: Initializes a new Faraday::Connection.
# Initializes a new {Connection}.
#
# url - The optional String base URL to use as a prefix for all
# requests. Can also be the options Hash.
# options - The optional Hash used to configure this Faraday::Connection.
# Any of these values will be set on every request made, unless
# overridden for a specific request.
# :url - String base URL.
# :params - Hash of URI query unencoded key/value pairs.
# :headers - Hash of unencoded HTTP header key/value pairs.
# :request - Hash of request options.
# :ssl - Hash of SSL options.
# :proxy - Hash of Proxy options.
#
# Examples
# @param url [String,Hash] The optional String base URL to use as a prefix
# for all requests. Can also be the options Hash. Any of these
# values will be set on every request made, unless overridden
# for a specific request.
# @param options [Hash]
# @option options [String] :url Base URL
# @option options [Hash] :params Hash of unencoded URI query params.
# @option options [Hash] :headers Hash of unencoded HTTP headers.
# @option options [Hash] :request Hash of request options.
# @option options [Hash] :ssl Hash of SSL options.
# @option options [Hash] :proxy Hash of Proxy options.
# @return [Faraday::Connection]
#
# @example With an URL argument
# Faraday.new 'http://faraday.com'
# # => Faraday::Connection to http://faraday.com
#
# # http://faraday.com?page=1
# Faraday.new 'http://faraday.com', :params => {:page => 1}
# @example With an URL argument and an options hash
# Faraday.new 'http://faraday.com', params: { page: 1 }
# # => Faraday::Connection to http://faraday.com?page=1
#
# # same
#
# Faraday.new :url => 'http://faraday.com',
# :params => {:page => 1}
#
# Returns a Faraday::Connection.
def new(url = nil, options = nil)
block = block_given? ? Proc.new : nil
options = options ? default_connection_options.merge(options) : default_connection_options
# @example With everything in an options hash
# Faraday.new url: 'http://faraday.com',
# params: { page: 1 }
# # => Faraday::Connection to http://faraday.com?page=1
def new(url = nil, options = {}, &block)
options = Utils.deep_merge(default_connection_options, options)
Faraday::Connection.new(url, options, &block)
end
# Internal: Requires internal Faraday libraries.
#
# *libs - One or more relative String names to Faraday classes.
#
# Returns nothing.
def require_libs(*libs)
libs.each do |lib|
require "#{lib_path}/#{lib}"
end
end
# Public: Updates default adapter while resetting
# #default_connection.
#
# Returns the new default_adapter.
# Documented elsewhere, see default_adapter reader
def default_adapter=(adapter)
@default_connection = nil
@default_adapter = adapter
end
alias require_lib require_libs
def respond_to?(symbol, include_private = false)
def respond_to_missing?(symbol, include_private = false)
default_connection.respond_to?(symbol, include_private) || super
end
private
# @overload default_connection
# Gets the default connection used for simple scripts.
# @return [Faraday::Connection] a connection configured with
# the default_adapter.
# @overload default_connection=(connection)
# @param connection [Faraday::Connection]
# Sets the default {Faraday::Connection} for simple scripts that
# access the Faraday constant directly, such as
# <code>Faraday.get "https://faraday.com"</code>.
def default_connection
@default_connection ||= Connection.new(default_connection_options)
end
# Gets the default connection options used when calling {Faraday#new}.
#
# @return [Faraday::ConnectionOptions]
def default_connection_options
@default_connection_options ||= ConnectionOptions.new
end
# Sets the default options used when calling {Faraday#new}.
#
# @param options [Hash, Faraday::ConnectionOptions]
def default_connection_options=(options)
@default_connection = nil
@default_connection_options = ConnectionOptions.from(options)
end
private
# Internal: Proxies method calls on the Faraday constant to
# #default_connection.
# .default_connection.
def method_missing(name, *args, &block)
default_connection.send(name, *args, &block)
if default_connection.respond_to?(name)
default_connection.send(name, *args, &block)
else
super
end
end
end
self.ignore_env_proxy = false
self.root_path = File.expand_path "..", __FILE__
self.lib_path = File.expand_path "../faraday", __FILE__
self.root_path = File.expand_path __dir__
self.lib_path = File.expand_path 'faraday', __dir__
self.default_adapter = :net_http
# Gets the default connection used for simple scripts.
#
# Returns a Faraday::Connection, configured with the #default_adapter.
def self.default_connection
@default_connection ||= Connection.new(default_connection_options)
end
# Gets the default connection options used when calling Faraday#new.
#
# Returns a Faraday::ConnectionOptions.
def self.default_connection_options
@default_connection_options ||= ConnectionOptions.new
end
# Public: Sets the default options used when calling Faraday#new.
def self.default_connection_options=(options)
@default_connection = nil
@default_connection_options = ConnectionOptions.from(options)
end
unless const_defined? :Timer
require 'timeout'
Timer = Timeout
end
# Public: Adds the ability for other modules to register and lookup
# middleware classes.
module MiddlewareRegistry
# Public: Register middleware class(es) on the current module.
#
# mapping - A Hash mapping Symbol keys to classes. Classes can be expressed
# as fully qualified constant, or a Proc that will be lazily
# called to return the former.
#
# Examples
#
# module Faraday
# class Whatever
# # Middleware looked up by :foo returns Faraday::Whatever::Foo.
# register_middleware :foo => Foo
#
# # Middleware looked up by :bar returns Faraday::Whatever.const_get(:Bar)
# register_middleware :bar => :Bar
#
# # Middleware looked up by :baz requires 'baz' and returns Faraday::Whatever.const_get(:Baz)
# register_middleware :baz => [:Baz, 'baz']
# end
# end
#
# Returns nothing.
def register_middleware(autoload_path = nil, mapping = nil)
if mapping.nil?
mapping = autoload_path
autoload_path = nil
end
middleware_mutex do
@middleware_autoload_path = autoload_path if autoload_path
(@registered_middleware ||= {}).update(mapping)
end
end
# Public: Lookup middleware class with a registered Symbol shortcut.
#
# key - The Symbol key for the registered middleware.
#
# Examples
#
# module Faraday
# class Whatever
# register_middleware :foo => Foo
# end
# end
#
# Faraday::Whatever.lookup_middleware(:foo)
# # => Faraday::Whatever::Foo
#
# Returns a middleware Class.
def lookup_middleware(key)
load_middleware(key) ||
raise(Faraday::Error.new("#{key.inspect} is not registered on #{self}"))
end
def middleware_mutex(&block)
@middleware_mutex ||= begin
require 'monitor'
Monitor.new
end
@middleware_mutex.synchronize(&block)
end
def fetch_middleware(key)
defined?(@registered_middleware) && @registered_middleware[key]
end
def load_middleware(key)
value = fetch_middleware(key)
case value
when Module
value
when Symbol, String
middleware_mutex do
@registered_middleware[key] = const_get(value)
end
when Proc
middleware_mutex do
@registered_middleware[key] = value.call
end
when Array
middleware_mutex do
const, path = value
if root = @middleware_autoload_path
path = "#{root}/#{path}"
end
require(path)
@registered_middleware[key] = const
end
load_middleware(key)
end
end
end
def self.const_missing(name)
if name.to_sym == :Builder
warn "Faraday::Builder is now Faraday::RackBuilder."
const_set name, RackBuilder
else
super
end
end
require_libs "utils", "options", "connection", "rack_builder", "parameters",
"middleware", "adapter", "request", "response", "upload_io", "error"
if !ENV["FARADAY_NO_AUTOLOAD"]
require_lib 'autoload'
end
self.default_adapter_options = {}
end

View File

@ -1,55 +1,101 @@
# frozen_string_literal: true
module Faraday
# Public: This is a base class for all Faraday adapters. Adapters are
# Base class for all Faraday adapters. Adapters are
# responsible for fulfilling a Faraday request.
class Adapter < Middleware
CONTENT_LENGTH = 'Content-Length'.freeze
class Adapter
extend MiddlewareRegistry
register_middleware File.expand_path('../adapter', __FILE__),
:test => [:Test, 'test'],
:net_http => [:NetHttp, 'net_http'],
:net_http_persistent => [:NetHttpPersistent, 'net_http_persistent'],
:typhoeus => [:Typhoeus, 'typhoeus'],
:patron => [:Patron, 'patron'],
:em_synchrony => [:EMSynchrony, 'em_synchrony'],
:em_http => [:EMHttp, 'em_http'],
:excon => [:Excon, 'excon'],
:rack => [:Rack, 'rack'],
:httpclient => [:HTTPClient, 'httpclient']
CONTENT_LENGTH = 'Content-Length'
# Public: This module marks an Adapter as supporting parallel requests.
# This module marks an Adapter as supporting parallel requests.
module Parallelism
attr_writer :supports_parallel
def supports_parallel?() @supports_parallel end
def supports_parallel?
@supports_parallel
end
def inherited(subclass)
super
subclass.supports_parallel = self.supports_parallel?
subclass.supports_parallel = supports_parallel?
end
end
extend Parallelism
self.supports_parallel = false
def initialize(app = nil, opts = {}, &block)
super(app)
def initialize(_app = nil, opts = {}, &block)
@app = lambda(&:response)
@connection_options = opts
@config_block = block
end
# Yields or returns an adapter's configured connection. Depends on
# #build_connection being defined on this adapter.
#
# @param env [Faraday::Env, Hash] The env object for a faraday request.
#
# @return The return value of the given block, or the HTTP connection object
# if no block is given.
def connection(env)
conn = build_connection(env)
return conn unless block_given?
yield conn
end
# Close any persistent connections. The adapter should still be usable
# after calling close.
def close
# Possible implementation:
# @app.close if @app.respond_to?(:close)
end
def call(env)
env.clear_body if env.needs_body?
env.response = Response.new
end
private
def save_response(env, status, body, headers = nil, reason_phrase = nil)
def save_response(env, status, body, headers = nil, reason_phrase = nil, finished: true)
env.status = status
env.body = body
env.reason_phrase = reason_phrase && reason_phrase.to_s.strip
env.reason_phrase = reason_phrase&.to_s&.strip
env.response_headers = Utils::Headers.new.tap do |response_headers|
response_headers.update headers unless headers.nil?
yield(response_headers) if block_given?
end
env.response.finish(env) unless env.parallel? || !finished
env.response
end
# Fetches either a read, write, or open timeout setting. Defaults to the
# :timeout value if a more specific one is not given.
#
# @param type [Symbol] Describes which timeout setting to get: :read,
# :write, or :open.
# @param options [Hash] Hash containing Symbol keys like :timeout,
# :read_timeout, :write_timeout, or :open_timeout
#
# @return [Integer, nil] Timeout duration in seconds, or nil if no timeout
# has been set.
def request_timeout(type, options)
key = TIMEOUT_KEYS.fetch(type) do
msg = "Expected :read, :write, :open. Got #{type.inspect} :("
raise ArgumentError, msg
end
options[key] || options[:timeout]
end
TIMEOUT_KEYS = {
read: :read_timeout,
open: :open_timeout,
write: :write_timeout
}.freeze
end
end
require 'faraday/adapter/test'

View File

@ -1,243 +0,0 @@
module Faraday
class Adapter
# EventMachine adapter is useful for either asynchronous requests
# when in EM reactor loop or for making parallel requests in
# synchronous code.
class EMHttp < Faraday::Adapter
module Options
def connection_config(env)
options = {}
configure_proxy(options, env)
configure_timeout(options, env)
configure_socket(options, env)
configure_ssl(options, env)
options
end
def request_config(env)
options = {
:body => read_body(env),
:head => env[:request_headers],
# :keepalive => true,
# :file => 'path/to/file', # stream data off disk
}
configure_compression(options, env)
options
end
def read_body(env)
body = env[:body]
body.respond_to?(:read) ? body.read : body
end
def configure_proxy(options, env)
if proxy = request_options(env)[:proxy]
options[:proxy] = {
:host => proxy[:uri].host,
:port => proxy[:uri].port,
:authorization => [proxy[:user], proxy[:password]]
}
end
end
def configure_socket(options, env)
if bind = request_options(env)[:bind]
options[:bind] = {
:host => bind[:host],
:port => bind[:port]
}
end
end
def configure_ssl(options, env)
if env[:url].scheme == 'https' && env[:ssl]
options[:ssl] = {
:cert_chain_file => env[:ssl][:ca_file],
:verify_peer => env[:ssl].fetch(:verify, true)
}
end
end
def configure_timeout(options, env)
timeout, open_timeout = request_options(env).values_at(:timeout, :open_timeout)
options[:connect_timeout] = options[:inactivity_timeout] = timeout
options[:connect_timeout] = open_timeout if open_timeout
end
def configure_compression(options, env)
if env[:method] == :get and not options[:head].key? 'accept-encoding'
options[:head]['accept-encoding'] = 'gzip, compressed'
end
end
def request_options(env)
env[:request]
end
end
include Options
dependency 'em-http'
self.supports_parallel = true
def self.setup_parallel_manager(options = nil)
Manager.new
end
def call(env)
super
perform_request env
@app.call env
end
def perform_request(env)
if parallel?(env)
manager = env[:parallel_manager]
manager.add {
perform_single_request(env).
callback { env[:response].finish(env) }
}
else
unless EventMachine.reactor_running?
error = nil
# start EM, block until request is completed
EventMachine.run do
perform_single_request(env).
callback { EventMachine.stop }.
errback { |client|
error = error_message(client)
EventMachine.stop
}
end
raise_error(error) if error
else
# EM is running: instruct upstream that this is an async request
env[:parallel_manager] = true
perform_single_request(env).
callback { env[:response].finish(env) }.
errback {
# TODO: no way to communicate the error in async mode
raise NotImplementedError
}
end
end
rescue EventMachine::Connectify::CONNECTError => err
if err.message.include?("Proxy Authentication Required")
raise Error::ConnectionFailed, %{407 "Proxy Authentication Required "}
else
raise Error::ConnectionFailed, err
end
rescue => err
if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err
raise Faraday::SSLError, err
else
raise
end
end
# TODO: reuse the connection to support pipelining
def perform_single_request(env)
req = create_request(env)
req.setup_request(env[:method], request_config(env)).callback { |client|
status = client.response_header.status
reason = client.response_header.http_reason
save_response(env, status, client.response, nil, reason) do |resp_headers|
client.response_header.each do |name, value|
resp_headers[name.to_sym] = value
end
end
}
end
def create_request(env)
EventMachine::HttpRequest.new(env[:url], connection_config(env).merge(@connection_options))
end
def error_message(client)
client.error or "request failed"
end
def raise_error(msg)
errklass = Faraday::Error::ClientError
if msg == Errno::ETIMEDOUT
errklass = Faraday::Error::TimeoutError
msg = "request timed out"
elsif msg == Errno::ECONNREFUSED
errklass = Faraday::Error::ConnectionFailed
msg = "connection refused"
elsif msg == "connection closed by server"
errklass = Faraday::Error::ConnectionFailed
end
raise errklass, msg
end
def parallel?(env)
!!env[:parallel_manager]
end
# The parallel manager is designed to start an EventMachine loop
# and block until all registered requests have been completed.
class Manager
def initialize
reset
end
def reset
@registered_procs = []
@num_registered = 0
@num_succeeded = 0
@errors = []
@running = false
end
def running?() @running end
def add
if running?
perform_request { yield }
else
@registered_procs << Proc.new
end
@num_registered += 1
end
def run
if @num_registered > 0
@running = true
EventMachine.run do
@registered_procs.each do |proc|
perform_request(&proc)
end
end
if @errors.size > 0
raise Faraday::Error::ClientError, @errors.first || "connection failed"
end
end
ensure
reset
end
def perform_request
client = yield
client.callback { @num_succeeded += 1; check_finished }
client.errback { @errors << client.error; check_finished }
end
def check_finished
if @num_succeeded + @errors.size == @num_registered
EventMachine.stop
end
end
end
end
end
end
begin
require 'openssl'
rescue LoadError
warn "Warning: no such file to load -- openssl. Make sure it is installed if you want HTTPS support"
else
require 'faraday/adapter/em_http_ssl_patch'
end if Faraday::Adapter::EMHttp.loaded?

View File

@ -1,56 +0,0 @@
require 'openssl'
require 'em-http'
module EmHttpSslPatch
def ssl_verify_peer(cert_string)
cert = nil
begin
cert = OpenSSL::X509::Certificate.new(cert_string)
rescue OpenSSL::X509::CertificateError
return false
end
@last_seen_cert = cert
if certificate_store.verify(@last_seen_cert)
begin
certificate_store.add_cert(@last_seen_cert)
rescue OpenSSL::X509::StoreError => e
raise e unless e.message == 'cert already in hash table'
end
true
else
raise OpenSSL::SSL::SSLError.new(%(unable to verify the server certificate for "#{host}"))
end
end
def ssl_handshake_completed
return true unless verify_peer?
unless OpenSSL::SSL.verify_certificate_identity(@last_seen_cert, host)
raise OpenSSL::SSL::SSLError.new(%(host "#{host}" does not match the server certificate))
else
true
end
end
def verify_peer?
parent.connopts.tls[:verify_peer]
end
def host
parent.uri.host
end
def certificate_store
@certificate_store ||= begin
store = OpenSSL::X509::Store.new
store.set_default_paths
ca_file = parent.connopts.tls[:cert_chain_file]
store.add_file(ca_file) if ca_file
store
end
end
end
EventMachine::HttpStubConnection.send(:include, EmHttpSslPatch)

View File

@ -1,106 +0,0 @@
require 'uri'
module Faraday
class Adapter
class EMSynchrony < Faraday::Adapter
include EMHttp::Options
dependency do
require 'em-synchrony/em-http'
require 'em-synchrony/em-multi'
require 'fiber'
end
self.supports_parallel = true
def self.setup_parallel_manager(options = {})
ParallelManager.new
end
def call(env)
super
request = create_request(env)
http_method = env[:method].to_s.downcase.to_sym
# Queue requests for parallel execution.
if env[:parallel_manager]
env[:parallel_manager].add(request, http_method, request_config(env)) do |resp|
save_response(env, resp.response_header.status, resp.response) do |resp_headers|
resp.response_header.each do |name, value|
resp_headers[name.to_sym] = value
end
end
# Finalize the response object with values from `env`.
env[:response].finish(env)
end
# Execute single request.
else
client = nil
block = lambda { request.send(http_method, request_config(env)) }
if !EM.reactor_running?
EM.run do
Fiber.new {
client = block.call
EM.stop
}.resume
end
else
client = block.call
end
raise client.error if client.error
status = client.response_header.status
reason = client.response_header.http_reason
save_response(env, status, client.response, nil, reason) do |resp_headers|
client.response_header.each do |name, value|
resp_headers[name.to_sym] = value
end
end
end
@app.call env
rescue Errno::ECONNREFUSED
raise Error::ConnectionFailed, $!
rescue EventMachine::Connectify::CONNECTError => err
if err.message.include?("Proxy Authentication Required")
raise Error::ConnectionFailed, %{407 "Proxy Authentication Required "}
else
raise Error::ConnectionFailed, err
end
rescue Errno::ETIMEDOUT => err
raise Error::TimeoutError, err
rescue RuntimeError => err
if err.message == "connection closed by server"
raise Error::ConnectionFailed, err
else
raise
end
rescue => err
if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err
raise Faraday::SSLError, err
else
raise
end
end
def create_request(env)
EventMachine::HttpRequest.new(Utils::URI(env[:url].to_s), connection_config(env).merge(@connection_options))
end
end
end
end
require 'faraday/adapter/em_synchrony/parallel_manager'
begin
require 'openssl'
rescue LoadError
warn "Warning: no such file to load -- openssl. Make sure it is installed if you want HTTPS support"
else
require 'faraday/adapter/em_http_ssl_patch'
end if Faraday::Adapter::EMSynchrony.loaded?

View File

@ -1,66 +0,0 @@
module Faraday
class Adapter
class EMSynchrony < Faraday::Adapter
class ParallelManager
# Add requests to queue. The `request` argument should be a
# `EM::HttpRequest` object.
def add(request, method, *args, &block)
queue << {
:request => request,
:method => method,
:args => args,
:block => block
}
end
# Run all requests on queue with `EM::Synchrony::Multi`, wrapping
# it in a reactor and fiber if needed.
def run
result = nil
if !EM.reactor_running?
EM.run {
Fiber.new do
result = perform
EM.stop
end.resume
}
else
result = perform
end
result
end
private
# The request queue.
def queue
@queue ||= []
end
# Main `EM::Synchrony::Multi` performer.
def perform
multi = ::EM::Synchrony::Multi.new
queue.each do |item|
method = "a#{item[:method]}".to_sym
req = item[:request].send(method, *item[:args])
req.callback(&item[:block])
req_name = "req_#{multi.requests.size}".to_sym
multi.add(req_name, req)
end
# Clear the queue, so parallel manager objects can be reused.
@queue = []
# Block fiber until all requests have returned.
multi.perform
end
end # ParallelManager
end # EMSynchrony
end # Adapter
end # Faraday

View File

@ -1,82 +0,0 @@
module Faraday
class Adapter
class Excon < Faraday::Adapter
dependency 'excon'
def call(env)
super
opts = {}
if env[:url].scheme == 'https' && ssl = env[:ssl]
opts[:ssl_verify_peer] = !!ssl.fetch(:verify, true)
opts[:ssl_ca_path] = ssl[:ca_path] if ssl[:ca_path]
opts[:ssl_ca_file] = ssl[:ca_file] if ssl[:ca_file]
opts[:client_cert] = ssl[:client_cert] if ssl[:client_cert]
opts[:client_key] = ssl[:client_key] if ssl[:client_key]
opts[:certificate] = ssl[:certificate] if ssl[:certificate]
opts[:private_key] = ssl[:private_key] if ssl[:private_key]
opts[:ssl_version] = ssl[:version] if ssl[:version]
opts[:ssl_min_version] = ssl[:min_version] if ssl[:min_version]
opts[:ssl_max_version] = ssl[:max_version] if ssl[:max_version]
# https://github.com/geemus/excon/issues/106
# https://github.com/jruby/jruby-ossl/issues/19
opts[:nonblock] = false
end
if ( req = env[:request] )
if req[:timeout]
opts[:read_timeout] = req[:timeout]
opts[:connect_timeout] = req[:timeout]
opts[:write_timeout] = req[:timeout]
end
if req[:open_timeout]
opts[:connect_timeout] = req[:open_timeout]
end
if req[:proxy]
opts[:proxy] = {
:host => req[:proxy][:uri].host,
:hostname => req[:proxy][:uri].hostname,
:port => req[:proxy][:uri].port,
:scheme => req[:proxy][:uri].scheme,
:user => req[:proxy][:user],
:password => req[:proxy][:password]
}
end
end
conn = create_connection(env, opts)
resp = conn.request \
:method => env[:method].to_s.upcase,
:headers => env[:request_headers],
:body => read_body(env)
save_response(env, resp.status.to_i, resp.body, resp.headers, resp.reason_phrase)
@app.call env
rescue ::Excon::Errors::SocketError => err
if err.message =~ /\btimeout\b/
raise Error::TimeoutError, err
elsif err.message =~ /\bcertificate\b/
raise Faraday::SSLError, err
else
raise Error::ConnectionFailed, err
end
rescue ::Excon::Errors::Timeout => err
raise Error::TimeoutError, err
end
def create_connection(env, opts)
::Excon.new(env[:url].to_s, opts.merge(@connection_options))
end
# TODO: support streaming requests
def read_body(env)
env[:body].respond_to?(:read) ? env[:body].read : env[:body]
end
end
end
end

View File

@ -1,128 +0,0 @@
module Faraday
class Adapter
class HTTPClient < Faraday::Adapter
dependency 'httpclient'
def client
@client ||= ::HTTPClient.new
end
def call(env)
super
# enable compression
client.transparent_gzip_decompression = true
if req = env[:request]
if proxy = req[:proxy]
configure_proxy proxy
end
if bind = req[:bind]
configure_socket bind
end
configure_timeouts req
end
if env[:url].scheme == 'https' && ssl = env[:ssl]
configure_ssl ssl
end
configure_client
# TODO Don't stream yet.
# https://github.com/nahi/httpclient/pull/90
env[:body] = env[:body].read if env[:body].respond_to? :read
resp = client.request env[:method], env[:url],
:body => env[:body],
:header => env[:request_headers]
save_response env, resp.status, resp.body, resp.headers, resp.reason
@app.call env
rescue ::HTTPClient::TimeoutError, Errno::ETIMEDOUT
raise Faraday::Error::TimeoutError, $!
rescue ::HTTPClient::BadResponseError => err
if err.message.include?('status 407')
raise Faraday::Error::ConnectionFailed, %{407 "Proxy Authentication Required "}
else
raise Faraday::Error::ClientError, $!
end
rescue Errno::ECONNREFUSED, IOError, SocketError
raise Faraday::Error::ConnectionFailed, $!
rescue => err
if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err
raise Faraday::SSLError, err
else
raise
end
end
def configure_socket(bind)
client.socket_local.host = bind[:host]
client.socket_local.port = bind[:port]
end
def configure_proxy(proxy)
client.proxy = proxy[:uri]
if proxy[:user] && proxy[:password]
client.set_proxy_auth proxy[:user], proxy[:password]
end
end
def configure_ssl(ssl)
ssl_config = client.ssl_config
ssl_config.verify_mode = ssl_verify_mode(ssl)
ssl_config.cert_store = ssl_cert_store(ssl)
ssl_config.add_trust_ca ssl[:ca_file] if ssl[:ca_file]
ssl_config.add_trust_ca ssl[:ca_path] if ssl[:ca_path]
ssl_config.client_cert = ssl[:client_cert] if ssl[:client_cert]
ssl_config.client_key = ssl[:client_key] if ssl[:client_key]
ssl_config.verify_depth = ssl[:verify_depth] if ssl[:verify_depth]
end
def configure_timeouts(req)
if req[:timeout]
client.connect_timeout = req[:timeout]
client.receive_timeout = req[:timeout]
client.send_timeout = req[:timeout]
end
if req[:open_timeout]
client.connect_timeout = req[:open_timeout]
client.send_timeout = req[:open_timeout]
end
end
def configure_client
@config_block.call(client) if @config_block
end
def ssl_cert_store(ssl)
return ssl[:cert_store] if ssl[:cert_store]
# Memoize the cert store so that the same one is passed to
# HTTPClient each time, to avoid resyncing SSL sesions when
# it's changed
@cert_store ||= begin
# Use the default cert store by default, i.e. system ca certs
cert_store = OpenSSL::X509::Store.new
cert_store.set_default_paths
cert_store
end
end
def ssl_verify_mode(ssl)
ssl[:verify_mode] || begin
if ssl.fetch(:verify, true)
OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
else
OpenSSL::SSL::VERIFY_NONE
end
end
end
end
end
end

View File

@ -1,152 +0,0 @@
begin
require 'net/https'
rescue LoadError
warn "Warning: no such file to load -- net/https. Make sure openssl is installed if you want ssl support"
require 'net/http'
end
require 'zlib'
module Faraday
class Adapter
class NetHttp < Faraday::Adapter
NET_HTTP_EXCEPTIONS = [
IOError,
Errno::ECONNABORTED,
Errno::ECONNREFUSED,
Errno::ECONNRESET,
Errno::EHOSTUNREACH,
Errno::EINVAL,
Errno::ENETUNREACH,
Errno::EPIPE,
Net::HTTPBadResponse,
Net::HTTPHeaderSyntaxError,
Net::ProtocolError,
SocketError,
Zlib::GzipFile::Error,
]
NET_HTTP_EXCEPTIONS << OpenSSL::SSL::SSLError if defined?(OpenSSL)
NET_HTTP_EXCEPTIONS << Net::OpenTimeout if defined?(Net::OpenTimeout)
def initialize(app = nil, opts = {}, &block)
@cert_store = nil
super(app, opts, &block)
end
def call(env)
super
with_net_http_connection(env) do |http|
configure_ssl(http, env[:ssl]) if env[:url].scheme == 'https' and env[:ssl]
configure_request(http, env[:request])
begin
http_response = perform_request(http, env)
rescue *NET_HTTP_EXCEPTIONS => err
if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err
raise Faraday::SSLError, err
else
raise Error::ConnectionFailed, err
end
end
save_response(env, http_response.code.to_i, http_response.body || '', nil, http_response.message) do |response_headers|
http_response.each_header do |key, value|
response_headers[key] = value
end
end
end
@app.call env
rescue Timeout::Error, Errno::ETIMEDOUT => err
raise Faraday::Error::TimeoutError, err
end
private
def create_request(env)
request = Net::HTTPGenericRequest.new \
env[:method].to_s.upcase, # request method
!!env[:body], # is there request body
:head != env[:method], # is there response body
env[:url].request_uri, # request uri path
env[:request_headers] # request headers
if env[:body].respond_to?(:read)
request.body_stream = env[:body]
else
request.body = env[:body]
end
request
end
def perform_request(http, env)
if :get == env[:method] and !env[:body]
# prefer `get` to `request` because the former handles gzip (ruby 1.9)
http.get env[:url].request_uri, env[:request_headers]
else
http.request create_request(env)
end
end
def with_net_http_connection(env)
yield net_http_connection(env)
end
def net_http_connection(env)
if proxy = env[:request][:proxy]
Net::HTTP::Proxy(proxy[:uri].hostname, proxy[:uri].port, proxy[:user], proxy[:password])
else
Net::HTTP
end.new(env[:url].hostname, env[:url].port || (env[:url].scheme == 'https' ? 443 : 80))
end
def configure_ssl(http, ssl)
http.use_ssl = true
http.verify_mode = ssl_verify_mode(ssl)
http.cert_store = ssl_cert_store(ssl)
http.cert = ssl[:client_cert] if ssl[:client_cert]
http.key = ssl[:client_key] if ssl[:client_key]
http.ca_file = ssl[:ca_file] if ssl[:ca_file]
http.ca_path = ssl[:ca_path] if ssl[:ca_path]
http.verify_depth = ssl[:verify_depth] if ssl[:verify_depth]
http.ssl_version = ssl[:version] if ssl[:version]
http.min_version = ssl[:min_version] if ssl[:min_version]
http.max_version = ssl[:max_version] if ssl[:max_version]
end
def configure_request(http, req)
if req[:timeout]
http.read_timeout = req[:timeout]
http.open_timeout = req[:timeout]
http.write_timeout = req[:timeout] if http.respond_to?(:write_timeout=)
end
http.open_timeout = req[:open_timeout] if req[:open_timeout]
http.write_timeout = req[:write_timeout] if req[:write_timeout] && http.respond_to?(:write_timeout=)
# Only set if Net::Http supports it, since Ruby 2.5.
http.max_retries = 0 if http.respond_to?(:max_retries=)
@config_block.call(http) if @config_block
end
def ssl_cert_store(ssl)
return ssl[:cert_store] if ssl[:cert_store]
return @cert_store if @cert_store
# Use the default cert store by default, i.e. system ca certs
@cert_store = OpenSSL::X509::Store.new
@cert_store.set_default_paths
@cert_store
end
def ssl_verify_mode(ssl)
ssl[:verify_mode] || begin
if ssl.fetch(:verify, true)
OpenSSL::SSL::VERIFY_PEER
else
OpenSSL::SSL::VERIFY_NONE
end
end
end
end
end
end

View File

@ -1,68 +0,0 @@
module Faraday
class Adapter
class NetHttpPersistent < NetHttp
dependency 'net/http/persistent'
private
def net_http_connection(env)
@cached_connection ||=
if Net::HTTP::Persistent.instance_method(:initialize).parameters.first == [:key, :name]
options = {name: 'Faraday'}
options[:pool_size] = @connection_options[:pool_size] if @connection_options.key?(:pool_size)
Net::HTTP::Persistent.new(options)
else
Net::HTTP::Persistent.new('Faraday')
end
proxy_uri = proxy_uri(env)
@cached_connection.proxy = proxy_uri if @cached_connection.proxy_uri != proxy_uri
@cached_connection
end
def proxy_uri(env)
proxy_uri = nil
if (proxy = env[:request][:proxy])
proxy_uri = ::URI::HTTP === proxy[:uri] ? proxy[:uri].dup : ::URI.parse(proxy[:uri].to_s)
proxy_uri.user = proxy_uri.password = nil
# awful patch for net-http-persistent 2.8 not unescaping user/password
(class << proxy_uri; self; end).class_eval do
define_method(:user) { proxy[:user] }
define_method(:password) { proxy[:password] }
end if proxy[:user]
end
proxy_uri
end
def perform_request(http, env)
http.request env[:url], create_request(env)
rescue Errno::ETIMEDOUT => error
raise Faraday::Error::TimeoutError, error
rescue Net::HTTP::Persistent::Error => error
if error.message.include? 'Timeout'
raise Faraday::Error::TimeoutError, error
elsif error.message.include? 'connection refused'
raise Faraday::Error::ConnectionFailed, error
else
raise
end
end
def configure_ssl(http, ssl)
http_set(http, :verify_mode, ssl_verify_mode(ssl))
http_set(http, :cert_store, ssl_cert_store(ssl))
http_set(http, :certificate, ssl[:client_cert]) if ssl[:client_cert]
http_set(http, :private_key, ssl[:client_key]) if ssl[:client_key]
http_set(http, :ca_file, ssl[:ca_file]) if ssl[:ca_file]
http_set(http, :ssl_version, ssl[:version]) if ssl[:version]
end
def http_set(http, attr, value)
if http.send(attr) != value
http.send("#{attr}=", value)
end
end
end
end
end

View File

@ -1,95 +0,0 @@
module Faraday
class Adapter
class Patron < Faraday::Adapter
dependency 'patron'
def call(env)
super
# TODO: support streaming requests
env[:body] = env[:body].read if env[:body].respond_to? :read
session = ::Patron::Session.new
@config_block.call(session) if @config_block
configure_ssl(session, env[:ssl]) if env[:url].scheme == 'https' and env[:ssl]
if req = env[:request]
session.timeout = session.connect_timeout = req[:timeout] if req[:timeout]
session.connect_timeout = req[:open_timeout] if req[:open_timeout]
if proxy = req[:proxy]
proxy_uri = proxy[:uri].dup
proxy_uri.user = proxy[:user] && Utils.escape(proxy[:user]).gsub('+', '%20')
proxy_uri.password = proxy[:password] && Utils.escape(proxy[:password]).gsub('+', '%20')
session.proxy = proxy_uri.to_s
end
end
response = begin
data = env[:body] ? env[:body].to_s : nil
session.request(env[:method], env[:url].to_s, env[:request_headers], :data => data)
rescue Errno::ECONNREFUSED, ::Patron::ConnectionFailed
raise Error::ConnectionFailed, $!
end
# Remove the "HTTP/1.1 200", leaving just the reason phrase
reason_phrase = response.status_line.gsub(/^.* \d{3} /, '')
save_response(env, response.status, response.body, response.headers, reason_phrase)
@app.call env
rescue ::Patron::TimeoutError => err
if connection_timed_out_message?(err.message)
raise Faraday::Error::ConnectionFailed, err
else
raise Faraday::Error::TimeoutError, err
end
rescue ::Patron::Error => err
if err.message.include?("code 407")
raise Error::ConnectionFailed, %{407 "Proxy Authentication Required "}
else
raise Error::ConnectionFailed, err
end
end
if loaded? && defined?(::Patron::Request::VALID_ACTIONS)
# HAX: helps but doesn't work completely
# https://github.com/toland/patron/issues/34
::Patron::Request::VALID_ACTIONS.tap do |actions|
if actions[0].is_a?(Symbol)
actions << :patch unless actions.include? :patch
actions << :options unless actions.include? :options
else
# Patron 0.4.20 and up
actions << "PATCH" unless actions.include? "PATCH"
actions << "OPTIONS" unless actions.include? "OPTIONS"
end
end
end
def configure_ssl(session, ssl)
if ssl.fetch(:verify, true)
session.cacert = ssl[:ca_file]
else
session.insecure = true
end
end
private
CURL_TIMEOUT_MESSAGES = [ "Connection time-out",
"Connection timed out",
"Timed out before name resolve",
"server connect has timed out",
"Resolving timed out",
"name lookup timed out",
"timed out before SSL",
"connect() timed out"
].freeze
def connection_timed_out_message?(message)
CURL_TIMEOUT_MESSAGES.any? { |curl_message| message.include?(curl_message) }
end
end
end
end

View File

@ -1,58 +0,0 @@
module Faraday
class Adapter
# Sends requests to a Rack app.
#
# Examples
#
# class MyRackApp
# def call(env)
# [200, {'Content-Type' => 'text/html'}, ["hello world"]]
# end
# end
#
# Faraday.new do |conn|
# conn.adapter :rack, MyRackApp.new
# end
class Rack < Faraday::Adapter
dependency 'rack/test'
# not prefixed with "HTTP_"
SPECIAL_HEADERS = %w[ CONTENT_LENGTH CONTENT_TYPE ]
def initialize(faraday_app, rack_app)
super(faraday_app)
mock_session = ::Rack::MockSession.new(rack_app)
@session = ::Rack::Test::Session.new(mock_session)
end
def call(env)
super
rack_env = {
:method => env[:method],
:input => env[:body].respond_to?(:read) ? env[:body].read : env[:body],
'rack.url_scheme' => env[:url].scheme
}
env[:request_headers].each do |name, value|
name = name.upcase.tr('-', '_')
name = "HTTP_#{name}" unless SPECIAL_HEADERS.include? name
rack_env[name] = value
end if env[:request_headers]
timeout = env[:request][:timeout] || env[:request][:open_timeout]
response = if timeout
Timer.timeout(timeout, Faraday::Error::TimeoutError) { execute_request(env, rack_env) }
else
execute_request(env, rack_env)
end
save_response(env, response.status, response.body, response.headers)
@app.call env
end
def execute_request(env, rack_env)
@session.request(env[:url].to_s, rack_env)
end
end
end
end

View File

@ -1,51 +1,78 @@
# frozen_string_literal: true
require 'timeout'
module Faraday
class Adapter
# Examples
#
# @example
# test = Faraday::Connection.new do
# use Faraday::Adapter::Test do |stub|
# # simply define matcher to match the request
# # Define matcher to match the request
# stub.get '/resource.json' do
# # return static content
# [200, {'Content-Type' => 'application/json'}, 'hi world']
# end
#
#
# # response with content generated based on request
# stub.get '/showget' do |env|
# [200, {'Content-Type' => 'text/plain'}, env[:method].to_s]
# end
#
# # regular expression can be used as matching filter
#
# # A regular expression can be used as matching filter
# stub.get /\A\/items\/(\d+)\z/ do |env, meta|
# # in case regular expression is used an instance of MatchData can be received
# [200, {'Content-Type' => 'text/plain'}, "showing item: #{meta[:match_data][1]}"]
# # in case regular expression is used, an instance of MatchData
# # can be received
# [200,
# {'Content-Type' => 'text/plain'},
# "showing item: #{meta[:match_data][1]}"
# ]
# end
#
# # Test the request body is the same as the stubbed body
# stub.post('/bar', 'name=YK&word=call') { [200, {}, ''] }
#
# # You can pass a proc as a stubbed body and check the request body in your way.
# # In this case, the proc should return true or false.
# stub.post('/foo', ->(request_body) do
# JSON.parse(request_body).slice('name') == { 'name' => 'YK' } }) { [200, {}, '']
# end
#
# # You can set strict_mode to exactly match the stubbed requests.
# stub.strict_mode = true
# end
# end
#
#
# resp = test.get '/resource.json'
# resp.body # => 'hi world'
#
#
# resp = test.get '/showget'
# resp.body # => 'get'
#
#
# resp = test.get '/items/1'
# resp.body # => 'showing item: 1'
#
#
# resp = test.get '/items/2'
# resp.body # => 'showing item: 2'
#
# resp = test.post '/bar', 'name=YK&word=call'
# resp.status # => 200
#
# resp = test.post '/foo', JSON.dump(name: 'YK', created_at: Time.now)
# resp.status # => 200
class Test < Faraday::Adapter
attr_accessor :stubs
# A stack of Stubs
class Stubs
class NotFound < StandardError
end
def initialize
# {:get => [Stub, Stub]}
@stack, @consumed = {}, {}
def initialize(strict_mode: false)
# { get: [Stub, Stub] }
@stack = {}
@consumed = {}
@strict_mode = strict_mode
@stubs_mutex = Monitor.new
yield(self) if block_given?
end
@ -53,17 +80,23 @@ module Faraday
@stack.empty?
end
def match(request_method, host, path, headers, body)
return false if !@stack.key?(request_method)
# @param env [Faraday::Env]
def match(env)
request_method = env[:method]
return false unless @stack.key?(request_method)
stack = @stack[request_method]
consumed = (@consumed[request_method] ||= [])
stub, meta = matches?(stack, host, path, headers, body)
if stub
consumed << stack.delete(stub)
return stub, meta
@stubs_mutex.synchronize do
stub, meta = matches?(stack, env)
if stub
removed = stack.delete(stub)
consumed << removed unless removed.nil?
return stub, meta
end
end
matches?(consumed, host, path, headers, body)
matches?(consumed, env)
end
def get(path, headers = {}, &block)
@ -74,15 +107,15 @@ module Faraday
new_stub(:head, path, headers, &block)
end
def post(path, body=nil, headers = {}, &block)
def post(path, body = nil, headers = {}, &block)
new_stub(:post, path, headers, body, &block)
end
def put(path, body=nil, headers = {}, &block)
def put(path, body = nil, headers = {}, &block)
new_stub(:put, path, headers, body, &block)
end
def patch(path, body=nil, headers = {}, &block)
def patch(path, body = nil, headers = {}, &block)
new_stub(:patch, path, headers, body, &block)
end
@ -98,87 +131,131 @@ module Faraday
def verify_stubbed_calls
failed_stubs = []
@stack.each do |method, stubs|
unless stubs.size == 0
failed_stubs.concat(stubs.map {|stub|
next if stubs.empty?
failed_stubs.concat(
stubs.map do |stub|
"Expected #{method} #{stub}."
})
end
)
end
raise failed_stubs.join(' ') unless failed_stubs.empty?
end
# Set strict_mode. If the value is true, this adapter tries to find matched requests strictly,
# which means that all of a path, parameters, and headers must be the same as an actual request.
def strict_mode=(value)
@strict_mode = value
@stack.each_value do |stubs|
stubs.each do |stub|
stub.strict_mode = value
end
end
raise failed_stubs.join(" ") unless failed_stubs.size == 0
end
protected
def new_stub(request_method, path, headers = {}, body=nil, &block)
def new_stub(request_method, path, headers = {}, body = nil, &block)
normalized_path, host =
if path.is_a?(Regexp)
path
else
[Faraday::Utils.normalize_path(path), Faraday::Utils.URI(path).host]
[
Faraday::Utils.normalize_path(path),
Faraday::Utils.URI(path).host
]
end
path, query = normalized_path.respond_to?(:split) ? normalized_path.split('?') : normalized_path
headers = Utils::Headers.new(headers)
(@stack[request_method] ||= []) << Stub.new(host, normalized_path, headers, body, block)
stub = Stub.new(host, path, query, headers, body, @strict_mode, block)
(@stack[request_method] ||= []) << stub
end
def matches?(stack, host, path, headers, body)
# @param stack [Hash]
# @param env [Faraday::Env]
def matches?(stack, env)
stack.each do |stub|
match_result, meta = stub.matches?(host, path, headers, body)
match_result, meta = stub.matches?(env)
return stub, meta if match_result
end
nil
end
end
class Stub < Struct.new(:host, :path, :params, :headers, :body, :block)
def initialize(host, full, headers, body, block)
path, query = full.respond_to?(:split) ? full.split("?") : full
params = query ?
Faraday::Utils.parse_nested_query(query) :
{}
super(host, path, params, headers, body, block)
end
# Stub request
Stub = Struct.new(:host, :path, :query, :headers, :body, :strict_mode, :block) do
# @param env [Faraday::Env]
def matches?(env)
request_host = env[:url].host
request_path = Faraday::Utils.normalize_path(env[:url].path)
request_headers = env.request_headers
request_body = env[:body]
def matches?(request_host, request_uri, request_headers, request_body)
request_path, request_query = request_uri.split('?')
request_params = request_query ?
Faraday::Utils.parse_nested_query(request_query) :
{}
# meta is a hash use as carrier
# meta is a hash used as carrier
# that will be yielded to consumer block
meta = {}
return (host.nil? || host == request_host) &&
[(host.nil? || host == request_host) &&
path_match?(request_path, meta) &&
params_match?(request_params) &&
(body.to_s.size.zero? || request_body == body) &&
headers_match?(request_headers), meta
params_match?(env) &&
body_match?(request_body) &&
headers_match?(request_headers), meta]
end
def path_match?(request_path, meta)
if path.is_a? Regexp
if path.is_a?(Regexp)
!!(meta[:match_data] = path.match(request_path))
else
path == request_path
end
end
def params_match?(request_params)
# @param env [Faraday::Env]
def params_match?(env)
request_params = env[:params]
params = env.params_encoder.decode(query) || {}
if strict_mode
return Set.new(params) == Set.new(request_params)
end
params.keys.all? do |key|
request_params[key] == params[key]
end
end
def headers_match?(request_headers)
if strict_mode
headers_with_user_agent = headers.dup.tap do |hs|
# NOTE: Set User-Agent in case it's not set when creating Stubs.
# Users would not want to set Faraday's User-Agent explicitly.
hs[:user_agent] ||= Connection::USER_AGENT
end
return Set.new(headers_with_user_agent) == Set.new(request_headers)
end
headers.keys.all? do |key|
request_headers[key] == headers[key]
end
end
def body_match?(request_body)
return true if body.to_s.empty?
case body
when Proc
body.call(request_body)
else
request_body == body
end
end
def to_s
"#{path} #{body}"
end
end
def initialize(app, stubs=nil, &block)
def initialize(app, stubs = nil, &block)
super(app)
@stubs = stubs || Stubs.new
configure(&block) if block
@ -188,26 +265,47 @@ module Faraday
yield(stubs)
end
# @param env [Faraday::Env]
def call(env)
super
host = env[:url].host
normalized_path = Faraday::Utils.normalize_path(env[:url])
params_encoder = env.request.params_encoder || Faraday::Utils.default_params_encoder
stub, meta = stubs.match(env[:method], host, normalized_path, env.request_headers, env[:body])
if stub
env[:params] = (query = env[:url].query) ?
params_encoder.decode(query) : {}
block_arity = stub.block.arity
status, headers, body = (block_arity >= 0) ?
stub.block.call(*[env, meta].take(block_arity)) :
stub.block.call(env, meta)
save_response(env, status, body, headers)
else
raise Stubs::NotFound, "no stubbed request for #{env[:method]} #{normalized_path} #{env[:body]}"
env.request.params_encoder ||= Faraday::Utils.default_params_encoder
env[:params] = env.params_encoder.decode(env[:url].query) || {}
stub, meta = stubs.match(env)
unless stub
raise Stubs::NotFound, "no stubbed request for #{env[:method]} " \
"#{env[:url]} #{env[:body]} #{env[:headers]}"
end
block_arity = stub.block.arity
params = if block_arity >= 0
[env, meta].take(block_arity)
else
[env, meta]
end
timeout = request_timeout(:open, env[:request])
timeout ||= request_timeout(:read, env[:request])
status, headers, body =
if timeout
::Timeout.timeout(timeout, Faraday::TimeoutError) do
stub.block.call(*params)
end
else
stub.block.call(*params)
end
# We need to explicitly pass `reason_phrase = nil` here to avoid keyword args conflicts.
# See https://github.com/lostisland/faraday/issues/1444
# TODO: remove `nil` explicit reason_phrase once Ruby 3.0 becomes minimum req. version
save_response(env, status, body, headers, nil)
@app.call(env)
end
end
end
end
Faraday::Adapter.register_middleware(test: Faraday::Adapter::Test)

View File

@ -1,12 +0,0 @@
module Faraday
class Adapter
# This class is just a stub, the real adapter is in https://github.com/philsturgeon/typhoeus/blob/master/lib/typhoeus/adapters/faraday.rb
class Typhoeus < Faraday::Adapter
# Needs to define this method in order to support Typhoeus <= 1.3.0
def call; end
dependency 'typhoeus'
dependency 'typhoeus/adapters/faraday'
end
end
end

View File

@ -0,0 +1,30 @@
# frozen_string_literal: true
require 'monitor'
module Faraday
# AdapterRegistry registers adapter class names so they can be looked up by a
# String or Symbol name.
class AdapterRegistry
def initialize
@lock = Monitor.new
@constants = {}
end
def get(name)
klass = @lock.synchronize do
@constants[name]
end
return klass if klass
Object.const_get(name).tap { |c| set(c, name) }
end
def set(klass, name = nil)
name ||= klass.to_s
@lock.synchronize do
@constants[name] = klass
end
end
end
end

View File

@ -1,84 +0,0 @@
module Faraday
# Internal: Adds the ability for other modules to manage autoloadable
# constants.
module AutoloadHelper
# Internal: Registers the constants to be auto loaded.
#
# prefix - The String require prefix. If the path is inside Faraday, then
# it will be prefixed with the root path of this loaded Faraday
# version.
# options - Hash of Symbol => String library names.
#
# Examples.
#
# Faraday.autoload_all 'faraday/foo',
# :Bar => 'bar'
#
# # requires faraday/foo/bar to load Faraday::Bar.
# Faraday::Bar
#
#
# Returns nothing.
def autoload_all(prefix, options)
if prefix =~ /^faraday(\/|$)/i
prefix = File.join(Faraday.root_path, prefix)
end
options.each do |const_name, path|
autoload const_name, File.join(prefix, path)
end
end
# Internal: Loads each autoloaded constant. If thread safety is a concern,
# wrap this in a Mutex.
#
# Returns nothing.
def load_autoloaded_constants
constants.each do |const|
const_get(const) if autoload?(const)
end
end
# Internal: Filters the module's contents with those that have been already
# autoloaded.
#
# Returns an Array of Class/Module objects.
def all_loaded_constants
constants.map { |c| const_get(c) }.
select { |a| a.respond_to?(:loaded?) && a.loaded? }
end
end
class Adapter
extend AutoloadHelper
autoload_all 'faraday/adapter',
:NetHttp => 'net_http',
:NetHttpPersistent => 'net_http_persistent',
:EMSynchrony => 'em_synchrony',
:EMHttp => 'em_http',
:Typhoeus => 'typhoeus',
:Patron => 'patron',
:Excon => 'excon',
:Test => 'test',
:Rack => 'rack',
:HTTPClient => 'httpclient'
end
class Request
extend AutoloadHelper
autoload_all 'faraday/request',
:UrlEncoded => 'url_encoded',
:Multipart => 'multipart',
:Retry => 'retry',
:Authorization => 'authorization',
:BasicAuthentication => 'basic_authentication',
:TokenAuthentication => 'token_authentication',
:Instrumentation => 'instrumentation'
end
class Response
extend AutoloadHelper
autoload_all 'faraday/response',
:RaiseError => 'raise_error',
:Logger => 'logger'
end
end

View File

@ -1,67 +1,70 @@
# frozen_string_literal: true
module Faraday
# Public: Connection objects manage the default properties and the middleware
# Connection objects manage the default properties and the middleware
# stack for fulfilling an HTTP request.
#
# Examples
# @example
#
# conn = Faraday::Connection.new 'http://sushi.com'
# conn = Faraday::Connection.new 'http://httpbingo.org'
#
# # GET http://sushi.com/nigiri
# # GET http://httpbingo.org/nigiri
# conn.get 'nigiri'
# # => #<Faraday::Response>
#
class Connection
# A Set of allowed HTTP verbs.
METHODS = Set.new [:get, :post, :put, :delete, :head, :patch, :options]
METHODS = Set.new %i[get post put delete head patch options trace]
USER_AGENT = "Faraday v#{VERSION}".freeze
# Public: Returns a Hash of URI query unencoded key/value pairs.
# @return [Hash] URI query unencoded key/value pairs.
attr_reader :params
# Public: Returns a Hash of unencoded HTTP header key/value pairs.
# @return [Hash] unencoded HTTP header key/value pairs.
attr_reader :headers
# Public: Returns a URI with the prefix used for all requests from this
# Connection. This includes a default host name, scheme, port, and path.
# @return [String] a URI with the prefix used for all requests from this
# Connection. This includes a default host name, scheme, port, and path.
attr_reader :url_prefix
# Public: Returns the Faraday::Builder for this Connection.
# @return [Faraday::RackBuilder] Builder for this Connection.
attr_reader :builder
# Public: Returns a Hash of the request options.
attr_reader :options
# Public: Returns a Hash of the SSL options.
# @return [Hash] SSL options.
attr_reader :ssl
# Public: Returns the parallel manager for this Connection.
# @return [Object] the parallel manager for this Connection.
attr_reader :parallel_manager
# Public: Sets the default parallel manager for this connection.
# Sets the default parallel manager for this connection.
attr_writer :default_parallel_manager
# Public: Gets or Sets the Hash proxy options.
# attr_reader :proxy
# @return [Hash] proxy options.
attr_reader :proxy
# Public: Initializes a new Faraday::Connection.
# Initializes a new Faraday::Connection.
#
# url - URI or String base URL to use as a prefix for all
# @param url [URI, String] URI or String base URL to use as a prefix for all
# requests (optional).
# options - Hash or Faraday::ConnectionOptions.
# :url - URI or String base URL (default: "http:/").
# :params - Hash of URI query unencoded key/value pairs.
# :headers - Hash of unencoded HTTP header key/value pairs.
# :request - Hash of request options.
# :ssl - Hash of SSL options.
# :proxy - URI, String or Hash of HTTP proxy options
# (default: "http_proxy" environment variable).
# :uri - URI or String
# :user - String (optional)
# :password - String (optional)
# @param options [Hash, Faraday::ConnectionOptions]
# @option options [URI, String] :url ('http:/') URI or String base URL
# @option options [Hash<String => String>] :params URI query unencoded
# key/value pairs.
# @option options [Hash<String => String>] :headers Hash of unencoded HTTP
# header key/value pairs.
# @option options [Hash] :request Hash of request options.
# @option options [Hash] :ssl Hash of SSL options.
# @option options [Hash, URI, String] :proxy proxy options, either as a URL
# or as a Hash
# @option options [URI, String] :proxy[:uri]
# @option options [String] :proxy[:user]
# @option options [String] :proxy[:password]
# @yield [self] after all setup has been done
def initialize(url = nil, options = nil)
options = ConnectionOptions.from(options)
if url.is_a?(Hash) || url.is_a?(ConnectionOptions)
options = options.merge(url)
options = Utils.deep_merge(options, url)
url = options.url
end
@ -71,10 +74,11 @@ module Faraday
@options = options.request
@ssl = options.ssl
@default_parallel_manager = options.parallel_manager
@manual_proxy = nil
@builder = options.builder || begin
# pass an empty block to Builder so it doesn't assume default middleware
options.new_builder(block_given? ? Proc.new { |b| } : nil)
options.new_builder(block_given? ? proc { |b| } : nil)
end
self.url_prefix = url || 'http:/'
@ -82,94 +86,195 @@ module Faraday
@params.update(options.params) if options.params
@headers.update(options.headers) if options.headers
@manual_proxy = !!options.proxy
@proxy = options.proxy ? ProxyOptions.from(options.proxy) : proxy_from_env(url)
@temp_proxy = @proxy
initialize_proxy(url, options)
yield(self) if block_given?
@headers[:user_agent] ||= "Faraday v#{VERSION}"
@headers[:user_agent] ||= USER_AGENT
end
# Public: Sets the Hash of URI query unencoded key/value pairs.
def initialize_proxy(url, options)
@manual_proxy = !!options.proxy
@proxy =
if options.proxy
ProxyOptions.from(options.proxy)
else
proxy_from_env(url)
end
end
# Sets the Hash of URI query unencoded key/value pairs.
# @param hash [Hash]
def params=(hash)
@params.replace hash
end
# Public: Sets the Hash of unencoded HTTP header key/value pairs.
# Sets the Hash of unencoded HTTP header key/value pairs.
# @param hash [Hash]
def headers=(hash)
@headers.replace hash
end
extend Forwardable
def_delegators :builder, :build, :use, :request, :response, :adapter, :app
def_delegators :builder, :use, :request, :response, :adapter, :app
# Public: Makes an HTTP request without a body.
# Closes the underlying resources and/or connections. In the case of
# persistent connections, this closes all currently open connections
# but does not prevent new connections from being made.
def close
app.close
end
# @!method get(url = nil, params = nil, headers = nil)
# Makes a GET HTTP request without a body.
# @!scope class
#
# url - The optional String base URL to use as a prefix for all
# requests. Can also be the options Hash.
# params - Hash of URI query unencoded key/value pairs.
# headers - Hash of unencoded HTTP header key/value pairs.
# @param url [String, URI, nil] The optional String base URL to use as a prefix for
# all requests. Can also be the options Hash.
# @param params [Hash, nil] Hash of URI query unencoded key/value pairs.
# @param headers [Hash, nil] unencoded HTTP header key/value pairs.
#
# Examples
#
# conn.get '/items', {:page => 1}, :accept => 'application/json'
# conn.head '/items/1'
# @example
# conn.get '/items', { page: 1 }, :accept => 'application/json'
#
# # ElasticSearch example sending a body with GET.
# conn.get '/twitter/tweet/_search' do |req|
# req.headers[:content_type] = 'application/json'
# req.params[:routing] = 'kimchy'
# req.body = JSON.generate(:query => {...})
# req.body = JSON.generate(query: {...})
# end
#
# Yields a Faraday::Request for further request customizations.
# Returns a Faraday::Response.
# @yield [Faraday::Request] for further request customizations
# @return [Faraday::Response]
# @!method head(url = nil, params = nil, headers = nil)
# Makes a HEAD HTTP request without a body.
# @!scope class
#
# Signature
# @param url [String, URI, nil] The optional String base URL to use as a prefix for
# all requests. Can also be the options Hash.
# @param params [Hash, nil] Hash of URI query unencoded key/value pairs.
# @param headers [Hash, nil] unencoded HTTP header key/value pairs.
#
# <verb>(url = nil, params = nil, headers = nil)
# @example
# conn.head '/items/1'
#
# verb - An HTTP verb: get, head, or delete.
%w[get head delete].each do |method|
# @yield [Faraday::Request] for further request customizations
# @return [Faraday::Response]
# @!method delete(url = nil, params = nil, headers = nil)
# Makes a DELETE HTTP request without a body.
# @!scope class
#
# @param url [String, URI, nil] The optional String base URL to use as a prefix for
# all requests. Can also be the options Hash.
# @param params [Hash, nil] Hash of URI query unencoded key/value pairs.
# @param headers [Hash, nil] unencoded HTTP header key/value pairs.
#
# @example
# conn.delete '/items/1'
#
# @yield [Faraday::Request] for further request customizations
# @return [Faraday::Response]
# @!method trace(url = nil, params = nil, headers = nil)
# Makes a TRACE HTTP request without a body.
# @!scope class
#
# @param url [String, URI, nil] The optional String base URL to use as a prefix for
# all requests. Can also be the options Hash.
# @param params [Hash, nil] Hash of URI query unencoded key/value pairs.
# @param headers [Hash, nil] unencoded HTTP header key/value pairs.
#
# @example
# conn.connect '/items/1'
#
# @yield [Faraday::Request] for further request customizations
# @return [Faraday::Response]
# @!visibility private
METHODS_WITH_QUERY.each do |method|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
def #{method}(url = nil, params = nil, headers = nil)
run_request(:#{method}, url, nil, headers) { |request|
run_request(:#{method}, url, nil, headers) do |request|
request.params.update(params) if params
yield(request) if block_given?
}
yield request if block_given?
end
end
RUBY
end
# Public: Makes an HTTP request with a body.
# @overload options()
# Returns current Connection options.
#
# url - The optional String base URL to use as a prefix for all
# requests. Can also be the options Hash.
# body - The String body for the request.
# headers - Hash of unencoded HTTP header key/value pairs.
# @overload options(url, params = nil, headers = nil)
# Makes an OPTIONS HTTP request to the given URL.
# @param url [String, URI, nil] String base URL to sue as a prefix for all requests.
# @param params [Hash, nil] Hash of URI query unencoded key/value pairs.
# @param headers [Hash, nil] unencoded HTTP header key/value pairs.
#
# Examples
# @example
# conn.options '/items/1'
#
# conn.post '/items', data, :content_type => 'application/json'
# @yield [Faraday::Request] for further request customizations
# @return [Faraday::Response]
def options(*args)
return @options if args.empty?
url, params, headers = *args
run_request(:options, url, nil, headers) do |request|
request.params.update(params) if params
yield request if block_given?
end
end
# @!method post(url = nil, body = nil, headers = nil)
# Makes a POST HTTP request with a body.
# @!scope class
#
# @param url [String, URI, nil] The optional String base URL to use as a prefix for
# all requests. Can also be the options Hash.
# @param body [String, nil] body for the request.
# @param headers [Hash, nil] unencoded HTTP header key/value pairs.
#
# @example
# conn.post '/items', data, content_type: 'application/json'
#
# # Simple ElasticSearch indexing sample.
# conn.post '/twitter/tweet' do |req|
# req.headers[:content_type] = 'application/json'
# req.params[:routing] = 'kimchy'
# req.body = JSON.generate(:user => 'kimchy', ...)
# req.body = JSON.generate(user: 'kimchy', ...)
# end
#
# Yields a Faraday::Request for further request customizations.
# Returns a Faraday::Response.
# @yield [Faraday::Request] for further request customizations
# @return [Faraday::Response]
# @!method put(url = nil, body = nil, headers = nil)
# Makes a PUT HTTP request with a body.
# @!scope class
#
# Signature
# @param url [String, URI, nil] The optional String base URL to use as a prefix for
# all requests. Can also be the options Hash.
# @param body [String, nil] body for the request.
# @param headers [Hash, nil] unencoded HTTP header key/value pairs.
#
# <verb>(url = nil, body = nil, headers = nil)
# @example
# conn.put '/products/123', data, content_type: 'application/json'
#
# verb - An HTTP verb: post, put, or patch.
%w[post put patch].each do |method|
# # Star a gist.
# conn.put 'https://api.github.com/gists/GIST_ID/star' do |req|
# req.headers['Accept'] = 'application/vnd.github+json'
# req.headers['Authorization'] = 'Bearer <YOUR-TOKEN>'
# req.headers['X-GitHub-Api-Version'] = '2022-11-28'
# end
#
# @yield [Faraday::Request] for further request customizations
# @return [Faraday::Response]
# @!visibility private
METHODS_WITH_BODY.each do |method|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
def #{method}(url = nil, body = nil, headers = nil, &block)
run_request(:#{method}, url, body, headers, &block)
@ -177,116 +282,62 @@ module Faraday
RUBY
end
# Public: Sets up the Authorization header with these credentials, encoded
# with base64.
# Check if the adapter is parallel-capable.
#
# login - The authentication login.
# pass - The authentication password.
# @yield if the adapter isn't parallel-capable, or if no adapter is set yet.
#
# Examples
#
# conn.basic_auth 'Aladdin', 'open sesame'
# conn.headers['Authorization']
# # => "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
#
# Returns nothing.
def basic_auth(login, pass)
set_authorization_header(:basic_auth, login, pass)
end
# Public: Sets up the Authorization header with the given token.
#
# token - The String token.
# options - Optional Hash of extra token options.
#
# Examples
#
# conn.token_auth 'abcdef', :foo => 'bar'
# conn.headers['Authorization']
# # => "Token token=\"abcdef\",
# foo=\"bar\""
#
# Returns nothing.
def token_auth(token, options = nil)
set_authorization_header(:token_auth, token, options)
end
# Public: Sets up a custom Authorization header.
#
# type - The String authorization type.
# token - The String or Hash token. A String value is taken literally, and
# a Hash is encoded into comma separated key/value pairs.
#
# Examples
#
# conn.authorization :Bearer, 'mF_9.B5f-4.1JqM'
# conn.headers['Authorization']
# # => "Bearer mF_9.B5f-4.1JqM"
#
# conn.authorization :Token, :token => 'abcdef', :foo => 'bar'
# conn.headers['Authorization']
# # => "Token token=\"abcdef\",
# foo=\"bar\""
#
# Returns nothing.
def authorization(type, token)
set_authorization_header(:authorization, type, token)
end
# Internal: Traverse the middleware stack in search of a
# parallel-capable adapter.
#
# Yields in case of not found.
#
# Returns a parallel manager or nil if not found.
# @return [Object, nil] a parallel manager or nil if yielded
# @api private
def default_parallel_manager
@default_parallel_manager ||= begin
handler = @builder.handlers.detect do |h|
h.klass.respond_to?(:supports_parallel?) and h.klass.supports_parallel?
end
adapter = @builder.adapter.klass if @builder.adapter
if handler
handler.klass.setup_parallel_manager
if support_parallel?(adapter)
adapter.setup_parallel_manager
elsif block_given?
yield
end
end
end
# Public: Determine if this Faraday::Connection can make parallel requests.
# Determine if this Faraday::Connection can make parallel requests.
#
# Returns true or false.
# @return [Boolean]
def in_parallel?
!!@parallel_manager
end
# Public: Sets up the parallel manager to make a set of requests.
# Sets up the parallel manager to make a set of requests.
#
# manager - The parallel manager that this Connection's Adapter uses.
# @param manager [Object] The parallel manager that this Connection's
# Adapter uses.
#
# Yields a block to execute multiple requests.
# Returns nothing.
def in_parallel(manager = nil)
@parallel_manager = manager || default_parallel_manager {
warn "Warning: `in_parallel` called but no parallel-capable adapter on Faraday stack"
warn caller[2,10].join("\n")
# @yield a block to execute multiple requests.
# @return [void]
def in_parallel(manager = nil, &block)
@parallel_manager = manager || default_parallel_manager do
warn 'Warning: `in_parallel` called but no parallel-capable adapter ' \
'on Faraday stack'
warn caller[2, 10].join("\n")
nil
}
yield
@parallel_manager && @parallel_manager.run
end
return yield unless @parallel_manager
if @parallel_manager.respond_to?(:execute)
# Execute is the new method that is responsible for executing the block.
@parallel_manager.execute(&block)
else
# TODO: Old behaviour, deprecate and remove in 3.0
yield
@parallel_manager.run
end
ensure
@parallel_manager = nil
end
# Public: Gets or Sets the Hash proxy options.
def proxy(arg = nil)
return @proxy if arg.nil?
warn 'Warning: use of proxy(new_value) to set connection proxy have been DEPRECATED and will be removed in Faraday 1.0'
@manual_proxy = true
@proxy = ProxyOptions.from(arg)
end
# Public: Sets the Hash proxy options.
# Sets the Hash proxy options.
#
# @param new_value [Object]
def proxy=(new_value)
@manual_proxy = true
@proxy = new_value ? ProxyOptions.from(new_value) : nil
@ -295,22 +346,21 @@ module Faraday
def_delegators :url_prefix, :scheme, :scheme=, :host, :host=, :port, :port=
def_delegator :url_prefix, :path, :path_prefix
# Public: Parses the giving url with URI and stores the individual
# components in this connection. These components serve as defaults for
# Parses the given URL with URI and stores the individual
# components in this connection. These components serve as defaults for
# requests made by this connection.
#
# url - A String or URI.
# @param url [String, URI]
# @param encoder [Object]
#
# Examples
# @example
#
# conn = Faraday::Connection.new { ... }
# conn.url_prefix = "https://sushi.com/api"
# conn.url_prefix = "https://httpbingo.org/api"
# conn.scheme # => https
# conn.path_prefix # => "/api"
#
# conn.get("nigiri?page=2") # accesses https://sushi.com/api/nigiri
#
# Returns the parsed URI from the given input..
# conn.get("nigiri?page=2") # accesses https://httpbingo.org/api/nigiri
def url_prefix=(url, encoder = nil)
uri = @url_prefix = Utils.URI(url)
self.path_prefix = uri.path
@ -319,65 +369,80 @@ module Faraday
uri.query = nil
with_uri_credentials(uri) do |user, password|
basic_auth user, password
set_basic_auth(user, password)
uri.user = uri.password = nil
end
uri
@proxy = proxy_from_env(url) unless @manual_proxy
end
# Public: Sets the path prefix and ensures that it always has a leading
def set_basic_auth(user, password)
header = Faraday::Utils.basic_header_from(user, password)
headers[Faraday::Request::Authorization::KEY] = header
end
# Sets the path prefix and ensures that it always has a leading
# slash.
#
# value - A String.
# @param value [String]
#
# Returns the new String path prefix.
# @return [String] the new path prefix
def path_prefix=(value)
url_prefix.path = if value
value = '/' + value unless value[0,1] == '/'
value
end
value = "/#{value}" unless value[0, 1] == '/'
value
end
end
# Public: Takes a relative url for a request and combines it with the defaults
# Takes a relative url for a request and combines it with the defaults
# set on the connection instance.
#
# @param url [String, URI, nil]
# @param extra_params [Hash]
#
# @example
# conn = Faraday::Connection.new { ... }
# conn.url_prefix = "https://sushi.com/api?token=abc"
# conn.url_prefix = "https://httpbingo.org/api?token=abc"
# conn.scheme # => https
# conn.path_prefix # => "/api"
#
# conn.build_url("nigiri?page=2") # => https://sushi.com/api/nigiri?token=abc&page=2
# conn.build_url("nigiri", :page => 2) # => https://sushi.com/api/nigiri?token=abc&page=2
# conn.build_url("nigiri?page=2")
# # => https://httpbingo.org/api/nigiri?token=abc&page=2
#
# conn.build_url("nigiri", page: 2)
# # => https://httpbingo.org/api/nigiri?token=abc&page=2
#
def build_url(url = nil, extra_params = nil)
uri = build_exclusive_url(url)
query_values = params.dup.merge_query(uri.query, options.params_encoder)
query_values.update extra_params if extra_params
uri.query = query_values.empty? ? nil : query_values.to_query(options.params_encoder)
query_values.update(extra_params) if extra_params
uri.query =
if query_values.empty?
nil
else
query_values.to_query(options.params_encoder)
end
uri
end
# Builds and runs the Faraday::Request.
#
# method - The Symbol HTTP method.
# url - The String or URI to access.
# body - The request body that will eventually be converted to a string.
# headers - Hash of unencoded HTTP header key/value pairs.
# @param method [Symbol] HTTP method.
# @param url [String, URI, nil] String or URI to access.
# @param body [String, Hash, Array, nil] The request body that will eventually be converted to
# a string; middlewares can be used to support more complex types.
# @param headers [Hash, nil] unencoded HTTP header key/value pairs.
#
# Returns a Faraday::Response.
# @return [Faraday::Response]
def run_request(method, url, body, headers)
if !METHODS.include?(method)
unless METHODS.include?(method)
raise ArgumentError, "unknown http method: #{method}"
end
# Resets temp_proxy
@temp_proxy = proxy_for_request(url)
request = build_request(method) do |req|
req.options = req.options.merge(:proxy => @temp_proxy)
req.options.proxy = proxy_for_request(url)
req.url(url) if url
req.headers.update(headers) if headers
req.body = body if body
@ -389,96 +454,111 @@ module Faraday
# Creates and configures the request object.
#
# Returns the new Request.
# @param method [Symbol]
#
# @yield [Faraday::Request] if block given
# @return [Faraday::Request]
def build_request(method)
Request.create(method) do |req|
req.params = self.params.dup
req.headers = self.headers.dup
req.options = self.options
req.params = params.dup
req.headers = headers.dup
req.options = options.dup
yield(req) if block_given?
end
end
# Internal: Build an absolute URL based on url_prefix.
# Build an absolute URL based on url_prefix.
#
# url - A String or URI-like object
# params - A Faraday::Utils::ParamsHash to replace the query values
# @param url [String, URI, nil]
# @param params [Faraday::Utils::ParamsHash] A Faraday::Utils::ParamsHash to
# replace the query values
# of the resulting url (default: nil).
#
# Returns the resulting URI instance.
# @return [URI]
def build_exclusive_url(url = nil, params = nil, params_encoder = nil)
url = nil if url.respond_to?(:empty?) and url.empty?
base = url_prefix
if url and base.path and base.path !~ /\/$/
base = base.dup
base.path = base.path + '/' # ensure trailing slash
url = nil if url.respond_to?(:empty?) && url.empty?
base = url_prefix.dup
if url && !base.path.end_with?('/')
base.path = "#{base.path}/" # ensure trailing slash
end
# Ensure relative url will be parsed correctly (such as `service:search` )
url = "./#{url}" if url.respond_to?(:start_with?) && !url.start_with?('http://', 'https://', '/', './', '../')
uri = url ? base + url : base
uri.query = params.to_query(params_encoder || options.params_encoder) if params
uri.query = nil if uri.query and uri.query.empty?
if params
uri.query = params.to_query(params_encoder || options.params_encoder)
end
uri.query = nil if uri.query && uri.query.empty?
uri
end
# Internal: Creates a duplicate of this Faraday::Connection.
# Creates a duplicate of this Faraday::Connection.
#
# Returns a Faraday::Connection.
# @api private
#
# @return [Faraday::Connection]
def dup
self.class.new(build_exclusive_url,
:headers => headers.dup,
:params => params.dup,
:builder => builder.dup,
:ssl => ssl.dup,
:request => options.dup)
headers: headers.dup,
params: params.dup,
builder: builder.dup,
ssl: ssl.dup,
request: options.dup)
end
# Internal: Yields username and password extracted from a URI if they both exist.
# Yields username and password extracted from a URI if they both exist.
#
# @param uri [URI]
# @yield [username, password] any username and password
# @yieldparam username [String] any username from URI
# @yieldparam password [String] any password from URI
# @return [void]
# @api private
def with_uri_credentials(uri)
if uri.user and uri.password
yield(Utils.unescape(uri.user), Utils.unescape(uri.password))
end
end
return unless uri.user && uri.password
def set_authorization_header(header_type, *args)
header = Faraday::Request.lookup_middleware(header_type).
header(*args)
headers[Faraday::Request::Authorization::KEY] = header
yield(Utils.unescape(uri.user), Utils.unescape(uri.password))
end
def proxy_from_env(url)
return if Faraday.ignore_env_proxy
uri = nil
if URI.parse('').respond_to?(:find_proxy)
case url
when String
uri = Utils.URI(url)
uri = URI.parse("#{uri.scheme}://#{uri.hostname}").find_proxy
when URI
uri = url.find_proxy
when nil
uri = find_default_proxy
end
else
warn 'no_proxy is unsupported' if ENV['no_proxy'] || ENV['NO_PROXY']
case url
when String
uri = Utils.URI(url)
uri = if uri.host.nil?
find_default_proxy
else
URI.parse("#{uri.scheme}://#{uri.host}").find_proxy
end
when URI
uri = url.find_proxy
when nil
uri = find_default_proxy
end
ProxyOptions.from(uri) if uri
end
def find_default_proxy
uri = ENV['http_proxy']
if uri && !uri.empty?
uri = 'http://' + uri if uri !~ /^http/i
uri
end
uri = ENV.fetch('http_proxy', nil)
return unless uri && !uri.empty?
uri = "http://#{uri}" unless uri.match?(/^http/i)
uri
end
def proxy_for_request(url)
return self.proxy if @manual_proxy
return proxy if @manual_proxy
if url && Utils.URI(url).absolute?
proxy_from_env(url)
else
self.proxy
proxy
end
end
def support_parallel?(adapter)
adapter.respond_to?(:supports_parallel?) && adapter&.supports_parallel?
end
end
end

View File

@ -0,0 +1,105 @@
# frozen_string_literal: true
module Faraday
# FlatParamsEncoder manages URI params as a flat hash. Any Array values repeat
# the parameter multiple times.
module FlatParamsEncoder
class << self
extend Forwardable
def_delegators :'Faraday::Utils', :escape, :unescape
end
# Encode converts the given param into a URI querystring. Keys and values
# will converted to strings and appropriately escaped for the URI.
#
# @param params [Hash] query arguments to convert.
#
# @example
#
# encode({a: %w[one two three], b: true, c: "C"})
# # => 'a=one&a=two&a=three&b=true&c=C'
#
# @return [String] the URI querystring (without the leading '?')
def self.encode(params)
return nil if params.nil?
unless params.is_a?(Array)
unless params.respond_to?(:to_hash)
raise TypeError,
"Can't convert #{params.class} into Hash."
end
params = params.to_hash
params = params.map do |key, value|
key = key.to_s if key.is_a?(Symbol)
[key, value]
end
# Only to be used for non-Array inputs. Arrays should preserve order.
params.sort! if @sort_params
end
# The params have form [['key1', 'value1'], ['key2', 'value2']].
buffer = +''
params.each do |key, value|
encoded_key = escape(key)
if value.nil?
buffer << "#{encoded_key}&"
elsif value.is_a?(Array)
if value.empty?
buffer << "#{encoded_key}=&"
else
value.each do |sub_value|
encoded_value = escape(sub_value)
buffer << "#{encoded_key}=#{encoded_value}&"
end
end
else
encoded_value = escape(value)
buffer << "#{encoded_key}=#{encoded_value}&"
end
end
buffer.chop
end
# Decode converts the given URI querystring into a hash.
#
# @param query [String] query arguments to parse.
#
# @example
#
# decode('a=one&a=two&a=three&b=true&c=C')
# # => {"a"=>["one", "two", "three"], "b"=>"true", "c"=>"C"}
#
# @return [Hash] parsed keys and value strings from the querystring.
def self.decode(query)
return nil if query.nil?
empty_accumulator = {}
split_query = query.split('&').filter_map do |pair|
pair.split('=', 2) if pair && !pair.empty?
end
split_query.each_with_object(empty_accumulator.dup) do |pair, accu|
pair[0] = unescape(pair[0])
pair[1] = true if pair[1].nil?
if pair[1].respond_to?(:to_str)
pair[1] = unescape(pair[1].to_str.tr('+', ' '))
end
if accu[pair[0]].is_a?(Array)
accu[pair[0]] << pair[1]
elsif accu[pair[0]]
accu[pair[0]] = [accu[pair[0]], pair[1]]
else
accu[pair[0]] = pair[1]
end
end
end
class << self
attr_accessor :sort_params
end
# Useful default for OAuth and caching.
@sort_params = true
end
end

View File

@ -0,0 +1,183 @@
# frozen_string_literal: true
module Faraday
# Sub-module for encoding parameters into query-string.
module EncodeMethods
# @param params [nil, Array, #to_hash] parameters to be encoded
#
# @return [String] the encoded params
#
# @raise [TypeError] if params can not be converted to a Hash
def encode(params)
return nil if params.nil?
unless params.is_a?(Array)
unless params.respond_to?(:to_hash)
raise TypeError, "Can't convert #{params.class} into Hash."
end
params = params.to_hash
params = params.map do |key, value|
key = key.to_s if key.is_a?(Symbol)
[key, value]
end
# Only to be used for non-Array inputs. Arrays should preserve order.
params.sort! if @sort_params
end
# The params have form [['key1', 'value1'], ['key2', 'value2']].
buffer = +''
params.each do |parent, value|
encoded_parent = escape(parent)
buffer << "#{encode_pair(encoded_parent, value)}&"
end
buffer.chop
end
protected
def encode_pair(parent, value)
if value.is_a?(Hash)
encode_hash(parent, value)
elsif value.is_a?(Array)
encode_array(parent, value)
elsif value.nil?
parent
else
encoded_value = escape(value)
"#{parent}=#{encoded_value}"
end
end
def encode_hash(parent, value)
value = value.map { |key, val| [escape(key), val] }.sort
buffer = +''
value.each do |key, val|
new_parent = "#{parent}%5B#{key}%5D"
buffer << "#{encode_pair(new_parent, val)}&"
end
buffer.chop
end
def encode_array(parent, value)
return "#{parent}%5B%5D" if value.empty?
buffer = +''
value.each_with_index do |val, index|
new_parent = if @array_indices
"#{parent}%5B#{index}%5D"
else
"#{parent}%5B%5D"
end
buffer << "#{encode_pair(new_parent, val)}&"
end
buffer.chop
end
end
# Sub-module for decoding query-string into parameters.
module DecodeMethods
# @param query [nil, String]
#
# @return [Array<Array, String>] the decoded params
#
# @raise [TypeError] if the nesting is incorrect
def decode(query)
return nil if query.nil?
params = {}
query.split('&').each do |pair|
next if pair.empty?
key, value = pair.split('=', 2)
key = unescape(key)
value = unescape(value.tr('+', ' ')) if value
decode_pair(key, value, params)
end
dehash(params, 0)
end
protected
SUBKEYS_REGEX = /[^\[\]]+(?:\]?\[\])?/
def decode_pair(key, value, context)
subkeys = key.scan(SUBKEYS_REGEX)
subkeys.each_with_index do |subkey, i|
is_array = subkey =~ /[\[\]]+\Z/
subkey = Regexp.last_match.pre_match if is_array
last_subkey = i == subkeys.length - 1
context = prepare_context(context, subkey, is_array, last_subkey)
add_to_context(is_array, context, value, subkey) if last_subkey
end
end
def prepare_context(context, subkey, is_array, last_subkey)
if !last_subkey || is_array
context = new_context(subkey, is_array, context)
end
if context.is_a?(Array) && !is_array
context = match_context(context, subkey)
end
context
end
def new_context(subkey, is_array, context)
value_type = is_array ? Array : Hash
if context[subkey] && !context[subkey].is_a?(value_type)
raise TypeError, "expected #{value_type.name} " \
"(got #{context[subkey].class.name}) for param `#{subkey}'"
end
context[subkey] ||= value_type.new
end
def match_context(context, subkey)
context << {} if !context.last.is_a?(Hash) || context.last.key?(subkey)
context.last
end
def add_to_context(is_array, context, value, subkey)
is_array ? context << value : context[subkey] = value
end
# Internal: convert a nested hash with purely numeric keys into an array.
# FIXME: this is not compatible with Rack::Utils.parse_nested_query
# @!visibility private
def dehash(hash, depth)
hash.each do |key, value|
hash[key] = dehash(value, depth + 1) if value.is_a?(Hash)
end
if depth.positive? && !hash.empty? && hash.keys.all? { |k| k =~ /^\d+$/ }
hash.sort.map(&:last)
else
hash
end
end
end
# This is the default encoder for Faraday requests.
# Using this encoder, parameters will be encoded respecting their structure,
# so you can send objects such as Arrays or Hashes as parameters
# for your requests.
module NestedParamsEncoder
class << self
attr_accessor :sort_params, :array_indices
extend Forwardable
def_delegators :'Faraday::Utils', :escape, :unescape
end
# Useful default for OAuth and caching.
@sort_params = true
@array_indices = false
extend EncodeMethods
extend DecodeMethods
end
end

View File

@ -1,22 +1,15 @@
module Faraday
class Error < StandardError; end
# frozen_string_literal: true
class ClientError < Error
# Faraday namespace.
module Faraday
# Faraday error base class.
class Error < StandardError
attr_reader :response, :wrapped_exception
def initialize(ex, response = nil)
@wrapped_exception = nil
@response = response
if ex.respond_to?(:backtrace)
super(ex.message)
@wrapped_exception = ex
elsif ex.respond_to?(:each_key)
super("the server responded with status #{ex[:status]}")
@response = ex
else
super(ex.to_s)
end
def initialize(exc = nil, response = nil)
@wrapped_exception = nil unless defined?(@wrapped_exception)
@response = nil unless defined?(@response)
super(exc_msg_and_response!(exc, response))
end
def backtrace
@ -28,39 +21,179 @@ module Faraday
end
def inspect
inner = ''
if @wrapped_exception
inner << " wrapped=#{@wrapped_exception.inspect}"
end
if @response
inner << " response=#{@response.inspect}"
end
if inner.empty?
inner << " #{super}"
end
inner = +''
inner << " wrapped=#{@wrapped_exception.inspect}" if @wrapped_exception
inner << " response=#{@response.inspect}" if @response
inner << " #{super}" if inner.empty?
%(#<#{self.class}#{inner}>)
end
end
class ConnectionFailed < ClientError; end
class ResourceNotFound < ClientError; end
class ParsingError < ClientError; end
def response_status
return unless @response
class TimeoutError < ClientError
def initialize(ex = nil)
super(ex || "timeout")
@response.is_a?(Faraday::Response) ? @response.status : @response[:status]
end
def response_headers
return unless @response
@response.is_a?(Faraday::Response) ? @response.headers : @response[:headers]
end
def response_body
return unless @response
@response.is_a?(Faraday::Response) ? @response.body : @response[:body]
end
protected
# Pulls out potential parent exception and response hash, storing them in
# instance variables.
# exc - Either an Exception, a string message, or a response hash.
# response - Hash
# :status - Optional integer HTTP response status
# :headers - String key/value hash of HTTP response header
# values.
# :body - Optional string HTTP response body.
# :request - Hash
# :method - Symbol with the request HTTP method.
# :url - URI object with the url requested.
# :url_path - String with the url path requested.
# :params - String key/value hash of query params
# present in the request.
# :headers - String key/value hash of HTTP request
# header values.
# :body - String HTTP request body.
#
# If a subclass has to call this, then it should pass a string message
# to `super`. See NilStatusError.
def exc_msg_and_response!(exc, response = nil)
if @response.nil? && @wrapped_exception.nil?
@wrapped_exception, msg, @response = exc_msg_and_response(exc, response)
return msg
end
exc.to_s
end
# Pulls out potential parent exception and response hash.
def exc_msg_and_response(exc, response = nil)
case exc
when Exception
[exc, exc.message, response]
when Hash
[nil, build_error_message_from_hash(exc), exc]
when Faraday::Env
[nil, build_error_message_from_env(exc), exc]
else
[nil, exc.to_s, response]
end
end
private
def build_error_message_from_hash(hash)
# Be defensive with external Hash objects - they might be missing keys
status = hash.fetch(:status, nil)
request = hash.fetch(:request, nil)
return fallback_error_message(status) if request.nil?
method = request.fetch(:method, nil)
url = request.fetch(:url, nil)
build_status_error_message(status, method, url)
end
def build_error_message_from_env(env)
# Faraday::Env is internal - we can make reasonable assumptions about its structure
build_status_error_message(env.status, env.method, env.url)
end
def build_status_error_message(status, method, url)
method_str = method ? method.to_s.upcase : ''
url_str = url ? url.to_s : ''
"the server responded with status #{status} for #{method_str} #{url_str}"
end
def fallback_error_message(status)
"the server responded with status #{status} - method and url are not available " \
'due to include_request: false on Faraday::Response::RaiseError middleware'
end
end
class SSLError < ClientError
# Faraday client error class. Represents 4xx status responses.
class ClientError < Error
end
class RetriableResponse < ClientError; end
[:ClientError, :ConnectionFailed, :ResourceNotFound,
:ParsingError, :TimeoutError, :SSLError, :RetriableResponse].each do |const|
Error.const_set(const, Faraday.const_get(const))
# Raised by Faraday::Response::RaiseError in case of a 400 response.
class BadRequestError < ClientError
end
# Raised by Faraday::Response::RaiseError in case of a 401 response.
class UnauthorizedError < ClientError
end
# Raised by Faraday::Response::RaiseError in case of a 403 response.
class ForbiddenError < ClientError
end
# Raised by Faraday::Response::RaiseError in case of a 404 response.
class ResourceNotFound < ClientError
end
# Raised by Faraday::Response::RaiseError in case of a 407 response.
class ProxyAuthError < ClientError
end
# Raised by Faraday::Response::RaiseError in case of a 408 response.
class RequestTimeoutError < ClientError
end
# Raised by Faraday::Response::RaiseError in case of a 409 response.
class ConflictError < ClientError
end
# Raised by Faraday::Response::RaiseError in case of a 422 response.
class UnprocessableEntityError < ClientError
end
# Raised by Faraday::Response::RaiseError in case of a 429 response.
class TooManyRequestsError < ClientError
end
# Faraday server error class. Represents 5xx status responses.
class ServerError < Error
end
# A unified client error for timeouts.
class TimeoutError < ServerError
def initialize(exc = 'timeout', response = nil)
super(exc, response)
end
end
# Raised by Faraday::Response::RaiseError in case of a nil status in response.
class NilStatusError < ServerError
def initialize(exc, response = nil)
exc_msg_and_response!(exc, response)
super('http status could not be derived from the server response')
end
end
# A unified error for failed connections.
class ConnectionFailed < Error
end
# A unified client error for SSL errors.
class SSLError < Error
end
# Raised by middlewares that parse the response, like the JSON response middleware.
class ParsingError < Error
end
# Raised by Faraday::Middleware and subclasses when invalid default_options are used
class InitializationError < Error
end
end

View File

@ -0,0 +1,118 @@
# frozen_string_literal: true
require 'pp' # This require is necessary for Hash#pretty_inspect to work, do not remove it, people rely on it.
module Faraday
module Logging
# Serves as an integration point to customize logging
class Formatter
extend Forwardable
DEFAULT_OPTIONS = { headers: true, bodies: false, errors: false,
log_level: :info }.freeze
def initialize(logger:, options:)
@logger = logger
@options = DEFAULT_OPTIONS.merge(options)
unless %i[debug info warn error fatal].include?(@options[:log_level])
@options[:log_level] = :info
end
@filter = []
end
def_delegators :@logger, :debug, :info, :warn, :error, :fatal
def request(env)
public_send(log_level) do
"request: #{env.method.upcase} #{apply_filters(env.url.to_s)}"
end
log_headers('request', env.request_headers) if log_headers?(:request)
log_body('request', env[:body]) if env[:body] && log_body?(:request)
end
def response(env)
public_send(log_level) { "response: Status #{env.status}" }
log_headers('response', env.response_headers) if log_headers?(:response)
log_body('response', env[:body]) if env[:body] && log_body?(:response)
end
def exception(exc)
return unless log_errors?
public_send(log_level) { "error: #{exc.full_message}" }
log_headers('error', exc.response_headers) if exc.respond_to?(:response_headers) && log_headers?(:error)
return unless exc.respond_to?(:response_body) && exc.response_body && log_body?(:error)
log_body('error', exc.response_body)
end
def filter(filter_word, filter_replacement)
@filter.push([filter_word, filter_replacement])
end
private
def dump_headers(headers)
return if headers.nil?
headers.map { |k, v| "#{k}: #{v.inspect}" }.join("\n")
end
def dump_body(body)
if body.respond_to?(:to_str)
body.to_str
else
pretty_inspect(body)
end
end
def pretty_inspect(body)
body.pretty_inspect
end
def log_headers?(type)
case @options[:headers]
when Hash
@options[:headers][type]
else
@options[:headers]
end
end
def log_body?(type)
case @options[:bodies]
when Hash
@options[:bodies][type]
else
@options[:bodies]
end
end
def log_errors?
@options[:errors]
end
def apply_filters(output)
@filter.each do |pattern, replacement|
output = output.to_s.gsub(pattern, replacement)
end
output
end
def log_level
@options[:log_level]
end
def log_headers(type, headers)
public_send(log_level) { "#{type}: #{apply_filters(dump_headers(headers))}" }
end
def log_body(type, body)
public_send(log_level) { "#{type}: #{apply_filters(dump_body(body))}" }
end
end
end
end

6
lib/faraday/methods.rb Normal file
View File

@ -0,0 +1,6 @@
# frozen_string_literal: true
module Faraday
METHODS_WITH_QUERY = %w[get head delete trace].freeze
METHODS_WITH_BODY = %w[post put patch].freeze
end

View File

@ -1,37 +1,72 @@
# frozen_string_literal: true
require 'monitor'
module Faraday
# Middleware is the basic base class of any Faraday middleware.
class Middleware
extend MiddlewareRegistry
class << self
attr_accessor :load_error
private :load_error=
end
attr_reader :app, :options
self.load_error = nil
DEFAULT_OPTIONS = {}.freeze
LOCK = Mutex.new
# Executes a block which should try to require and reference dependent libraries
def self.dependency(lib = nil)
lib ? require(lib) : yield
rescue LoadError, NameError => error
self.load_error = error
end
def self.new(*)
raise "missing dependency for #{self}: #{load_error.message}" unless loaded?
super
end
def self.loaded?
load_error.nil?
end
def self.inherited(subclass)
super
subclass.send(:load_error=, self.load_error)
end
def initialize(app = nil)
def initialize(app = nil, options = {})
@app = app
@options = self.class.default_options.merge(options)
end
class << self
# Faraday::Middleware::default_options= allows user to set default options at the Faraday::Middleware
# class level.
#
# @example Set the Faraday::Response::RaiseError option, `include_request` to `false`
# my_app/config/initializers/my_faraday_middleware.rb
#
# Faraday::Response::RaiseError.default_options = { include_request: false }
#
def default_options=(options = {})
validate_default_options(options)
LOCK.synchronize do
@default_options = default_options.merge(options)
end
end
# default_options attr_reader that initializes class instance variable
# with the values of any Faraday::Middleware defaults, and merges with
# subclass defaults
def default_options
@default_options ||= DEFAULT_OPTIONS.merge(self::DEFAULT_OPTIONS)
end
private
def validate_default_options(options)
invalid_keys = options.keys.reject { |opt| self::DEFAULT_OPTIONS.key?(opt) }
return unless invalid_keys.any?
raise(Faraday::InitializationError,
"Invalid options provided. Keys not found in #{self}::DEFAULT_OPTIONS: #{invalid_keys.join(', ')}")
end
end
def call(env)
on_request(env) if respond_to?(:on_request)
app.call(env).on_complete do |environment|
on_complete(environment) if respond_to?(:on_complete)
end
rescue StandardError => e
on_error(e) if respond_to?(:on_error)
raise
end
def close
if app.respond_to?(:close)
app.close
else
warn "#{app} does not implement \#close!"
end
end
end
end

View File

@ -0,0 +1,83 @@
# frozen_string_literal: true
require 'monitor'
module Faraday
# Adds the ability for other modules to register and lookup
# middleware classes.
module MiddlewareRegistry
def registered_middleware
@registered_middleware ||= {}
end
# Register middleware class(es) on the current module.
#
# @param mappings [Hash] Middleware mappings from a lookup symbol to a middleware class.
# @return [void]
#
# @example Lookup by a constant
#
# module Faraday
# class Whatever < Middleware
# # Middleware looked up by :foo returns Faraday::Whatever::Foo.
# register_middleware(foo: Whatever)
# end
# end
def register_middleware(**mappings)
middleware_mutex do
registered_middleware.update(mappings)
end
end
# Unregister a previously registered middleware class.
#
# @param key [Symbol] key for the registered middleware.
def unregister_middleware(key)
registered_middleware.delete(key)
end
# Lookup middleware class with a registered Symbol shortcut.
#
# @param key [Symbol] key for the registered middleware.
# @return [Class] a middleware Class.
# @raise [Faraday::Error] if given key is not registered
#
# @example
#
# module Faraday
# class Whatever < Middleware
# register_middleware(foo: Whatever)
# end
# end
#
# Faraday::Middleware.lookup_middleware(:foo)
# # => Faraday::Whatever
def lookup_middleware(key)
load_middleware(key) ||
raise(Faraday::Error, "#{key.inspect} is not registered on #{self}")
end
private
def middleware_mutex(&block)
@middleware_mutex ||= Monitor.new
@middleware_mutex.synchronize(&block)
end
def load_middleware(key)
value = registered_middleware[key]
case value
when Module
value
when Symbol, String
middleware_mutex do
@registered_middleware[key] = const_get(value)
end
when Proc
middleware_mutex do
@registered_middleware[key] = value.call
end
end
end
end
end

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
module Faraday
# Subclasses Struct with some special helpers for converting from a Hash to
# a Struct.
@ -10,6 +12,7 @@ module Faraday
# Public
def each
return to_enum(:each) unless block_given?
members.each do |key|
yield(key.to_sym, send(key))
end
@ -27,7 +30,7 @@ module Faraday
new_value = value
end
self.send("#{key}=", new_value) unless new_value.nil?
send(:"#{key}=", new_value) unless new_value.nil?
end
self
end
@ -35,7 +38,7 @@ module Faraday
# Public
def delete(key)
value = send(key)
send("#{key}=", nil)
send(:"#{key}=", nil)
value
end
@ -47,10 +50,14 @@ module Faraday
# Public
def merge!(other)
other.each do |key, other_value|
self_value = self.send(key)
self_value = send(key)
sub_options = self.class.options_for(key)
new_value = (self_value && sub_options && other_value) ? self_value.merge(other_value) : other_value
self.send("#{key}=", new_value) unless new_value.nil?
new_value = if self_value && sub_options && other_value
self_value.merge(other_value)
else
other_value
end
send(:"#{key}=", new_value) unless new_value.nil?
end
self
end
@ -69,10 +76,10 @@ module Faraday
def fetch(key, *args)
unless symbolized_key_set.include?(key.to_sym)
key_setter = "#{key}="
if args.size > 0
if !args.empty?
send(key_setter, args.first)
elsif block_given?
send(key_setter, Proc.new.call(key))
send(key_setter, yield(key))
else
raise self.class.fetch_error_class, "key not found: #{key.inspect}"
end
@ -96,11 +103,10 @@ module Faraday
end
# Public
def each_key
return to_enum(:each_key) unless block_given?
keys.each do |key|
yield(key)
end
def each_key(&block)
return to_enum(:each_key) unless block
keys.each(&block)
end
# Public
@ -111,11 +117,10 @@ module Faraday
alias has_key? key?
# Public
def each_value
return to_enum(:each_value) unless block_given?
values.each do |value|
yield(value)
end
def each_value(&block)
return to_enum(:each_value) unless block
values.each(&block)
end
# Public
@ -142,9 +147,9 @@ module Faraday
value = send(member)
values << "#{member}=#{value.inspect}" if value
end
values = values.empty? ? ' (empty)' : (' ' << values.join(", "))
values = values.empty? ? '(empty)' : values.join(', ')
%(#<#{self.class}#{values}>)
%(#<#{self.class} #{values}>)
end
# Internal
@ -162,9 +167,14 @@ module Faraday
@attribute_options ||= {}
end
def self.memoized(key)
memoized_attributes[key.to_sym] = Proc.new
def self.memoized(key, &block)
unless block
raise ArgumentError, '#memoized must be called with a block'
end
memoized_attributes[key.to_sym] = block
class_eval <<-RUBY, __FILE__, __LINE__ + 1
remove_method(key) if method_defined?(key, false)
def #{key}() self[:#{key}]; end
RUBY
end
@ -175,7 +185,7 @@ module Faraday
def [](key)
key = key.to_sym
if method = self.class.memoized_attributes[key]
if (method = self.class.memoized_attributes[key])
super(key) || (self[key] = instance_eval(&method))
else
super
@ -183,7 +193,7 @@ module Faraday
end
def symbolized_key_set
@symbolized_key_set ||= Set.new(keys.map { |k| k.to_sym })
@symbolized_key_set ||= Set.new(keys.map(&:to_sym))
end
def self.inherited(subclass)
@ -194,180 +204,16 @@ module Faraday
def self.fetch_error_class
@fetch_error_class ||= if Object.const_defined?(:KeyError)
::KeyError
else
::IndexError
end
end
end
class RequestOptions < Options.new(:params_encoder, :proxy, :bind,
:timeout, :open_timeout, :write_timeout, :boundary, :oauth, :context)
def []=(key, value)
if key && key.to_sym == :proxy
super(key, value ? ProxyOptions.from(value) : nil)
else
super(key, value)
end
end
end
class SSLOptions < Options.new(:verify, :ca_file, :ca_path, :verify_mode,
:cert_store, :client_cert, :client_key, :certificate, :private_key, :verify_depth,
:version, :min_version, :max_version)
def verify?
verify != false
end
def disable?
!verify?
end
end
class ProxyOptions < Options.new(:uri, :user, :password)
extend Forwardable
def_delegators :uri, :scheme, :scheme=, :host, :host=, :port, :port=, :path, :path=
def self.from(value)
case value
when String
value = {:uri => Utils.URI(value)}
when URI
value = {:uri => value}
when Hash, Options
if uri = value.delete(:uri)
value[:uri] = Utils.URI(uri)
end
end
super(value)
end
memoized(:user) { uri && uri.user && Utils.unescape(uri.user) }
memoized(:password) { uri && uri.password && Utils.unescape(uri.password) }
end
class ConnectionOptions < Options.new(:request, :proxy, :ssl, :builder, :url,
:parallel_manager, :params, :headers, :builder_class)
options :request => RequestOptions, :ssl => SSLOptions
memoized(:request) { self.class.options_for(:request).new }
memoized(:ssl) { self.class.options_for(:ssl).new }
memoized(:builder_class) { RackBuilder }
def new_builder(block)
builder_class.new(&block)
end
end
class Env < Options.new(:method, :body, :url, :request, :request_headers,
:ssl, :parallel_manager, :params, :response, :response_headers, :status,
:reason_phrase)
ContentLength = 'Content-Length'.freeze
StatusesWithoutBody = Set.new [204, 304]
SuccessfulStatuses = 200..299
# A Set of HTTP verbs that typically send a body. If no body is set for
# these requests, the Content-Length header is set to 0.
MethodsWithBodies = Set.new [:post, :put, :patch, :options]
options :request => RequestOptions,
:request_headers => Utils::Headers, :response_headers => Utils::Headers
extend Forwardable
def_delegators :request, :params_encoder
# Public
def self.from(value)
env = super(value)
if value.respond_to?(:custom_members)
env.custom_members.update(value.custom_members)
end
env
end
# Public
def [](key)
if in_member_set?(key)
super(key)
else
custom_members[key]
end
end
# Public
def []=(key, value)
if in_member_set?(key)
super(key, value)
else
custom_members[key] = value
end
end
# Public
def success?
SuccessfulStatuses.include?(status)
end
# Public
def needs_body?
!body && MethodsWithBodies.include?(method)
end
# Public
def clear_body
request_headers[ContentLength] = '0'
self.body = ''
end
# Public
def parse_body?
!StatusesWithoutBody.include?(status)
end
# Public
def parallel?
!!parallel_manager
end
def inspect
attrs = [nil]
members.each do |mem|
if value = send(mem)
attrs << "@#{mem}=#{value.inspect}"
end
end
if !custom_members.empty?
attrs << "@custom=#{custom_members.inspect}"
end
%(#<#{self.class}#{attrs.join(" ")}>)
end
# Internal
def custom_members
@custom_members ||= {}
end
# Internal
if members.first.is_a?(Symbol)
def in_member_set?(key)
self.class.member_set.include?(key.to_sym)
end
else
def in_member_set?(key)
self.class.member_set.include?(key.to_s)
end
end
# Internal
def self.member_set
@member_set ||= Set.new(members)
::KeyError
else
::IndexError
end
end
end
end
require 'faraday/options/request_options'
require 'faraday/options/ssl_options'
require 'faraday/options/proxy_options'
require 'faraday/options/connection_options'
require 'faraday/options/env'

View File

@ -0,0 +1,23 @@
# frozen_string_literal: true
module Faraday
# @!parse
# # ConnectionOptions contains the configurable properties for a Faraday
# # connection object.
# class ConnectionOptions < Options; end
ConnectionOptions = Options.new(:request, :proxy, :ssl, :builder, :url,
:parallel_manager, :params, :headers,
:builder_class) do
options request: RequestOptions, ssl: SSLOptions
memoized(:request) { self.class.options_for(:request).new }
memoized(:ssl) { self.class.options_for(:ssl).new }
memoized(:builder_class) { RackBuilder }
def new_builder(block)
builder_class.new(&block)
end
end
end

204
lib/faraday/options/env.rb Normal file
View File

@ -0,0 +1,204 @@
# frozen_string_literal: true
module Faraday
# @!parse
# # @!attribute method
# # @return [Symbol] HTTP method (`:get`, `:post`)
# #
# # @!attribute body
# # @return [String] The request body that will eventually be converted to a
# # string.
# #
# # @!attribute url
# # @return [URI] URI instance for the current request.
# #
# # @!attribute request
# # @return [Hash] options for configuring the request.
# # Options for configuring the request.
# #
# # - `:timeout` - time limit for the entire request (Integer in
# # seconds)
# # - `:open_timeout` - time limit for just the connection phase (e.g.
# # handshake) (Integer in seconds)
# # - `:read_timeout` - time limit for the first response byte received from
# # the server (Integer in seconds)
# # - `:write_timeout` - time limit for the client to send the request to the
# # server (Integer in seconds)
# # - `:on_data` - Proc for streaming
# # - `:proxy` - Hash of proxy options
# # - `:uri` - Proxy server URI
# # - `:user` - Proxy server username
# # - `:password` - Proxy server password
# #
# # @!attribute request_headers
# # @return [Hash] HTTP Headers to be sent to the server.
# #
# # @!attribute ssl
# # @return [Hash] options for configuring SSL requests
# #
# # @!attribute parallel_manager
# # @return [Object] sent if the connection is in parallel mode
# #
# # @!attribute params
# # @return [Hash]
# #
# # @!attribute response
# # @return [Response]
# #
# # @!attribute response_headers
# # @return [Hash] HTTP headers from the server
# #
# # @!attribute status
# # @return [Integer] HTTP response status code
# #
# # @!attribute reason_phrase
# # @return [String]
# class Env < Options; end
Env = Options.new(:method, :request_body, :url, :request,
:request_headers, :ssl, :parallel_manager, :params,
:response, :response_headers, :status,
:reason_phrase, :response_body) do
const_set(:ContentLength, 'Content-Length')
const_set(:StatusesWithoutBody, Set.new([204, 304]))
const_set(:SuccessfulStatuses, 200..299)
# A Set of HTTP verbs that typically send a body. If no body is set for
# these requests, the Content-Length header is set to 0.
const_set(:MethodsWithBodies, Set.new(Faraday::METHODS_WITH_BODY.map(&:to_sym)))
options request: RequestOptions,
request_headers: Utils::Headers, response_headers: Utils::Headers
extend Forwardable
def_delegators :request, :params_encoder
# Build a new Env from given value. Respects and updates `custom_members`.
#
# @param value [Object] a value fitting Option.from(v).
# @return [Env] from given value
def self.from(value)
env = super(value)
if value.respond_to?(:custom_members)
env.custom_members.update(value.custom_members)
end
env
end
# @param key [Object]
def [](key)
return self[current_body] if key == :body
if in_member_set?(key)
super(key)
else
custom_members[key]
end
end
# @param key [Object]
# @param value [Object]
def []=(key, value)
if key == :body
super(current_body, value)
return
end
if in_member_set?(key)
super(key, value)
else
custom_members[key] = value
end
end
def current_body
!!status ? :response_body : :request_body
end
def body
self[:body]
end
def body=(value)
self[:body] = value
end
# @return [Boolean] true if status is in the set of {SuccessfulStatuses}.
def success?
Env::SuccessfulStatuses.include?(status)
end
# @return [Boolean] true if there's no body yet, and the method is in the
# set of {Env::MethodsWithBodies}.
def needs_body?
!body && Env::MethodsWithBodies.include?(method)
end
# Sets content length to zero and the body to the empty string.
def clear_body
request_headers[Env::ContentLength] = '0'
self.body = +''
end
# @return [Boolean] true if the status isn't in the set of
# {Env::StatusesWithoutBody}.
def parse_body?
!Env::StatusesWithoutBody.include?(status)
end
# @return [Boolean] true if there is a parallel_manager
def parallel?
!!parallel_manager
end
def inspect
attrs = [nil]
members.each do |mem|
if (value = send(mem))
attrs << "@#{mem}=#{value.inspect}"
end
end
attrs << "@custom=#{custom_members.inspect}" unless custom_members.empty?
%(#<#{self.class}#{attrs.join(' ')}>)
end
def stream_response?
request.stream_response?
end
def stream_response(&block)
size = 0
yielded = false
block_result = block.call do |chunk|
if chunk.bytesize.positive? || size.positive?
yielded = true
size += chunk.bytesize
request.on_data.call(chunk, size, self)
end
end
request.on_data.call(+'', 0, self) unless yielded
block_result
end
# @private
def custom_members
@custom_members ||= {}
end
# @private
if members.first.is_a?(Symbol)
def in_member_set?(key)
self.class.member_set.include?(key.to_sym)
end
else
def in_member_set?(key)
self.class.member_set.include?(key.to_s)
end
end
# @private
def self.member_set
@member_set ||= Set.new(members)
end
end
end

View File

@ -0,0 +1,38 @@
# frozen_string_literal: true
module Faraday
# @!parse
# # ProxyOptions contains the configurable properties for the proxy
# # configuration used when making an HTTP request.
# class ProxyOptions < Options; end
ProxyOptions = Options.new(:uri, :user, :password) do
extend Forwardable
def_delegators :uri, :scheme, :scheme=, :host, :host=, :port, :port=,
:path, :path=
def self.from(value)
case value
when ''
value = nil
when String
# URIs without a scheme should default to http (like 'example:123').
# This fixes #1282 and prevents a silent failure in some adapters.
value = "http://#{value}" unless value.include?('://')
value = { uri: Utils.URI(value) }
when URI
value = { uri: value }
when Hash, Options
if value[:uri]
value = value.dup.tap do |duped|
duped[:uri] = Utils.URI(duped[:uri])
end
end
end
super(value)
end
memoized(:user) { uri&.user && Utils.unescape(uri.user) }
memoized(:password) { uri&.password && Utils.unescape(uri.password) }
end
end

View File

@ -0,0 +1,23 @@
# frozen_string_literal: true
module Faraday
# @!parse
# # RequestOptions contains the configurable properties for a Faraday request.
# class RequestOptions < Options; end
RequestOptions = Options.new(:params_encoder, :proxy, :bind,
:timeout, :open_timeout, :read_timeout,
:write_timeout, :boundary, :oauth,
:context, :on_data) do
def []=(key, value)
if key && key.to_sym == :proxy
super(key, value ? ProxyOptions.from(value) : nil)
else
super(key, value)
end
end
def stream_response?
on_data.is_a?(Proc)
end
end
end

View File

@ -0,0 +1,76 @@
# frozen_string_literal: true
module Faraday
# @!parse
# # SSL-related options.
# #
# # @!attribute verify
# # @return [Boolean] whether to verify SSL certificates or not
# #
# # @!attribute verify_hostname
# # @return [Boolean] whether to enable hostname verification on server certificates
# # during the handshake or not (see https://github.com/ruby/openssl/pull/60)
# #
# # @!attribute hostname
# # @return [String] Server hostname used for SNI (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLSocket.html#method-i-hostname-3D)
# #
# # @!attribute ca_file
# # @return [String] CA file
# #
# # @!attribute ca_path
# # @return [String] CA path
# #
# # @!attribute verify_mode
# # @return [Integer] Any `OpenSSL::SSL::` constant (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL.html)
# #
# # @!attribute cert_store
# # @return [OpenSSL::X509::Store] certificate store
# #
# # @!attribute client_cert
# # @return [String, OpenSSL::X509::Certificate] client certificate
# #
# # @!attribute client_key
# # @return [String, OpenSSL::PKey::RSA, OpenSSL::PKey::DSA] client key
# #
# # @!attribute certificate
# # @return [OpenSSL::X509::Certificate] certificate (Excon only)
# #
# # @!attribute private_key
# # @return [OpenSSL::PKey::RSA, OpenSSL::PKey::DSA] private key (Excon only)
# #
# # @!attribute verify_depth
# # @return [Integer] maximum depth for the certificate chain verification
# #
# # @!attribute version
# # @return [String, Symbol] SSL version (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-ssl_version-3D)
# #
# # @!attribute min_version
# # @return [String, Symbol] minimum SSL version (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-min_version-3D)
# #
# # @!attribute max_version
# # @return [String, Symbol] maximum SSL version (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-max_version-3D)
# #
# # @!attribute ciphers
# # @return [String] cipher list in OpenSSL format (see https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-ciphers-3D)
# class SSLOptions < Options; end
SSLOptions = Options.new(:verify, :verify_hostname, :hostname,
:ca_file, :ca_path, :verify_mode,
:cert_store, :client_cert, :client_key,
:certificate, :private_key, :verify_depth,
:version, :min_version, :max_version, :ciphers) do
# @return [Boolean] true if should verify
def verify?
verify != false
end
# @return [Boolean] true if should not verify
def disable?
!verify?
end
# @return [Boolean] true if should verify_hostname
def verify_hostname?
verify_hostname != false
end
end
end

View File

@ -1,198 +1,5 @@
require "forwardable"
# frozen_string_literal: true
module Faraday
module NestedParamsEncoder
class << self
extend Forwardable
def_delegators :'Faraday::Utils', :escape, :unescape
end
def self.encode(params)
return nil if params == nil
if !params.is_a?(Array)
if !params.respond_to?(:to_hash)
raise TypeError,
"Can't convert #{params.class} into Hash."
end
params = params.to_hash
params = params.map do |key, value|
key = key.to_s if key.kind_of?(Symbol)
[key, value]
end
# Useful default for OAuth and caching.
# Only to be used for non-Array inputs. Arrays should preserve order.
params.sort!
end
# Helper lambda
to_query = lambda do |parent, value|
if value.is_a?(Hash)
value = value.map do |key, val|
key = escape(key)
[key, val]
end
value.sort!
buffer = ""
value.each do |key, val|
new_parent = "#{parent}%5B#{key}%5D"
buffer << "#{to_query.call(new_parent, val)}&"
end
return buffer.chop
elsif value.is_a?(Array)
new_parent = "#{parent}%5B%5D"
return new_parent if value.empty?
buffer = ""
value.each_with_index do |val, i|
buffer << "#{to_query.call(new_parent, val)}&"
end
return buffer.chop
elsif value.nil?
return parent
else
encoded_value = escape(value)
return "#{parent}=#{encoded_value}"
end
end
# The params have form [['key1', 'value1'], ['key2', 'value2']].
buffer = ''
params.each do |parent, value|
encoded_parent = escape(parent)
buffer << "#{to_query.call(encoded_parent, value)}&"
end
return buffer.chop
end
def self.decode(query)
return nil if query == nil
params = {}
query.split("&").each do |pair|
next if pair.empty?
key, value = pair.split("=", 2)
key = unescape(key)
value = unescape(value.gsub(/\+/, ' ')) if value
subkeys = key.scan(/[^\[\]]+(?:\]?\[\])?/)
context = params
subkeys.each_with_index do |subkey, i|
is_array = subkey =~ /[\[\]]+\Z/
subkey = $` if is_array
last_subkey = i == subkeys.length - 1
if !last_subkey || is_array
value_type = is_array ? Array : Hash
if context[subkey] && !context[subkey].is_a?(value_type)
raise TypeError, "expected %s (got %s) for param `%s'" % [
value_type.name,
context[subkey].class.name,
subkey
]
end
context = (context[subkey] ||= value_type.new)
end
if context.is_a?(Array) && !is_array
if !context.last.is_a?(Hash) || context.last.has_key?(subkey)
context << {}
end
context = context.last
end
if last_subkey
if is_array
context << value
else
context[subkey] = value
end
end
end
end
dehash(params, 0)
end
# Internal: convert a nested hash with purely numeric keys into an array.
# FIXME: this is not compatible with Rack::Utils.parse_nested_query
def self.dehash(hash, depth)
hash.each do |key, value|
hash[key] = dehash(value, depth + 1) if value.kind_of?(Hash)
end
if depth > 0 && !hash.empty? && hash.keys.all? { |k| k =~ /^\d+$/ }
hash.keys.sort.inject([]) { |all, key| all << hash[key] }
else
hash
end
end
end
module FlatParamsEncoder
class << self
extend Forwardable
def_delegators :'Faraday::Utils', :escape, :unescape
end
def self.encode(params)
return nil if params == nil
if !params.is_a?(Array)
if !params.respond_to?(:to_hash)
raise TypeError,
"Can't convert #{params.class} into Hash."
end
params = params.to_hash
params = params.map do |key, value|
key = key.to_s if key.kind_of?(Symbol)
[key, value]
end
# Useful default for OAuth and caching.
# Only to be used for non-Array inputs. Arrays should preserve order.
params.sort!
end
# The params have form [['key1', 'value1'], ['key2', 'value2']].
buffer = ''
params.each do |key, value|
encoded_key = escape(key)
value = value.to_s if value == true || value == false
if value == nil
buffer << "#{encoded_key}&"
elsif value.kind_of?(Array)
value.each do |sub_value|
encoded_value = escape(sub_value)
buffer << "#{encoded_key}=#{encoded_value}&"
end
else
encoded_value = escape(value)
buffer << "#{encoded_key}=#{encoded_value}&"
end
end
return buffer.chop
end
def self.decode(query)
empty_accumulator = {}
return nil if query == nil
split_query = (query.split('&').map do |pair|
pair.split('=', 2) if pair && !pair.empty?
end).compact
return split_query.inject(empty_accumulator.dup) do |accu, pair|
pair[0] = unescape(pair[0])
pair[1] = true if pair[1].nil?
if pair[1].respond_to?(:to_str)
pair[1] = unescape(pair[1].to_str.gsub(/\+/, " "))
end
if accu[pair[0]].kind_of?(Array)
accu[pair[0]] << pair[1]
elsif accu[pair[0]]
accu[pair[0]] = [accu[pair[0]], pair[1]]
else
accu[pair[0]] = pair[1]
end
accu
end
end
end
end
require 'forwardable'
require 'faraday/encoders/nested_params_encoder'
require 'faraday/encoders/flat_params_encoder'

View File

@ -1,12 +1,20 @@
# frozen_string_literal: true
require 'faraday/adapter_registry'
module Faraday
# A Builder that processes requests into responses by passing through an inner
# middleware stack (heavily inspired by Rack).
#
# Faraday::Connection.new(:url => 'http://sushi.com') do |builder|
# @example
# Faraday::Connection.new(url: 'http://httpbingo.org') do |builder|
# builder.request :url_encoded # Faraday::Request::UrlEncoded
# builder.adapter :net_http # Faraday::Adapter::NetHttp
# end
class RackBuilder
# Used to detect missing arguments
NO_ARGUMENT = Object.new
attr_accessor :handlers
# Error raised when trying to modify the stack after calling `lock!`
@ -15,28 +23,29 @@ module Faraday
# borrowed from ActiveSupport::Dependencies::Reference &
# ActionDispatch::MiddlewareStack::Middleware
class Handler
@@constants_mutex = Mutex.new
@@constants = Hash.new { |h, k|
value = k.respond_to?(:constantize) ? k.constantize : Object.const_get(k)
@@constants_mutex.synchronize { h[k] = value }
}
REGISTRY = Faraday::AdapterRegistry.new
attr_reader :name
def initialize(klass, *args, &block)
def initialize(klass, *args, **kwargs, &block)
@name = klass.to_s
if klass.respond_to?(:name)
@@constants_mutex.synchronize { @@constants[@name] = klass }
end
@args, @block = args, block
REGISTRY.set(klass) if klass.respond_to?(:name)
@args = args
@kwargs = kwargs
@block = block
end
def klass() @@constants[@name] end
def inspect() @name end
def klass
REGISTRY.get(@name)
end
def inspect
@name
end
def ==(other)
if other.is_a? Handler
self.name == other.name
name == other.name
elsif other.respond_to? :name
klass == other
else
@ -44,33 +53,34 @@ module Faraday
end
end
def build(app)
klass.new(app, *@args, &@block)
def build(app = nil)
klass.new(app, *@args, **@kwargs, &@block)
end
end
def initialize(handlers = [])
@handlers = handlers
if block_given?
build(&Proc.new)
elsif @handlers.empty?
# default stack, if nothing else is configured
self.request :url_encoded
self.adapter Faraday.default_adapter
end
def initialize(&block)
@adapter = nil
@handlers = []
build(&block)
end
def build(options = {})
def initialize_dup(original)
super
@adapter = original.adapter
@handlers = original.handlers.dup
end
def build
raise_if_locked
@handlers.clear unless options[:keep]
yield(self) if block_given?
block_given? ? yield(self) : request(:url_encoded)
adapter(Faraday.default_adapter, **Faraday.default_adapter_options) unless @adapter
end
def [](idx)
@handlers[idx]
end
# Locks the middleware stack to ensure no further modifications are possible.
# Locks the middleware stack to ensure no further modifications are made.
def lock!
@handlers.freeze
end
@ -79,50 +89,52 @@ module Faraday
@handlers.frozen?
end
def use(klass, *args, &block)
def use(klass, ...)
if klass.is_a? Symbol
use_symbol(Faraday::Middleware, klass, *args, &block)
use_symbol(Faraday::Middleware, klass, ...)
else
raise_if_locked
warn_middleware_after_adapter if adapter_set?
@handlers << self.class::Handler.new(klass, *args, &block)
raise_if_adapter(klass)
@handlers << self.class::Handler.new(klass, ...)
end
end
def request(key, *args, &block)
use_symbol(Faraday::Request, key, *args, &block)
def request(key, ...)
use_symbol(Faraday::Request, key, ...)
end
def response(key, *args, &block)
use_symbol(Faraday::Response, key, *args, &block)
def response(...)
use_symbol(Faraday::Response, ...)
end
def adapter(key, *args, &block)
use_symbol(Faraday::Adapter, key, *args, &block)
def adapter(klass = NO_ARGUMENT, *args, **kwargs, &block)
return @adapter if klass == NO_ARGUMENT || klass.nil?
klass = Faraday::Adapter.lookup_middleware(klass) if klass.is_a?(Symbol)
@adapter = self.class::Handler.new(klass, *args, **kwargs, &block)
end
## methods to push onto the various positions in the stack:
def insert(index, *args, &block)
def insert(index, ...)
raise_if_locked
index = assert_index(index)
warn_middleware_after_adapter if inserting_after_adapter?(index)
handler = self.class::Handler.new(*args, &block)
handler = self.class::Handler.new(...)
@handlers.insert(index, handler)
end
alias_method :insert_before, :insert
alias insert_before insert
def insert_after(index, *args, &block)
def insert_after(index, ...)
index = assert_index(index)
insert(index + 1, *args, &block)
insert(index + 1, ...)
end
def swap(index, *args, &block)
def swap(index, ...)
raise_if_locked
index = assert_index(index)
@handlers.delete_at(index)
insert(index, *args, &block)
insert(index, ...)
end
def delete(handler)
@ -133,13 +145,11 @@ module Faraday
# Processes a Request into a Response by passing it through this Builder's
# middleware stack.
#
# connection - Faraday::Connection
# request - Faraday::Request
# @param connection [Faraday::Connection]
# @param request [Faraday::Request]
#
# Returns a Faraday::Response.
# @return [Faraday::Response]
def build_response(connection, request)
warn 'WARNING: No adapter was configured for this request' unless adapter_set?
app.call(build_env(connection, request))
end
@ -153,30 +163,27 @@ module Faraday
def app
@app ||= begin
lock!
to_app(lambda { |env|
response = Response.new
env.response = response
response.finish(env) unless env.parallel?
response
})
ensure_adapter!
to_app
end
end
def to_app(inner_app)
def to_app
# last added handler is the deepest and thus closest to the inner app
@handlers.reverse.inject(inner_app) { |app, handler| handler.build(app) }
# adapter is always the last one
@handlers.reverse.inject(@adapter.build) do |app, handler|
handler.build(app)
end
end
def ==(other)
other.is_a?(self.class) && @handlers == other.handlers
end
def dup
self.class.new(@handlers.dup)
other.is_a?(self.class) &&
@handlers == other.handlers &&
@adapter == other.adapter
end
# ENV Keys
# :method - a symbolized request method (:get, :post)
# :http_method - a symbolized request HTTP method (:get, :post)
# :body - the request body that will eventually be converted to a string.
# :url - URI instance for the current request.
# :status - HTTP response status code
@ -192,45 +199,49 @@ module Faraday
# :password - Proxy server password
# :ssl - Hash of options for configuring SSL requests.
def build_env(connection, request)
Env.new(request.method, request.body,
connection.build_exclusive_url(request.path, request.params, request.options.params_encoder),
request.options, request.headers, connection.ssl,
connection.parallel_manager)
exclusive_url = connection.build_exclusive_url(
request.path, request.params,
request.options.params_encoder
)
Env.new(request.http_method, request.body, exclusive_url,
request.options, request.headers, connection.ssl,
connection.parallel_manager)
end
private
LOCK_ERR = "can't modify middleware stack after making a request"
MISSING_ADAPTER_ERROR = "An attempt to run a request with a Faraday::Connection without adapter has been made.\n" \
"Please set Faraday.default_adapter or provide one when initializing the connection.\n" \
'For more info, check https://lostisland.github.io/faraday/usage/.'
def raise_if_locked
raise StackLocked, "can't modify middleware stack after making a request" if locked?
raise StackLocked, LOCK_ERR if locked?
end
def warn_middleware_after_adapter
warn "WARNING: Unexpected middleware set after the adapter. " \
"This won't be supported from Faraday 1.0."
def raise_if_adapter(klass)
return unless klass <= Faraday::Adapter
raise 'Adapter should be set using the `adapter` method, not `use`'
end
def ensure_adapter!
raise MISSING_ADAPTER_ERROR unless @adapter
end
def adapter_set?
@handlers.any? { |handler| is_adapter?(handler) }
!@adapter.nil?
end
def inserting_after_adapter?(index)
adapter_index = @handlers.find_index { |handler| is_adapter?(handler) }
return false if adapter_index.nil?
index > adapter_index
end
def is_adapter?(handler)
handler.klass.ancestors.include? Faraday::Adapter
end
def use_symbol(mod, key, *args, &block)
use(mod.lookup_middleware(key), *args, &block)
def use_symbol(mod, key, ...)
use(mod.lookup_middleware(key), ...)
end
def assert_index(index)
idx = index.is_a?(Integer) ? index : @handlers.index(index)
raise "No such handler: #{index.inspect}" unless idx
idx
end
end

View File

@ -1,6 +1,9 @@
# frozen_string_literal: true
module Faraday
# Used to setup urls, params, headers, and the request body in a sane manner.
# Used to setup URLs, params, headers, and the request body in a sane manner.
#
# @example
# @connection.post do |req|
# req.url 'http://localhost', 'a' => '1' # 'http://localhost?a=1'
# req.headers['b'] = '2' # Header
@ -9,45 +12,68 @@ module Faraday
# req.body = 'abc'
# end
#
class Request < Struct.new(:method, :path, :params, :headers, :body, :options)
# @!attribute http_method
# @return [Symbol] the HTTP method of the Request
# @!attribute path
# @return [URI, String] the path
# @!attribute params
# @return [Hash] query parameters
# @!attribute headers
# @return [Faraday::Utils::Headers] headers
# @!attribute body
# @return [String] body
# @!attribute options
# @return [RequestOptions] options
Request = Struct.new(:http_method, :path, :params, :headers, :body, :options) do
extend MiddlewareRegistry
register_middleware File.expand_path('../request', __FILE__),
:url_encoded => [:UrlEncoded, 'url_encoded'],
:multipart => [:Multipart, 'multipart'],
:retry => [:Retry, 'retry'],
:authorization => [:Authorization, 'authorization'],
:basic_auth => [:BasicAuthentication, 'basic_authentication'],
:token_auth => [:TokenAuthentication, 'token_authentication'],
:instrumentation => [:Instrumentation, 'instrumentation']
alias_method :member_get, :[]
private :member_get
alias_method :member_set, :[]=
private :member_set
# @param request_method [String]
# @yield [request] for block customization, if block given
# @yieldparam request [Request]
# @return [Request]
def self.create(request_method)
new(request_method).tap do |request|
yield(request) if block_given?
end
end
# Public: Replace params, preserving the existing hash type
remove_method :params=
# Replace params, preserving the existing hash type.
#
# @param hash [Hash] new params
def params=(hash)
if params
params.replace hash
else
super
member_set(:params, hash)
end
end
# Public: Replace request headers, preserving the existing hash type
remove_method :headers=
# Replace request headers, preserving the existing hash type.
#
# @param hash [Hash] new headers
def headers=(hash)
if headers
headers.replace hash
else
super
member_set(:headers, hash)
end
end
# Update path and params.
#
# @param path [URI, String]
# @param params [Hash, nil]
# @return [void]
def url(path, params = nil)
if path.respond_to? :query
if query = path.query
if (query = path.query)
path = path.dup
path.query = nil
end
@ -61,54 +87,53 @@ module Faraday
self.params.update(params) if params
end
# @param key [Object] key to look up in headers
# @return [Object] value of the given header name
def [](key)
headers[key]
end
# @param key [Object] key of header to write
# @param value [Object] value of header
def []=(key, value)
headers[key] = value
end
# Marshal serialization support.
#
# @return [Hash] the hash ready to be serialized in Marshal.
def marshal_dump
{
:method => method,
:body => body,
:headers => headers,
:path => path,
:params => params,
:options => options
http_method: http_method,
body: body,
headers: headers,
path: path,
params: params,
options: options
}
end
# Marshal serialization support.
# Restores the instance variables according to the +serialised+.
# @param serialised [Hash] the serialised object.
def marshal_load(serialised)
self.method = serialised[:method]
self.body = serialised[:body]
self.http_method = serialised[:http_method]
self.body = serialised[:body]
self.headers = serialised[:headers]
self.path = serialised[:path]
self.params = serialised[:params]
self.path = serialised[:path]
self.params = serialised[:params]
self.options = serialised[:options]
end
# ENV Keys
# :method - a symbolized request method (:get, :post)
# :body - the request body that will eventually be converted to a string.
# :url - URI instance for the current request.
# :status - HTTP response status code
# :request_headers - hash of HTTP Headers to be sent to the server
# :response_headers - Hash of HTTP headers from the server
# :parallel_manager - sent if the connection is in parallel mode
# :request - Hash of options for configuring the request.
# :timeout - open/read timeout Integer in seconds
# :open_timeout - read timeout Integer in seconds
# :proxy - Hash of proxy options
# :uri - Proxy Server URI
# :user - Proxy server username
# :password - Proxy server password
# :ssl - Hash of options for configuring SSL requests.
# @return [Env] the Env for this Request
def to_env(connection)
Env.new(method, body, connection.build_exclusive_url(path, params),
options, headers, connection.ssl, connection.parallel_manager)
Env.new(http_method, body, connection.build_exclusive_url(path, params),
options, headers, connection.ssl, connection.parallel_manager)
end
end
end
require 'faraday/request/authorization'
require 'faraday/request/instrumentation'
require 'faraday/request/json'
require 'faraday/request/url_encoded'

View File

@ -1,41 +1,54 @@
# frozen_string_literal: true
module Faraday
class Request::Authorization < Faraday::Middleware
KEY = "Authorization".freeze unless defined? KEY
class Request
# Request middleware for the Authorization HTTP header
class Authorization < Faraday::Middleware
KEY = 'Authorization'
# Public
def self.header(type, token)
case token
when String, Symbol
"#{type} #{token}"
when Hash
build_hash(type.to_s, token)
else
raise ArgumentError, "Can't build an Authorization #{type} header from #{token.inspect}"
# @param app [#call]
# @param type [String, Symbol] Type of Authorization
# @param params [Array<String, Proc, #call>] parameters to build the Authorization header.
# If the type is `:basic`, then these can be a login and password pair.
# Otherwise, a single value is expected that will be appended after the type.
# This value can be a proc or an object responding to `.call`, in which case
# it will be invoked on each request.
def initialize(app, type, *params)
@type = type
@params = params
super(app)
end
end
# Internal
def self.build_hash(type, hash)
comma = ", "
values = []
hash.each do |key, value|
values << "#{key}=#{value.to_s.inspect}"
# @param env [Faraday::Env]
def on_request(env)
return if env.request_headers[KEY]
env.request_headers[KEY] = header_from(@type, env, *@params)
end
"#{type} #{values * comma}"
end
def initialize(app, type, token)
@header_value = self.class.header(type, token)
super(app)
end
private
# Public
def call(env)
unless env.request_headers[KEY]
env.request_headers[KEY] = @header_value
# @param type [String, Symbol]
# @param env [Faraday::Env]
# @param params [Array]
# @return [String] a header value
def header_from(type, env, *params)
if type.to_s.casecmp('basic').zero? && params.size == 2
Utils.basic_header_from(*params)
elsif params.size != 1
raise ArgumentError, "Unexpected params received (got #{params.size} instead of 1)"
else
value = params.first
if (value.is_a?(Proc) && value.arity == 1) || (value.respond_to?(:call) && value.method(:call).arity == 1)
value = value.call(env)
elsif value.is_a?(Proc) || value.respond_to?(:call)
value = value.call
end
"#{type} #{value}"
end
end
@app.call(env)
end
end
end
Faraday::Request.register_middleware(authorization: Faraday::Request::Authorization)

View File

@ -1,13 +0,0 @@
require 'base64'
module Faraday
class Request::BasicAuthentication < Request.load_middleware(:authorization)
# Public
def self.header(login, pass)
value = Base64.encode64([login, pass].join(':'))
value.gsub!("\n", '')
super(:Basic, value)
end
end
end

Some files were not shown because too many files have changed in this diff Show More