Compare commits

...

270 Commits

Author SHA1 Message Date
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
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
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
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
177 changed files with 7232 additions and 5032 deletions

View File

@ -24,7 +24,7 @@ These resources can help:
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://twitter.com/iMacTia) and [@olleolleolle](https://twitter.com/olleolleolle) on Twitter.
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
@ -64,50 +64,16 @@ We encourage adapters that:
1. have features not present in included adapters.
### Changes to the Faraday Website
### Changes to the Faraday Docs
The [Faraday Website][website] is included in the Faraday repository, under the `/docs` folder.
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.
#### Test website changes using Docker
Start by cloning the repository and navigate to the newly-cloned directory on your computer. Then run the following:
```bash
docker container run -p 80:4000 -v $(pwd)/docs:/site bretfisher/jekyll-serve
```
And that's it! Open your browser and navigate to `http://localhost` to see the website running.
Any change done to files in the `/docs` folder will be automatically picked up (with the exception of config changes).
#### Test website changes using Jekyll
You can test website changes locally, on your machine, too. Here's how:
Navigate into the /docs folder:
```bash
$ cd docs
```
Install Jekyll dependencies, this bundle is different from Faraday's one.
```bash
$ bundle install
```
Run the Jekyll server with the Faraday website
```bash
$ bundle exec jekyll serve
```
Now, navigate to http://127.0.0.1:4000/faraday/ to see the website running.
[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"

View File

@ -4,63 +4,66 @@ on:
pull_request:
push:
branches: [main, 0.1x]
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@v1
- uses: actions/checkout@v4
- name: Set up Ruby 2.7
- name: Setup Ruby 3.x
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
ruby-version: 3
bundler-cache: true
- name: Rubocop
run: |
gem install bundler
bundle config set without 'development test'
bundle config set with 'lint'
bundle install
bundle exec rubocop --format progress
run: bundle exec rubocop --format progress
- name: Yard-Junk
run: |
gem install yard-junk --no-document
yard-junk --path lib
run: bundle exec yard-junk --path lib
build:
needs: [linting]
needs: [ linting ]
runs-on: ubuntu-latest
name: build ${{ matrix.ruby }}
strategy:
fail-fast: false
matrix:
ruby: ['2.4', '2.5', '2.6', '2.7', '3.0']
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@v1
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
- name: Install dependencies
run: |
sudo apt-get install libcurl4-openssl-dev
- name: Build
run: |
gem install bundler -v '<2'
bundle install --jobs 4 --retry 3
- name: Test
- 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

View File

@ -9,21 +9,18 @@ jobs:
name: Publish to Rubygems
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
permissions:
contents: write
id-token: write
- name: Set up Ruby 2.6
uses: actions/setup-ruby@v1
steps:
- uses: actions/checkout@v4
- name: Setup Ruby 3.x
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6.x
bundler-cache: true
ruby-version: 3
- name: Publish to RubyGems
run: |
mkdir -p $HOME/.gem
touch $HOME/.gem/credentials
chmod 0600 $HOME/.gem/credentials
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
gem build faraday.gemspec
gem push faraday-*.gem
env:
GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_AUTH_TOKEN }}
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"

5
.gitignore vendored
View File

@ -8,12 +8,17 @@ tmp
.rvmrc
.ruby-version
.yardoc
.DS_Store
## BUNDLER
*.gem
.bundle
Gemfile.lock
vendor/bundle
external
## NPM
node_modules
## PROJECT::SPECIFIC
.rbx

View File

@ -1,62 +1,200 @@
inherit_from: .rubocop_todo.yml
require:
- rubocop-inclusivity
- rubocop-packaging
- rubocop-performance
AllCops:
DisplayCopNames: true
DisplayStyleGuide: true
TargetRubyVersion: 2.4
Inclusivity/Race:
Enabled: true
Metrics/BlockLength:
Exclude:
- spec/**/*.rb
- examples/**/*.rb
Layout/EmptyLinesAroundAttributeAccessor: # (0.83)
Enabled: 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
Layout/SpaceAroundMethodCallOperator:
Enabled: true
Lint/DeprecatedOpenSSLConstant: # (0.84)
Enabled: true
Lint/RaiseException:
Enabled: true
Lint/StructNewOverride:
Enabled: true
Style/DoubleNegation:
Enabled: false
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/ExponentialNotation:
Enabled: true
Style/HashEachMethods:
Enabled: true
Style/HashTransformKeys:
Enabled: true
Style/HashTransformValues:
Enabled: true
Style/DoubleNegation:
Enabled: false
Style/IfUnlessModifier:
Enabled: false
Style/SlicingWithRange: # (0.83)
# 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

View File

@ -1,32 +1,71 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2021-04-14 06:51:37 UTC using RuboCop version 0.90.0.
# 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: 26
# Configuration parameters: IgnoredMethods.
# 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: 5
# Offense count: 3
# Configuration parameters: CountComments, CountAsOne.
Metrics/ClassLength:
Max: 256
Max: 230
# Offense count: 15
# Configuration parameters: IgnoredMethods.
# Offense count: 9
# Configuration parameters: AllowedMethods, AllowedPatterns.
Metrics/CyclomaticComplexity:
Max: 13
# Offense count: 43
# Configuration parameters: CountComments, CountAsOne, ExcludedMethods.
# Offense count: 27
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
Metrics/MethodLength:
Max: 37
Max: 33
# Offense count: 9
# Configuration parameters: IgnoredMethods.
# 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,5 +1,192 @@
# Faraday Changelog
## 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
@ -104,7 +291,7 @@ Many thanks to the Faraday Team, @JanDintel and everyone who attended the [ROSS
* Website: add search bar (#1116)
* Fix request/response mix-up in docs text (#1132)
## v1.0
## [v1.0](https://github.com/lostisland/faraday/releases/tag/v1.0.0) (2020-01-22)
Features:
@ -148,6 +335,13 @@ Misc:
* 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:
@ -323,7 +517,7 @@ Breaking changes:
- Drop support for Ruby 1.8
Features:
- Include wrapped exception/reponse in ClientErrors
- 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

41
Gemfile
View File

@ -2,39 +2,28 @@
source 'https://rubygems.org'
ruby RUBY_VERSION
gem 'jruby-openssl', '~> 0.10.7', platforms: :jruby
# 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
group :development, :test do
gem 'pry'
gem 'rake'
end
group :lint, :development do
gem 'rubocop', '~> 0.90.0'
gem 'rubocop-inclusivity', '~> 1.0'
gem 'rubocop-packaging', '~> 0.5'
gem 'rubocop-performance', '~> 1.0'
end
group :test, :development do
gem 'bake-test-external'
gem 'coveralls_reborn', require: false
gem 'em-http-request', '>= 1.1', require: 'em-http', platform: :ruby
gem 'em-synchrony', '>= 1.0.3', require: %w[em-synchrony em-synchrony/em-http], platform: :ruby
gem 'excon', '>= 0.27.4'
gem 'httpclient', '>= 2.2'
gem 'multipart-parser'
# TODO: remove this once v4 is released
options = (RUBY_VERSION.start_with?('3') ? { github: 'grosser/net-http-persistent', branch: 'grosser/spec' } : {})
gem 'net-http-persistent', '>= 3.0', **options
gem 'patron', '>= 0.4.2', platforms: :ruby
gem 'rack-test', '>= 0.6', require: 'rack/test'
gem 'pry'
gem 'rack', '~> 3.0'
gem 'rake'
gem 'rspec', '~> 3.7'
gem 'rspec_junit_formatter', '~> 0.4'
gem 'simplecov'
gem 'typhoeus', '~> 1.4'
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-2020 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

View File

@ -1,25 +1,41 @@
# [![Faraday](./docs/assets/img/repo-card-slim.png)][website]
# [![Faraday](./docs/_media/home-logo.svg)][website]
[![Gem Version](https://badge.fury.io/rb/faraday.svg)](https://rubygems.org/gems/faraday)
[![GitHub Actions CI](https://github.com/lostisland/faraday/workflows/CI/badge.svg)](https://github.com/lostisland/faraday/actions?query=workflow%3ACI)
[![Gitter](https://badges.gitter.im/lostisland/faraday.svg)](https://gitter.im/lostisland/faraday?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[![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 library 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!
## Getting Started
The best starting point is the [Faraday Website][website], with its introduction and explanation.
Need more details? See the [Faraday API Documentation][apidoc] to see how it works internally.
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][actions] the following Ruby
implementations:
* Ruby 2.4+
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.
@ -41,13 +57,11 @@ Open the issues page and check for the `help wanted` label!
But before you start coding, please read our [Contributing Guide][contributing]
## Copyright
&copy; 2009 - 2020, the [Faraday Team][faraday_team]. Website and branding design by [Elena Lo Piccolo](https://elelopic.design).
&copy; 2009 - 2023, the Faraday Team. Website and branding design by [Elena Lo Piccolo](https://elelopic.design).
[awesome]: https://github.com/lostisland/awesome-faraday/#adapters
[website]: https://lostisland.github.io/faraday
[faraday_team]: https://lostisland.github.io/faraday/team
[contributing]: https://github.com/lostisland/faraday/blob/master/.github/CONTRIBUTING.md
[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
[jruby]: http://jruby.org/
[rubinius]: http://rubini.us/
[license]: LICENSE.md

View File

@ -1,7 +1,12 @@
# frozen_string_literal: true
require 'rspec/core/rake_task'
require 'bundler'
RSpec::Core::RakeTask.new(:spec)
Bundler::GemHelper.install_tasks
RSpec::Core::RakeTask.new(:spec) do |task|
task.ruby_opts = %w[-W]
end
task default: :spec

View File

@ -1,7 +1,133 @@
## 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

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

3
docs/.gitignore vendored
View File

@ -1,3 +0,0 @@
_site
.sass-cache
.jekyll-metadata

0
docs/.nojekyll Normal file
View File

View File

@ -1,24 +0,0 @@
---
layout: default
---
<style type="text/css" media="screen">
.container {
margin: 10px auto;
max-width: 600px;
text-align: center;
}
h1 {
margin: 30px 0;
font-size: 4em;
line-height: 1;
letter-spacing: -1px;
}
</style>
<div class="container">
<h1>404</h1>
<p><strong>Page not found :(</strong></p>
<p>The requested page could not be found.</p>
</div>

View File

@ -1,34 +0,0 @@
# frozen_string_literal: true
source 'https://rubygems.org'
# Hello! This is where you manage which Jekyll version is used to run.
# When you want to use a different version, change it below, save the
# file and run `bundle install`. Run Jekyll with `bundle exec`, like so:
#
# bundle exec jekyll serve
#
# This will help ensure the proper Jekyll version is running.
# Happy Jekylling!
# gem "jekyll", "~> 3.7.4"
# This is the default theme for new Jekyll sites.
# You may change this to anything you like.
# gem "minima", "~> 2.0"
# gem "jekyll-theme-type"
gem 'jekyll-remote-theme'
# If you want to use GitHub Pages, remove the "gem "jekyll"" above and
# uncomment the line below. To upgrade, run `bundle update github-pages`.
gem 'github-pages', group: :jekyll_plugins
# If you have any plugins, put them here!
group :jekyll_plugins do
gem 'jekyll-feed', '~> 0.6'
end
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby]
# Performance-booster for watching directories on Windows
gem 'wdm', '~> 0.1.0' if Gem.win_platform?

View File

@ -1,21 +1,21 @@
# Faraday Website
# Faraday Docs
This is the root directory of the [Faraday Website][website].
If you want to apply changes to it, please test it locally using `Jekyll`.
Faraday Docs are powered by [Docsify](https://docsify.js.org/#/).
Here is how:
## Development
### Setup
From the Faraday project root, run the following:
```bash
# Navigate into the /docs folder
$ cd docs
# Install Jekyll dependencies, this bundle is different from Faraday's one.
$ bundle install
# Run the Jekyll server with the Faraday website
$ bundle exec jekyll serve
# The site will now be reachable at http://127.0.0.1:4000/faraday/
npm install # this will install the necessary dependencies
```
[website]: https://lostisland.github.io/faraday
### Running the Docs Locally
To preview your changes locally, run the following:
```bash
npm run docs
```

View File

@ -1,55 +0,0 @@
# SITE CONFIGURATION
url: 'https://lostisland.github.io'
baseurl: '/faraday'
repository: 'lostisland/faraday'
# THEME-SPECIFIC CONFIGURATION
theme_settings:
title: Faraday
avatar: assets/img/logo.png
favicon: assets/img/favicon.png
# email: your-email@example.com
description: >-
Simple, but flexible HTTP client library, with support for multiple backends
footer_text: "&copy; 2009 - 2020, the <a class=\"body-link\" href=\"/faraday/team\">Faraday Team</a>. Website and branding design by <a href=\"https://elelopic.design\" target=\"_blank\">Elena Lo Piccolo</a>."
# Icons
github: 'lostisland/faraday'
gitter: 'lostisland/faraday'
# Post navigation
post_navigation: true
site_navigation_sort: 'order'
# BUILD SETTINGS
markdown: kramdown
remote_theme: rohanchandra/type-theme
plugins:
- jekyll-feed
- jekyll-remote-theme
# GitHub settings
lsi: false
safe: true
#source: [your repo's top level directory]
incremental: false
highlighter: rouge
gist:
noscript: false
kramdown:
math_engine: mathjax
syntax_highlighter: rouge
# Exclude from processing.
# The following items will not be processed, by default. Create a custom list
# to override the default setting.
exclude:
- Gemfile
- Gemfile.lock
- README.md
- node_modules
- vendor/bundle/
- vendor/cache/
- vendor/gems/
- vendor/ruby/

View File

@ -1,18 +0,0 @@
<div class="docs-nav">
<p class="docs-nav-item">
{% if page.prev_link %}
<a href="{{page.prev_link}}"><i class="fa fa-angle-left"></i> {{ page.prev_name }}</a>
{% endif %}
</p>
<p class="docs-nav-item">
{% if page.top_link %}
<a href="{{ page.top_link }}"><i class="fa fa-angle-up"></i> {{ page.top_name }}</a>
{% endif %}
</p>
<p class="docs-nav-item">
{% if page.next_link %}
<a href="{{ page.next_link }}">{{ page.next_name }} <i class="fa fa-angle-right"></i></a>
{% endif %}
</p>
</div>

View File

@ -1,21 +0,0 @@
<!-- Directly extracted from https://github.com/rohanchandra/type-theme/blob/c6ec5a69ff7dfe2df193be08515193c72bd4a55d/_includes/footer.html
for customization (DocSearch feature) -->
{% if site.theme_settings.katex and page.id %}
<script src="{{ "/assets/js/katex_init.js" | relative_url }}"></script>
{% endif %}
{% if site.theme_settings.footer_text %}
<footer class="site-footer">
<p class="text">{{ site.theme_settings.footer_text }}</p>
</footer>
{% endif %}
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.js"></script>
<script type="text/javascript"> docsearch({
apiKey: '4b20e432aa42a515b1a465b1494df8bf',
indexName: 'lostisland_faraday',
inputSelector: '#search-box',
debug: false // Set debug to true if you want to inspect the dropdown
});
</script>

View File

@ -1,59 +0,0 @@
<!-- This is extracted directly from https://github.com/rohanchandra/type-theme/blob/c6ec5a69ff7dfe2df193be08515193c72bd4a55d/_includes/header.html
for customization (DocSearch feature) -->
<header class="site-header">
<div class="branding">
{% if site.theme_settings.gravatar %}
<a href="{{ site.baseurl }}/">
<img class="avatar" src="https://secure.gravatar.com/avatar/{{ site.theme_settings.gravatar }}?s=100" alt=""/>
</a>
{% elsif site.theme_settings.avatar %}
<a href="{{ site.baseurl }}/">
<img class="avatar" src="{{ site.baseurl }}/{{ site.theme_settings.avatar }}" alt=""/>
</a>
{% endif %}
<h1 class="site-title">
<a href="{{ site.baseurl }}/">{{ site.theme_settings.title }}</a>
</h1>
</div>
<nav class="site-nav">
<ul>
{% if site.theme_settings.site_navigation_sort %}
{% assign site_pages = site.pages | sort: site.theme_settings.site_navigation_sort %}
{% else %}
{% assign site_pages = site.pages %}
{% endif %}
{% for page in site_pages %}
{% if page.title and page.hide != true %}
<li>
<a class="page-link" href="{{ page.url | relative_url }}">
{{ page.title }}
</a>
</li>
{% endif %}
{% endfor %}
<!-- Social icons from Font Awesome, if enabled -->
{% include icons.html %}
<!-- Search bar -->
{% if site.theme_settings.search %}
<li>
<form action="{{ site.baseurl }}/search.html" method="get">
<input type="text" id="search-box" name="query" placeholder="Search" class="">
<button type="submit" class="">
<i class="fa fa-fw fa-search"></i>
</button>
</form>
</li>
{% endif %}
<li>
<form id="search-form">
<input type="text" id="search-box" placeholder="Search">
<button type="submit">
<i class="fa fa-fw fa-search"></i>
</button>
</form>
</li>
</ul>
</nav>
</header>

View File

@ -1,7 +0,0 @@
---
layout: page
---
{{ content }}
{% include docs_nav.md %}

View File

Before

Width:  |  Height:  |  Size: 700 B

After

Width:  |  Height:  |  Size: 700 B

View File

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
docs/_media/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 225 KiB

After

Width:  |  Height:  |  Size: 225 KiB

BIN
docs/_media/overview.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

View File

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 186 KiB

View File

Before

Width:  |  Height:  |  Size: 358 KiB

After

Width:  |  Height:  |  Size: 358 KiB

View File

@ -1,25 +0,0 @@
---
layout: post
title: "Welcome to Jekyll!"
date: 2019-03-12 10:25:23 +0000
categories: jekyll update
---
Youll find this post in your `_posts` directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run `jekyll serve`, which launches a web server and auto-regenerates your site when a file is updated.
To add new posts, simply add a file in the `_posts` directory that follows the convention `YYYY-MM-DD-name-of-post.ext` and includes the necessary front matter. Take a look at the source for this post to get an idea about how it works.
Jekyll also offers powerful support for code snippets:
{% highlight ruby %}
def print_hi(name)
puts "Hi, #{name}"
end
print_hi('Tom')
#=> prints 'Hi, Tom' to STDOUT.
{% endhighlight %}
Check out the [Jekyll docs][jekyll-docs] for more info on how to get the most out of Jekyll. File all bugs/feature requests at [Jekylls GitHub repo][jekyll-gh]. If you have questions, you can ask them on [Jekyll Talk][jekyll-talk].
[jekyll-docs]: https://jekyllrb.com/docs/home
[jekyll-gh]: https://github.com/jekyll/jekyll
[jekyll-talk]: https://talk.jekyllrb.com/

View File

@ -1,9 +0,0 @@
// Override theme variables.
@import url('https://fonts.googleapis.com/css?family=Raleway:700');
$link-color: #EE4266;
$text-color: #3C3C3C;
$font-family-main: 'KohinoorTelugu-Regular', Helvetica, Arial, sans-serif;
$font-family-headings: 'Raleway', Helvetica, Arial, sans-serif;
$search-color: #EE4266;

View File

@ -1,129 +0,0 @@
// Custom Styles added on top of the theme.
.btn
display: inline-block
background-color: $link-color
padding: 5px 10px
box-shadow: 0 4px 10px 5px rgba(238, 66, 102, 0.30)
border-radius: 20px
width: 200px
color: #FFFFFF
letter-spacing: -0.41px
text-align: center
margin: 0 10px
&:hover
background-color: darken($link-color, 10%)
color: white
text-decoration: none
.text-center
text-align: center
.mt-60
margin-top: 60px
.hidden
display: none
.docs-nav
display: flex
margin-top: 40px
.docs-nav-item
flex: 1 1 0
text-align: center
pre.highlight
padding: 20px
background-color: #F6F6F6
border-radius: 4px
code
word-wrap: normal
overflow: scroll
code.highlighter-rouge
background-color: #EEE
padding: 0 5px
border-radius: 3px
.site-header .site-nav li
margin-right: 1.2em
h1, h2, h3, h4, h5, h6
font-weight: bold
.feature-image header
@media (max-width: 1000px)
padding: 7% 12.5%
@media (max-width: 576px)
padding: 4% 5% 1% 5%
#team-content
h3
margin: 30px 0
#contributors-list
text-align: justify
.team-tile
width: 200px
display: inline-block
margin: 0 20px
img
width: 100%
border-radius: 50%
footer
background-color: #f1f3f4
#active-maintainers-list, #historical-team-list
text-align: center
#loader
margin-top: 20%
margin-bottom: 20%
text-align: center
.lds-ring
display: inline-block
position: relative
width: 200px
height: 200px
.lds-ring div
box-sizing: border-box
display: block
position: absolute
width: 187px
height: 187px
margin: 6px
border: 12px solid $link-color
border-radius: 50%
animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite
border-color: $link-color transparent transparent transparent
.lds-ring div:nth-child(1)
animation-delay: -0.45s
.lds-ring div:nth-child(2)
animation-delay: -0.3s
.lds-ring div:nth-child(3)
animation-delay: -0.15s
@keyframes lds-ring
0%
transform: rotate(0deg)
100%
transform: rotate(360deg)
#search-form
display: inline-block
// You need a minimal window size for the search to display well, should be ok, people are on desktop
// when needing search usually
@media screen and (max-width: 800px)
display: none

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

View File

@ -1,72 +0,0 @@
---
layout: documentation
title: "EM-HTTP Adapter"
permalink: /adapters/em-http
hide: true
top_name: Adapters
top_link: ./
---
This Adapter uses [EventMachine](https://github.com/eventmachine/eventmachine/) and the tie in [em-http-request][src]
It can be used to make parallel requests using EventMachine.
The major difference between this and EMSynchrony is that it does not use fibers.
**Error handling and responses have a slightly different behaviour and structure in some cases. Please run thorough testing scenarios, including connection failures and SSL failures**
You will need to add em-http-request to your Gemfile:
```ruby
# Gemfile
gem 'em-http-request'
```
### Base request
```ruby
require 'faraday'
require 'em-http-request'
conn = Faraday.new(...) do |f|
# no custom options available
f.adapter :em_http
end
```
### Parallel Requests
```ruby
require 'faraday'
require 'em-http-request'
urls = Array.new(5) { 'http://127.0.0.1:3000' }
conn = Faraday::Connection.new do |builder|
builder.adapter :em_http
end
begin
conn.in_parallel do
puts "Parallel manager: #{conn.parallel_manager}"
@responses = urls.map do |url|
conn.get(url)
end
end
end
# Gather responses outside of block
puts @responses.map(&:status).join(', ')
puts @responses.map(&:status).compact.count
```
## Links
* [Gem RDoc][rdoc]
* [Gem source][src]
* [Adapter RDoc][adapter_rdoc]
* [EM-Synchrony Adapter](./em-synchrony.md)
[rdoc]: https://www.rubydoc.info/gems/em-http-request
[src]: https://github.com/igrigorik/em-http-request#readme
[adapter_rdoc]: https://www.rubydoc.info/github/lostisland/faraday/Faraday/Adapter/EMHttp

View File

@ -1,78 +0,0 @@
---
layout: documentation
title: "EM-Synchrony Adapter"
permalink: /adapters/em-synchrony
hide: true
top_name: Adapters
top_link: ./
---
This Adapter uses [EventMachine](https://github.com/eventmachine/eventmachine/) and the tie in [em-http-request](https://www.rubydoc.info/gems/em-http-request) in conjunction with [em-synchrony][rdoc]
It can be used to make parallel requests using EventMachine.
The key difference between this and EM-Http is that it uses fibers. For more information see igrigorik's blog posts on the matter:
- [fibers-cooperative-scheduling-in-ruby](https://www.igvita.com/2009/05/13/fibers-cooperative-scheduling-in-ruby/)
- [untangling-evented-code-with-ruby-fibers](https://www.igvita.com/2010/03/22/untangling-evented-code-with-ruby-fibers)
**Error handling and responses have a slightly different behaviour and structure in some cases. Please run thorough testing scenarios, including connection failures and SSL failures**
You will need to add em-http-request and em-synchrony to your Gemfile:
```ruby
# Gemfile
gem 'em-http-request'
gem 'em-synchrony'
```
### Base request
```ruby
require 'faraday'
require 'em-http-request'
require 'em-synchrony'
conn = Faraday.new(...) do |f|
# no custom options available
f.adapter :em_synchrony
end
```
### Parallel Requests
```ruby
require 'faraday'
require 'em-http-request'
require 'em-synchrony'
urls = Array.new(5) { 'http://127.0.0.1:3000' }
conn = Faraday::Connection.new do |builder|
builder.adapter :em_synchrony
end
begin
conn.in_parallel do
puts "Parallel manager: #{conn.parallel_manager}"
@responses = urls.map do |url|
conn.get(url)
end
end
end
# Gather responses outside of block
puts @responses.map(&:status).join(', ')
puts @responses.map(&:status).compact.count
```
## Links
* [Gem RDoc][rdoc]
* [Gem source][src]
* [Adapter RDoc][adapter_rdoc]
* [EM-HTTP Adapter](./em-http.md)
[rdoc]: https://www.rubydoc.info/gems/em-synchrony
[src]: https://github.com/igrigorik/em-synchrony
[adapter_rdoc]: https://www.rubydoc.info/github/lostisland/faraday/Faraday/Adapter/EMSynchrony

View File

@ -1,27 +0,0 @@
---
layout: documentation
title: "Excon Adapter"
permalink: /adapters/excon
hide: true
top_name: Adapters
top_link: ./
---
This Adapter uses the [excon][rdoc] gem to make HTTP requests.
```ruby
conn = Faraday.new(...) do |f|
# no custom options available
f.adapter :excon
end
```
## Links
* [Gem RDoc][rdoc]
* [Gem source][src]
* [Adapter RDoc][adapter_rdoc]
[rdoc]: https://www.rubydoc.info/gems/excon
[src]: https://github.com/excon/excon
[adapter_rdoc]: https://www.rubydoc.info/github/lostisland/faraday/Faraday/Adapter/Excon

View File

@ -1,30 +0,0 @@
---
layout: documentation
title: "HTTPClient Adapter"
permalink: /adapters/httpclient
hide: true
top_name: Adapters
top_link: ./
---
This Adapter uses the [httpclient][rdoc] gem to make HTTP requests.
```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
```
## Links
* [Gem RDoc][rdoc]
* [Gem source][src]
* [Adapter RDoc][adapter_rdoc]
[rdoc]: https://www.rubydoc.info/gems/httpclient
[src]: https://github.com/nahi/httpclient
[adapter_rdoc]: https://www.rubydoc.info/github/lostisland/faraday/Faraday/Adapter/HTTPClient

View File

@ -1,186 +1,46 @@
---
layout: documentation
title: "Adapters"
permalink: /adapters/
order: 2
---
# 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.
{: .mt-60}
## Built-in adapters
For example, consider using `httpclient` as an adapter. Note that [faraday-httpclient](https://github.com/lostisland/faraday-httpclient) must be installed beforehand.
Faraday includes these adapters (but not the HTTP client libraries):
If you want to configure it globally, do the following:
* [Net::HTTP][net_http] _(this is the default adapter)_
* [Net::HTTP::Persistent][persistent]
* [Excon][excon]
* [Patron][patron]
* [EM-Synchrony][em-synchrony]
* [EM-Http][em-http]
* [HTTPClient][httpclient]
```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.
* [Test Adapter][testing]
* Rack Adapter (link TBD)
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]!
## External adapters
Adapters are slowly being moved into their own gems, or bundled with HTTP clients.
Please refer to their documentation for usage examples.
* [Typhoeus][typhoeus]
* [HTTP.rb][faraday-http]
* [httpx][httpx]
## 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 each adapter page for more details.
## Write your own adapter
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:
```ruby
class FlorpHttp < ::Faraday::Adapter
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.
### Helpful method: `#build_connection`
Faraday abstracts all your backend's concrete stuff behind its user-facing API.
You take care of setting up the connection from the supplied parameters.
Example from the excon adapter: it gets an `Env` and reads its information
to instantiate an `Excon` object:
```ruby
class FlorpHttp < ::Faraday::Adapter
def build_connection(env)
opts = opts_from_env(env)
::Excon.new(env[:url].to_s, opts.merge(@connection_options))
end
end
```
The `env` contains stuff like:
- `env[:ssl]`
- `env[:request]`
There are helper to fetch timeouts: `#request_timeout(type, options)` 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.
So, use the information provided in `env` to instantiate your backend's connection class.
Return that instance. Now, Faraday knows how to create and reuse that connection.
### Nickname for your adapter: `.register_middleware`
You may register a nickname for your adapter. People can then refer to your adapter with that name.
You do that using `.register_middleware`, like this:
```ruby
class FlorpHttp < ::Faraday::Adapter
register_middleware(
File.expand_path('adapter', __dir__),
florp_http: [ :FlorpHttp, 'florp_http' ]
)
# ...
end
```
## Does your backend support parallel operation?
:warning: 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/master/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
end
class FlorpParallelManager
def add(request, method, *args, &block)
# Collect the requests
end
def run
# Process the requests
end
end
```
Compare to the finished example [em-synchrony](https://github.com/lostisland/faraday/blob/master/lib/faraday/adapter/em_synchrony.rb) and its [ParallelManager implementation](https://github.com/lostisland/faraday/blob/master/lib/faraday/adapter/em_synchrony/parallel_manager.rb).
[net_http]: ./net-http
[persistent]: ./net-http-persistent
[excon]: ./excon
[patron]: ./patron
[em-synchrony]: ./em-synchrony
[em-http]: ./em-http
[httpclient]: ./httpclient
[typhoeus]: https://github.com/typhoeus/typhoeus/blob/master/lib/typhoeus/adapters/faraday.rb
[faraday-http]: https://github.com/lostisland/faraday-http
[testing]: ./testing
[httpx]: https://honeyryderchuck.gitlab.io/httpx/wiki/Faraday-Adapter
[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

@ -1,31 +0,0 @@
---
layout: documentation
title: "Net::HTTP Adapter"
permalink: /adapters/net-http
hide: true
top_name: Adapters
top_link: ./
---
This Adapter uses the [`Net::HTTP`][rdoc] client from the Ruby standard library to make
HTTP requests.
```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, cert_store|
# do something here...
end
end
end
```
## Links
* [Net::HTTP RDoc][rdoc]
* [Adapter RDoc][adapter_rdoc]
[rdoc]: http://ruby-doc.org/stdlib/libdoc/net/http/rdoc/Net/HTTP.html
[adapter_rdoc]: https://www.rubydoc.info/github/lostisland/faraday/Faraday/Adapter/NetHttp

View File

@ -1,29 +0,0 @@
---
layout: documentation
title: "Net::HTTP::Persistent Adapter"
permalink: /adapters/net-http-persistent
hide: true
top_name: Adapters
top_link: ./
---
This Adapter uses the [net-http-persistent][rdoc] gem to make HTTP requests.
```ruby
conn = Faraday.new(...) do |f|
f.adapter :net_http_persistent, pool_size: 5 do |http|
# yields Net::HTTP::Persistent
http.idle_timeout = 100
end
end
```
## Links
* [Gem RDoc][rdoc]
* [Gem source][src]
* [Adapter RDoc][adapter_rdoc]
[rdoc]: https://www.rubydoc.info/gems/net-http-persistent
[src]: https://github.com/drbrain/net-http-persistent
[adapter_rdoc]: https://www.rubydoc.info/github/lostisland/faraday/Faraday/Adapter/NetHttpPersistent

View File

@ -1,29 +0,0 @@
---
layout: documentation
title: "Patron Adapter"
permalink: /adapters/patron
hide: true
top_name: Adapters
top_link: ./
---
This Adapter uses the [patron][rdoc] gem to make HTTP requests.
```ruby
conn = Faraday.new(...) do |f|
f.adapter :patron do |session|
# yields Patron::Session
session.max_redirects = 10
end
end
```
## Links
* [Gem RDoc][rdoc]
* [Gem source][src]
* [Adapter RDoc][adapter_rdoc]
[rdoc]: https://www.rubydoc.info/gems/patron
[src]: https://github.com/toland/patron
[adapter_rdoc]: https://www.rubydoc.info/github/lostisland/faraday/Faraday/Adapter/Patron

View File

@ -1,11 +1,4 @@
---
layout: documentation
title: "Testing"
permalink: /adapters/testing
hide: true
top_name: Adapters
top_link: ./
---
# 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.
@ -33,7 +26,7 @@ conn = Faraday.new do |builder|
# test exceptions too
stub.get('/boom') do
raise Faraday::ConnectionFailed, nil
raise Faraday::ConnectionFailed
end
end
end
@ -64,6 +57,14 @@ initialized. This is useful for testing.
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.
@ -112,5 +113,5 @@ Faraday.default_connection = nil
Working [RSpec] and [test/unit] examples for a fictional JSON API client are
available.
[RSpec]: https://github.com/lostisland/faraday/blob/master/examples/client_spec.rb
[test/unit]: https://github.com/lostisland/faraday/blob/master/examples/client_test.rb
[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

@ -1,7 +0,0 @@
---
---
@import "variables";
@import "type-theme";
@import "faraday";
@import "https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.css"

View File

@ -1,52 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="1920px" height="1024px" viewBox="0 0 1920 1024" 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>Background and Stripes</title>
<desc>Created with Sketch.</desc>
<defs>
<linearGradient x1="0%" y1="50%" x2="113.817376%" y2="50%" 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>
<path d="M1497.08184,1023 L1413.76949,1023 L1970,467.082708 L1970,550.348143 L1747.2718,772.950924 L1497.08184,1023 Z M1237.28591,1023 L1153.97357,1023 L1970,207.433075 L1970,290.698512 L1308.46073,951.865267 L1237.28591,1023 Z M977.1947,1023 L893.882349,1023 L1917.45873,-5.68434189e-13 L1970,-2.27373675e-13 L1970,30.7537554 L977.1947,1023 Z M716.514745,1023 L633.202393,1023 L1656.77878,-2.27373675e-13 L1740.09113,-2.01923225e-13 L716.514745,1023 Z M455.834791,1023 L372.522439,1023 L1396.09882,-2.27373675e-13 L1479.41117,-1.73066477e-13 L455.834791,1023 Z M198.100371,1023 L114.787781,1023 L1138.36416,-3.41060513e-13 L1221.67675,-1.44535795e-13 L198.100371,1023 Z" id="path-2"></path>
<filter x="-4.5%" y="-4.5%" width="109.0%" height="109.0%" filterUnits="objectBoundingBox" id="filter-4">
<feGaussianBlur stdDeviation="0" in="SourceGraphic"></feGaussianBlur>
</filter>
<filter x="-2.9%" y="-2.9%" width="105.8%" height="105.8%" filterUnits="objectBoundingBox" id="filter-5">
<feGaussianBlur stdDeviation="0" in="SourceGraphic"></feGaussianBlur>
</filter>
<filter x="-2.1%" y="-2.1%" width="104.3%" height="104.3%" filterUnits="objectBoundingBox" id="filter-6">
<feGaussianBlur stdDeviation="0" in="SourceGraphic"></feGaussianBlur>
</filter>
<filter x="-2.1%" y="-2.1%" width="104.0%" height="104.1%" filterUnits="objectBoundingBox" id="filter-7">
<feGaussianBlur stdDeviation="0" in="SourceGraphic"></feGaussianBlur>
</filter>
<filter x="-2.0%" y="-2.1%" width="104.0%" height="104.1%" filterUnits="objectBoundingBox" id="filter-8">
<feGaussianBlur stdDeviation="0" in="SourceGraphic"></feGaussianBlur>
</filter>
<filter x="-2.0%" y="-2.1%" width="104.0%" height="104.1%" filterUnits="objectBoundingBox" id="filter-9">
<feGaussianBlur stdDeviation="0" in="SourceGraphic"></feGaussianBlur>
</filter>
</defs>
<g id="Background-and-Stripes" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<rect id="Rectangle" fill="#EDEBEB" fill-rule="nonzero" x="0" y="0" width="1922" height="1023"></rect>
<mask id="mask-3" fill="white">
<use xlink:href="#path-2"></use>
</mask>
<use id="Combined-Shape" fill-opacity="0.5" fill="url(#linearGradient-1)" fill-rule="nonzero" xlink:href="#path-2"></use>
<g id="Line" transform="translate(148.000000, 0.000000)" stroke="#FFFFFF" stroke-linecap="square" stroke-width="30">
<path d="M1303.02503,1024 L1772,555.025033" filter="url(#filter-4)"></path>
<path d="M1045.02503,1024 L1772,297.025033" filter="url(#filter-5)"></path>
<path d="M786.025033,1024 L1772,38.0250327" filter="url(#filter-6)"></path>
<path d="M522.025037,1024 L1546.02504,0" filter="url(#filter-7)"></path>
<path d="M261.55292,1024 L1285.55292,0" filter="url(#filter-8)"></path>
<path d="M0.552920204,1024 L1024.55292,0" filter="url(#filter-9)"></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 876 B

View File

@ -1,49 +0,0 @@
function teamTile(member) {
console.log(member);
return '<div class="team-tile">' +
'<a href="' + member.author.html_url + '">' +
'<img src="' + member.author.avatar_url + '" />' +
'<p class="team-tile-login">' +
member.author.login +
'</p>' +
'</a>' +
'</div>';
}
function fetchTeam(json, team, div) {
let el = document.querySelector(div);
el.innerHTML = team.map(function (m) {
let index = json.findIndex(function(e) {
return e.author.login === m
});
return teamTile(json.splice(index, 1)[0]);
}).join('');
}
function fetchContributors(json) {
let el = document.querySelector('#contributors-list');
el.innerHTML = json.reverse().map(function (c) {
return '<span class="contributor"><a href="' + c.author.html_url + '">' + c.author.login + '</a></span>';
}).join('<b> &#183; </b>');
}
function hideLoader() {
let el = document.querySelector('#loader');
el.classList.add('hidden');
}
function showTeam() {
let el = document.querySelector('#team-content');
el.classList.remove('hidden');
}
fetch('https://api.github.com/repos/lostisland/faraday/stats/contributors')
.then(function (response) {
response.json().then(function (json) {
fetchTeam(json, ['technoweenie', 'iMacTia', 'olleolleolle'], '#active-maintainers-list');
fetchTeam(json, ['mislav', 'sferik'], '#historical-team-list');
fetchContributors(json);
hideLoader();
showTeam();
});
});

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

View File

@ -1,28 +1,23 @@
---
layout: documentation
title: "Customizing the Request"
permalink: /usage/customize
hide: true
top_name: Usage
top_link: ./
next_name: Streaming Responses
next_link: ./streaming
---
# 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://sushi.com', request: { timeout: 5 })
conn.get('/search')
conn = Faraday.new('http://httpbingo.org', request: { timeout: 5 })
conn.get('/ip')
```
Or as per-request options:
```ruby
conn.get do |req|
req.url '/search'
req.url '/ip'
req.options.timeout = 5
end
```
@ -32,7 +27,7 @@ This will be available in the `env` on all middleware.
```ruby
conn.get do |req|
req.url '/search'
req.url '/get'
req.options.context = {
foo: 'foo',
bar: 'bar'
@ -77,6 +72,20 @@ 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].

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>

View File

@ -1,51 +1,28 @@
---
# You don't need to edit this file, it's empty on purpose.
# Edit theme's home layout instead if you wanna make some changes
# See: https://jekyllrb.com/docs/themes/#overriding-theme-defaults
layout: page
title: Homepage
feature-title: <img src="assets/img/home-logo.svg">
feature-img: "assets/img/featured-bg.svg"
hide: true
---
# ![Faraday](_media/home-logo.svg)
Faraday is an HTTP client library 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.
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.
{: .text-center}
[<i class="fab fa-fw fa-github"> </i> Fork on GitHub][github]{: .btn}
[<i class="fab fa-fw fa-gitter"> </i> Chat with us][gitter]{: .btn}
## Why use Faraday?
{: .mt-60}
## Installation
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.
Add this line to your application's Gemfile:
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!
```ruby
gem 'faraday'
```
## Who uses Faraday?
And then execute:
```bash
$ bundle
```
Or install it yourself as:
```bash
$ gem install faraday
```
You can also install the [`faraday_middleware`][faraday_middleware]
extension gem to access a collection of useful Faraday middleware.
{: .mt-60}
{: .text-center}
[<i class="fas fa-fw fa-book-open"> </i> Read the docs][usage]{: .btn}
[github]: https://github.com/lostisland/faraday
[gitter]: https://gitter.im/lostisland/faraday
[faraday_middleware]: https://github.com/lostisland/faraday_middleware
[usage]: ./usage
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

@ -1,59 +0,0 @@
---
layout: documentation
title: "Writing Middleware"
permalink: /middleware/custom
hide: true
top_name: Middleware
top_link: ./
prev_name: Available Middleware
prev_link: ./list
---
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
```
### Faraday::Middleware
There's an easier way to write middleware, and it's also the recommended one: make your middleware subclass `Faraday::Middleware`.
`Faraday::Middleware` already implements the `#call` method for you and looks for two methods in your subclass: `#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.
### Do I need to override `#call`?
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!

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

@ -1,13 +1,4 @@
---
layout: documentation
title: "Available Middleware"
permalink: /middleware/list
hide: true
top_name: Middleware
top_link: ./
next_name: Writing Middleware
next_link: ./custom
---
# 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**.
@ -21,14 +12,9 @@ parsing the response body, logging useful info or checking the response status.
middleware set Header values or transform the request body based on the
content type.
* [`BasicAuthentication`][authentication] sets the `Authorization` header to the `user:password`
base64 representation.
* [`TokenAuthentication`][authentication] sets the `Authorization` header to the specified token.
* [`Multipart`][multipart] converts a `Faraday::Request#body` hash of key/value pairs into a
multipart form request.
* [`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.
* [`Retry`][retry] automatically retries requests that fail due to intermittent client
or server errors (such as network hiccups).
* [`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.
@ -37,14 +23,15 @@ or server errors (such as network hiccups).
**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]: ./authentication
[multipart]: ./multipart
[url_encoded]: ./url-encoded
[retry]: ./retry
[instrumentation]: ./instrumentation
[logger]: ./logger
[raise_error]: ./raise-error
[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

@ -1,15 +1,4 @@
---
layout: documentation
title: "Instrumentation Middleware"
permalink: /middleware/instrumentation
hide: true
prev_name: Retry Middleware
prev_link: ./retry
next_name: Logger Middleware
next_link: ./logger
top_name: Back to Middleware
top_link: ./list
---
# 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.

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

@ -1,15 +1,4 @@
---
layout: documentation
title: "Logger Middleware"
permalink: /middleware/logger
hide: true
prev_name: Instrumentation Middleware
prev_link: ./instrumentation
next_name: RaiseError Middleware
next_link: ./raise-error
top_name: Back to Middleware
top_link: ./list
---
# 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.
@ -17,12 +6,12 @@ It is highly customizable and allows to mask confidential information if necessa
### Basic Usage
```ruby
conn = Faraday.new(url: 'http://sushi.com') do |faraday|
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://sushi.com/
# => 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"
@ -34,7 +23,7 @@ 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://sushi.com') do |faraday|
conn = Faraday.new(url: 'http://httpbingo.org') do |faraday|
faraday.response :logger, MyLogger.new($stdout)
end
```
@ -42,12 +31,21 @@ 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 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:
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://sushi.com') do |faraday|
faraday.response :logger, nil, { headers: true, bodies: true }
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
```
@ -58,14 +56,14 @@ Please note this only works with the default formatter.
You can filter sensitive information from Faraday logs using a regex matcher:
```ruby
conn = Faraday.new(url: 'http://sushi.com') do |faraday|
conn = Faraday.new(url: 'http://httpbingo.org') do |faraday|
faraday.response :logger do | logger |
logger.filter(/(api_key=)(\w+)/, '\1[REMOVED]')
logger.filter(/(api_key=)([^&]+)/, '\1[REMOVED]')
end
end
conn.get('/', api_key: 'secret')
# => INFO -- request: GET http://sushi.com/?api_key=[REMOVED]
# => 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"
@ -77,16 +75,18 @@ By default, the `logger` middleware logs on the `info` log level. It is possible
the severity by providing the `log_level` option:
```ruby
conn = Faraday.new(url: 'http://sushi.com') do |faraday|
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 and responses are logged.
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.
@ -101,9 +101,14 @@ class MyFormatter < Faraday::Logging::Formatter
# 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://sushi.com/api_key=s3cr3t') do |faraday|
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

@ -1,19 +1,8 @@
---
layout: documentation
title: "UrlEncoded Middleware"
permalink: /middleware/url-encoded
hide: true
prev_name: Multipart Middleware
prev_link: ./multipart
next_name: Retry Middleware
next_link: ./retry
top_name: Back to Middleware
top_link: ./list
---
# 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][customize].
The way parameters are serialized can be customized in the [Request Options](customization/request-options.md).
### Example Usage
@ -39,4 +28,4 @@ conn.post('/', { a: [1, 3], b: { c: 2, d: 4} })
# 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
[customize]: ../usage/customize#changing-how-parameters-are-serialized

View File

@ -1,11 +1,4 @@
---
layout: documentation
title: "Middleware"
permalink: /middleware/
next_name: Available Middleware
next_link: ./list
order: 3
---
# 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
@ -19,19 +12,18 @@ Here are some of the features that middleware can provide:
- following redirects
- JSON encoding/decoding
- logging
- retrying
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_middleware'
require 'faraday'
conn = Faraday.new do |f|
f.request :json # encode req bodies as JSON
f.request :retry # retry transient failures
f.response :follow_redirects # follow redirects
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")
```
@ -45,10 +37,44 @@ 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), it must
innermost one. If you want to use a custom [adapter](adapters/index.md), it must
therefore be last.
![Middleware](../assets/img/middleware.png)
![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
@ -64,8 +90,8 @@ For example, the `Faraday::Request::UrlEncoded` middleware registers itself in
# Faraday::Response and Faraday::Adapter registries
conn = Faraday.new do |f|
f.request :url_encoded
f.response :follow_redirects
f.adapter :httpclient
f.response :logger
f.adapter :net_http
end
```
@ -75,8 +101,8 @@ or:
# identical, but add the class directly instead of using lookups
conn = Faraday.new do |f|
f.use Faraday::Request::UrlEncoded
f.use FaradayMiddleware::FollowRedirects
f.use Faraday::Adapter::HTTPClient
f.use Faraday::Response::Logger
f.use Faraday::Adapter::NetHttp
end
```
@ -84,19 +110,67 @@ This is also the place to pass options. For example:
```ruby
conn = Faraday.new do |f|
f.request :retry, max: 10
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-middleware](https://github.com/lostisland/faraday_middleware) gem.
We also have [great documentation](list) for the middleware that ships with
Faraday.
[faraday-retry](https://github.com/lostisland/faraday-retry) gem.
### Detailed Example
@ -104,32 +178,23 @@ Here's a more realistic example:
```ruby
Faraday.new(...) do |conn|
# POST/PUT params encoders:
conn.request :multipart
# POST/PUT params encoder
conn.request :url_encoded
# Last middleware must be the adapter:
conn.adapter :typhoeus
# 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::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
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.
For example:
```ruby
# uploading a file:
payload[:profile_pic] = Faraday::FilePart.new('/path/to/avatar.jpg', 'image/jpeg')
# "Multipart" middleware detects files and encodes with "multipart/form-data":
conn.put '/profile', payload
```

View File

@ -1,46 +0,0 @@
---
layout: documentation
title: "Authentication Middleware"
permalink: /middleware/authentication
hide: true
next_name: Multipart Middleware
next_link: ./multipart
top_name: Back to Middleware
top_link: ./list
---
The `Faraday::Request::Authorization` middleware allows you to automatically add an `Authorization` header
to your requests. It also features 2 specialised sub-classes that provide useful extra features for Basic Authentication
and Token Authentication requests.
### Any Authentication
The generic `Authorization` middleware allows you to add any type of Authorization header.
```ruby
Faraday.new(...) do |conn|
conn.request :authorization, 'Bearer', 'authentication-token'
end
```
### Basic Authentication
`BasicAuthentication` adds a 'Basic' type Authorization header to a Faraday request.
```ruby
Faraday.new(...) do |conn|
conn.request :basic_auth, 'username', 'password'
end
```
### Token Authentication
`TokenAuthentication` adds a 'Token' type Authorization header to a Faraday request.
You can optionally provide a hash of `options` that will be appended to the token.
This is not used anymore in modern web and have been replaced by Bearer tokens.
```ruby
Faraday.new(...) do |conn|
conn.request :token_auth, 'authentication-token', **options
end
```

View File

@ -1,68 +0,0 @@
---
layout: documentation
title: "Multipart Middleware"
permalink: /middleware/multipart
hide: true
prev_name: Authentication Middleware
prev_link: ./authentication
next_name: UrlEncoded Middleware
next_link: ./url-encoded
top_name: Back to Middleware
top_link: ./list
---
The `Multipart` middleware converts a `Faraday::Request#body` Hash of key/value
pairs into a multipart form request, but only under these conditions:
* The request's Content-Type is "multipart/form-data"
* Content-Type is unspecified, AND one of the values in the Body responds to
`#content_type`.
Faraday contains a couple helper classes for multipart values:
* `Faraday::FilePart` wraps binary file data with a Content-Type. The file data
can be specified with a String path to a local file, or an IO object.
* `Faraday::ParamPart` wraps a String value with a Content-Type, and optionally
a Content-ID.
Note: `Faraday::ParamPart` was added in Faraday v0.16.0. Before that,
`Faraday::FilePart` was called `Faraday::UploadIO`.
### Example Usage
```ruby
conn = Faraday.new(...) do |f|
f.request :multipart
...
end
```
Payload can be a mix of POST data and multipart values.
```ruby
# regular POST form value
payload = { string: 'value' }
# filename for this value is File.basename(__FILE__)
payload[:file] = Faraday::FilePart.new(__FILE__, 'text/x-ruby')
# specify filename because IO object doesn't know it
payload[:file_with_name] = Faraday::FilePart.new(File.open(__FILE__),
'text/x-ruby',
File.basename(__FILE__))
# Sets a custom Content-Disposition:
# nil filename still defaults to File.basename(__FILE__)
payload[:file_with_header] = Faraday::FilePart.new(__FILE__,
'text/x-ruby', nil,
'Content-Disposition' => 'form-data; foo=1')
# Upload raw json with content type
payload[:raw_data] = Faraday::ParamPart.new({a: 1}.to_json, 'application/json')
# optionally sets Content-ID too
payload[:raw_with_id] = Faraday::ParamPart.new({a: 1}.to_json, 'application/json',
'foo-123')
conn.post('/', payload)
```

View File

@ -1,126 +0,0 @@
---
layout: documentation
title: "Retry Middleware"
permalink: /middleware/retry
hide: true
prev_name: UrlEncoded Middleware
prev_link: ./url-encoded
next_name: Instrumentation Middleware
next_link: ./instrumentation
top_name: Back to Middleware
top_link: ./list
---
The `Retry` middleware automatically retries requests that fail due to intermittent client
or server errors (such as network hiccups).
By default, it retries 2 times and handles only timeout exceptions.
It can be configured with an arbitrary number of retries, a list of exceptions to handle,
a retry interval, a percentage of randomness to add to the retry interval, and a backoff factor.
The middleware can also handle the [`Retry-After`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After) header automatically when configured with the right status codes (see below for an example).
### Example Usage
This example will result in a first interval that is random between 0.05 and 0.075
and a second interval that is random between 0.1 and 0.125.
```ruby
retry_options = {
max: 2,
interval: 0.05,
interval_randomness: 0.5,
backoff_factor: 2
}
conn = Faraday.new(...) do |f|
f.request :retry, retry_options
...
end
conn.get('/')
```
### Control when the middleware will retry requests
By default, the `Retry` middleware will only retry idempotent methods and the most common network-related exceptions.
You can change this behaviour by providing the right option when adding the middleware to your connection.
#### Specify which methods will be retried
You can provide a `methods` option with a list of HTTP methods.
This will replace the default list of HTTP methods: `delete`, `get`, `head`, `options`, `put`.
```ruby
retry_options = {
methods: %i[get post]
}
```
#### Specify which exceptions should trigger a retry
You can provide an `exceptions` option with a list of exceptions that will replace
the default list of network-related exceptions: `Errno::ETIMEDOUT`, `Timeout::Error`, `Faraday::TimeoutError`.
This can be particularly useful when combined with the [RaiseError][raise_error] middleware.
```ruby
retry_options = {
exceptions: [Faraday::ResourceNotFound, Faraday::UnauthorizedError]
}
```
#### Specify on which response statuses to retry
By default the `Retry` middleware will only retry the request if one of the expected exceptions arise.
However, you can specify a list of HTTP statuses you'd like to be retried. When you do so, the middleware will
check the response `status` code and will retry the request if included in the list.
```ruby
retry_options = {
retry_statuses: [401, 409]
}
```
#### Automatically handle the `Retry-After` header
Some APIs, like the [Slack API](https://api.slack.com/docs/rate-limits), will inform you when you reach their API limits by replying with a response status code of `429` and a response header of `Retry-After` containing a time in seconds. You should then only retry querying after the amount of time provided by the `Retry-After` header, otherwise you won't get a response.
You can automatically handle this and have Faraday pause and retry for the right amount of time by including the `429` status code in the retry statuses list:
```ruby
retry_options = {
retry_statuses: [429]
}
```
#### Specify a custom retry logic
You can also specify a custom retry logic with the `retry_if` option.
This option accepts a block that will receive the `env` object and the exception raised
and should decide if the code should retry still the action or not independent of the retry count.
This would be useful if the exception produced is non-recoverable or if the the HTTP method called is not idempotent.
**NOTE:** this option will only be used for methods that are not included in the `methods` option.
If you want this to apply to all HTTP methods, pass `methods: []` as an additional option.
```ruby
# Retries the request if response contains { success: false }
retry_options = {
retry_if: -> (env, _exc) { env.body[:success] == 'false' }
}
```
### Call a block on every retry
You can specify a block through the `retry_block` option that will be called before every retry.
There are many different applications for this feature, spacing from instrumentation to monitoring.
Request environment, middleware options, current number of retries and the exception is passed to the block as parameters.
For example, you might want to keep track of the response statuses:
```ruby
response_statuses = []
retry_options = {
retry_block: -> (env, options, retries, exc) { response_statuses << env.status }
}
```
[raise_error]: ../middleware/raise-error

View File

@ -1,49 +0,0 @@
---
layout: documentation
title: "Raise Error Middleware"
permalink: /middleware/raise-error
hide: true
prev_name: Logger Middleware
prev_link: ./logger
top_name: Back to Middleware
top_link: ./list
---
The `RaiseError` middleware raises a `Faraday::Error` exception if an HTTP
response returns with a 4xx or 5xx status code. All exceptions are initialized
providing the response `status`, `headers`, and `body`.
```ruby
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, according to the list below:
An HTTP status in the 400-499 range typically represents an error
by the client. They raise error classes inheriting from `Faraday::ClientError`.
* 400 => `Faraday::BadRequestError`
* 401 => `Faraday::UnauthorizedError`
* 403 => `Faraday::ForbiddenError`
* 404 => `Faraday::ResourceNotFound`
* 407 => `Faraday::ProxyAuthError`
* 409 => `Faraday::ConflictError`
* 422 => `Faraday::UnprocessableEntityError`
* 4xx => `Faraday::ClientError`
An HTTP status in the 500-599 range represents a server error, and raises a
`Faraday::ServerError` exception.
* 5xx => `Faraday::ServerError`
The HTTP response status may be nil due to a malformed HTTP response from the
server, or a bug in the underlying HTTP library. It inherits from
`Faraday::ServerError`.
* nil => `Faraday::NilStatusError`

View File

@ -1,26 +0,0 @@
---
layout: page
title: Team
permalink: /team/
order: 4
---
<div id="loader">
<div class="lds-ring"><div></div><div></div><div></div><div></div></div>
</div>
<div id="team-content" class="hidden">
<h3 class="text-center">Active Maintainers</h3>
<div id="active-maintainers-list"></div>
<h3 class="text-center">Historical team</h3>
<div id="historical-team-list"></div>
<h3 class="text-center">All the contributors</h3>
<div id="contributors-list"></div>
<h3 class="text-center">And some extra help</h3>
<p class="text-center">Website and branding design: <a href="https://elelopic.design" target="_blank">Elena Lo Piccolo</a></p>
</div>
<script src="{{ site.baseurl }}/assets/js/team.js"></script>

View File

@ -1,182 +0,0 @@
---
layout: documentation
title: "Usage"
permalink: /usage/
next_name: Customizing the Request
next_link: ./customize
order: 1
---
Let's fetch the home page for the wonderful
[httpbingo.org](https://httpbingo.org) service. Make a simple `GET` request by
requiring the Faraday gem and using `Faraday.get`:
```ruby
require 'faraday'
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> ...
```
### GET
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
url = 'http://httpbingo.org/get'
response = Faraday.get(url, {boom: 'zap'}, {'User-Agent' => 'myapp'})
# => GET http://httpbingo.org/get?boom=zap
```
### POST
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
url = 'http://httpbingo.org/post'
# POST 'application/x-www-form-urlencoded' content
response = Faraday.post(url, "boom=zap")
# POST JSON content
response = Faraday.post(url, '{"boom": "zap"}',
"Content-Type" => "application/json")
```
#### Posting Forms
Faraday will automatically convert key/value hashes into proper form bodies.
```ruby
# POST 'application/x-www-form-urlencoded' content
url = 'http://httpbingo.org/post'
response = Faraday.post(url, boom: 'zap')
# => POST 'boom=zap' to http://httpbingo.org/post
```
Faraday can also [upload files][multipart].
### 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 = Faraday.post('http://httpbingo.org/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
```
### Customizing Faraday::Connection
You may want to create a `Faraday::Connection` to setup a common config for
multiple requests. The connection object can be configured with things like:
- 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`. The HTTP verbs
described above (`get`, `post`, ...) are `Faraday::Connection` methods:
```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
```
### Adapters
Adapters are responsible for actually executing HTTP requests. The default
adapter uses Ruby's `Net::HTTP`, but there are many different adapters
available. You might want to use Faraday with the Typhoeus adapter, for example.
[Learn more about Adapters](../adapters).
### 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. [Learn
more about Middleware](../middleware).
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
- retrying
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_middleware'
conn = Faraday.new do |f|
f.request :json # encode req bodies as JSON
f.request :retry # retry transient failures
f.response :follow_redirects # follow redirects
f.response :json # decode response bodies as JSON
end
response = conn.get("http://httpbingo.org/get")
```
#### Default Connection, Default Middleware
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.
Note that if you create your own connection with middleware, it won't encode
form bodies unless you too include the `:url_encoded` middleware!
[encoding]: ../middleware/url-encoded
[multipart]: ../middleware/multipart

View File

@ -1,37 +0,0 @@
---
layout: documentation
title: "Streaming Responses"
permalink: /usage/streaming
hide: true
top_name: Usage
top_link: ./
prev_name: Customizing the Request
prev_link: ./customize
---
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.get('/nigiri/sake.json') do |req|
# Set a callback which will receive tuples of chunk Strings
# and the sum of characters received so far
req.options.on_data = Proc.new do |chunk, overall_received_bytes|
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 the `Net::HTTP` adapter.

View File

@ -12,10 +12,15 @@ class Client
@conn = conn
end
def sushi(jname, params: {})
def httpbingo(jname, params: {})
res = @conn.get("/#{jname}", params)
data = JSON.parse(res.body)
data['name']
data['origin']
end
def foo(params)
res = @conn.post('/foo', JSON.dump(params))
res.status
end
end
@ -24,42 +29,42 @@ RSpec.describe Client do
let(:conn) { Faraday.new { |b| b.adapter(:test, stubs) } }
let(:client) { Client.new(conn) }
it 'parses name' do
stubs.get('/ebi') do |env|
it 'parses origin' do
stubs.get('/ip') do |env|
# optional: you can inspect the Faraday::Env
expect(env.url.path).to eq('/ebi')
expect(env.url.path).to eq('/ip')
[
200,
{ 'Content-Type': 'application/javascript' },
'{"name": "shrimp"}'
'{"origin": "127.0.0.1"}'
]
end
# uncomment to trigger stubs.verify_stubbed_calls failure
# stubs.get('/unused') { [404, {}, ''] }
expect(client.sushi('ebi')).to eq('shrimp')
expect(client.httpbingo('ip')).to eq('127.0.0.1')
stubs.verify_stubbed_calls
end
it 'handles 404' do
stubs.get('/ebi') do
stubs.get('/api') do
[
404,
{ 'Content-Type': 'application/javascript' },
'{}'
]
end
expect(client.sushi('ebi')).to be_nil
expect(client.httpbingo('api')).to be_nil
stubs.verify_stubbed_calls
end
it 'handles exception' do
stubs.get('/ebi') do
raise Faraday::ConnectionFailed, nil
stubs.get('/api') do
raise Faraday::ConnectionFailed
end
expect { client.sushi('ebi') }.to raise_error(Faraday::ConnectionFailed)
expect { client.httpbingo('api') }.to raise_error(Faraday::ConnectionFailed)
stubs.verify_stubbed_calls
end
@ -67,17 +72,47 @@ RSpec.describe Client do
let(:stubs) { Faraday::Adapter::Test::Stubs.new(strict_mode: true) }
it 'verifies the all parameter values are identical' do
stubs.get('/ebi?abc=123') do
stubs.get('/api?abc=123') do
[
200,
{ 'Content-Type': 'application/javascript' },
'{"name": "shrimp"}'
'{"origin": "127.0.0.1"}'
]
end
# uncomment to raise Stubs::NotFound
# expect(client.sushi('ebi', params: { abc: 123, foo: 'Kappa' })).to eq('shrimp')
expect(client.sushi('ebi', params: { abc: 123 })).to eq('shrimp')
# 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

View File

@ -13,24 +13,29 @@ class Client
@conn = conn
end
def sushi(jname)
res = @conn.get("/#{jname}")
def httpbingo(jname, params: {})
res = @conn.get("/#{jname}", params)
data = JSON.parse(res.body)
data['name']
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_sushi_name
def test_httpbingo_name
stubs = Faraday::Adapter::Test::Stubs.new
stubs.get('/ebi') do |env|
stubs.get('/api') do |env|
# optional: you can inspect the Faraday::Env
assert_equal '/ebi', env.url.path
assert_equal '/api', env.url.path
[
200,
{ 'Content-Type': 'application/javascript' },
'{"name": "shrimp"}'
'{"origin": "127.0.0.1"}'
]
end
@ -38,13 +43,13 @@ class ClientTest < Test::Unit::TestCase
# stubs.get('/unused') { [404, {}, ''] }
cli = client(stubs)
assert_equal 'shrimp', cli.sushi('ebi')
assert_equal '127.0.0.1', cli.httpbingo('api')
stubs.verify_stubbed_calls
end
def test_sushi_404
def test_httpbingo_not_found
stubs = Faraday::Adapter::Test::Stubs.new
stubs.get('/ebi') do
stubs.get('/api') do
[
404,
{ 'Content-Type': 'application/javascript' },
@ -53,23 +58,83 @@ class ClientTest < Test::Unit::TestCase
end
cli = client(stubs)
assert_nil cli.sushi('ebi')
assert_nil cli.httpbingo('api')
stubs.verify_stubbed_calls
end
def test_sushi_exception
def test_httpbingo_exception
stubs = Faraday::Adapter::Test::Stubs.new
stubs.get('/ebi') do
raise Faraday::ConnectionFailed, nil
stubs.get('/api') do
raise Faraday::ConnectionFailed
end
cli = client(stubs)
assert_raise Faraday::ConnectionFailed do
cli.sushi('ebi')
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

View File

@ -2,7 +2,7 @@
require_relative 'lib/faraday/version'
Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
Gem::Specification.new do |spec|
spec.name = 'faraday'
spec.version = Faraday::VERSION
@ -13,18 +13,17 @@ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
spec.homepage = 'https://lostisland.github.io/faraday'
spec.licenses = ['MIT']
spec.required_ruby_version = '>= 2.4'
spec.required_ruby_version = '>= 3.0'
spec.add_dependency 'faraday-em_http', '~> 1.0'
spec.add_dependency 'faraday-em_synchrony', '~> 1.0'
spec.add_dependency 'faraday-excon', '~> 1.1'
spec.add_dependency 'faraday-httpclient', '~> 1.0.1'
spec.add_dependency 'faraday-net_http', '~> 1.0'
spec.add_dependency 'faraday-net_http_persistent', '~> 1.1'
spec.add_dependency 'faraday-patron', '~> 1.0'
spec.add_dependency 'faraday-rack', '~> 1.0'
spec.add_dependency 'multipart-post', '>= 1.2', '< 3'
spec.add_dependency 'ruby2_keywords', '>= 0.0.4'
# 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'
# 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']
@ -34,6 +33,7 @@ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
'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'
'bug_tracker_uri' => 'https://github.com/lostisland/faraday/issues',
'rubygems_mfa_required' => 'true'
}
end

View File

@ -1,19 +1,14 @@
# frozen_string_literal: true
require 'cgi'
require 'cgi/escape'
require 'cgi/util' if RUBY_VERSION < '3.5'
require 'date'
require 'set'
require 'forwardable'
require 'faraday/middleware_registry'
require 'faraday/dependency_loader'
unless defined?(::Faraday::Timer)
require 'timeout'
::Faraday::Timer = Timeout
end
require 'faraday/version'
require 'faraday/methods'
require 'faraday/error'
require 'faraday/middleware_registry'
require 'faraday/utils'
require 'faraday/options'
require 'faraday/connection'
@ -23,21 +18,7 @@ require 'faraday/middleware'
require 'faraday/adapter'
require 'faraday/request'
require 'faraday/response'
require 'faraday/error'
require 'faraday/file_part'
require 'faraday/param_part'
unless defined?(JRUBY_VERSION)
require 'faraday/em_http'
require 'faraday/em_synchrony'
end
require 'faraday/excon'
require 'faraday/httpclient'
require 'faraday/net_http'
require 'faraday/net_http_persistent'
require 'faraday/patron'
require 'faraday/rack'
# This is the main namespace for Faraday.
#
# It provides methods to create {Connection} objects, and HTTP-related
@ -51,6 +32,8 @@ require 'faraday/rack'
# conn.get '/'
#
module Faraday
CONTENT_TYPE = 'Content-Type'
class << self
# The root path that Faraday is being loaded from.
#
@ -72,6 +55,10 @@ module Faraday
# @return [Symbol] the new default_adapter.
attr_reader :default_adapter
# Option for the default_adapter
# @return [Hash] default_adapter options
attr_accessor :default_adapter_options
# Documented below, see default_connection
attr_writer :default_connection
@ -108,23 +95,10 @@ module Faraday
# params: { page: 1 }
# # => Faraday::Connection to http://faraday.com?page=1
def new(url = nil, options = {}, &block)
options = default_connection_options.merge(options)
options = Utils.deep_merge(default_connection_options, options)
Faraday::Connection.new(url, options, &block)
end
# @private
# Internal: Requires internal Faraday libraries.
#
# @param libs [Array] one or more relative String names to Faraday classes.
# @return [void]
def require_libs(*libs)
libs.each do |lib|
require "#{lib_path}/#{lib}"
end
end
alias require_lib require_libs
# Documented elsewhere, see default_adapter reader
def default_adapter=(adapter)
@default_connection = nil
@ -180,6 +154,5 @@ module Faraday
self.root_path = File.expand_path __dir__
self.lib_path = File.expand_path 'faraday', __dir__
self.default_adapter = :net_http
require_lib 'autoload' unless ENV['FARADAY_NO_AUTOLOAD']
self.default_adapter_options = {}
end

View File

@ -5,14 +5,9 @@ module Faraday
# responsible for fulfilling a Faraday request.
class Adapter
extend MiddlewareRegistry
extend DependencyLoader
CONTENT_LENGTH = 'Content-Length'
register_middleware File.expand_path('adapter', __dir__),
test: [:Test, 'test'],
typhoeus: [:Typhoeus, 'typhoeus']
# This module marks an Adapter as supporting parallel requests.
module Parallelism
attr_writer :supports_parallel
@ -31,7 +26,7 @@ module Faraday
self.supports_parallel = false
def initialize(_app = nil, opts = {}, &block)
@app = ->(env) { env.response }
@app = lambda(&:response)
@connection_options = opts
@config_block = block
end
@ -64,7 +59,7 @@ module Faraday
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&.to_s&.strip
@ -73,7 +68,7 @@ module Faraday
yield(response_headers) if block_given?
end
env.response.finish(env) unless env.parallel?
env.response.finish(env) unless env.parallel? || !finished
env.response
end
@ -83,8 +78,7 @@ module Faraday
# @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, :open_timeout, or
# :timeout
# :read_timeout, :write_timeout, or :open_timeout
#
# @return [Integer, nil] Timeout duration in seconds, or nil if no timeout
# has been set.
@ -103,3 +97,5 @@ module Faraday
}.freeze
end
end
require 'faraday/adapter/test'

View File

@ -1,5 +1,7 @@
# frozen_string_literal: true
require 'timeout'
module Faraday
class Adapter
# @example
@ -26,6 +28,15 @@ module Faraday
# ]
# 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
@ -42,6 +53,12 @@ module Faraday
#
# 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
@ -55,6 +72,7 @@ module Faraday
@stack = {}
@consumed = {}
@strict_mode = strict_mode
@stubs_mutex = Monitor.new
yield(self) if block_given?
end
@ -62,18 +80,23 @@ module Faraday
@stack.empty?
end
def match(request_method, host, path, headers, body)
# @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)
@stubs_mutex.synchronize do
stub, meta = matches?(stack, env)
if stub
consumed << stack.delete(stub)
removed = stack.delete(stub)
consumed << removed unless removed.nil?
return stub, meta
end
matches?(consumed, host, path, headers, body)
end
matches?(consumed, env)
end
def get(path, headers = {}, &block)
@ -123,7 +146,7 @@ module Faraday
# 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 do |_method, stubs|
@stack.each_value do |stubs|
stubs.each do |stub|
stub.strict_mode = value
end
@ -142,15 +165,18 @@ module Faraday
Faraday::Utils.URI(path).host
]
end
path, query = normalized_path.respond_to?(:split) ? normalized_path.split('?') : normalized_path
headers = Utils::Headers.new(headers)
stub = Stub.new(host, normalized_path, headers, body, @strict_mode, 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
@ -158,36 +184,21 @@ module Faraday
end
# Stub request
# rubocop:disable Style/StructInheritance
class Stub < Struct.new(:host, :path, :params, :headers, :body, :strict_mode, :block)
# rubocop:enable Style/StructInheritance
def initialize(host, full, headers, body, strict_mode, block) # rubocop:disable Metrics/ParameterLists
path, query = full.respond_to?(:split) ? full.split('?') : full
params =
if query
Faraday::Utils.parse_nested_query(query)
else
{}
end
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]
super(host, path, params, headers, body, strict_mode, block)
end
def matches?(request_host, request_uri, request_headers, request_body)
request_path, request_query = request_uri.split('?')
request_params =
if request_query
Faraday::Utils.parse_nested_query(request_query)
else
{}
end
# meta is a hash used as carrier
# that will be yielded to consumer block
meta = {}
[(host.nil? || host == request_host) &&
path_match?(request_path, meta) &&
params_match?(request_params) &&
(body.to_s.size.zero? || request_body == body) &&
params_match?(env) &&
body_match?(request_body) &&
headers_match?(request_headers), meta]
end
@ -199,7 +210,11 @@ module Faraday
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
@ -224,6 +239,17 @@ module Faraday
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
@ -239,37 +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])
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]} "\
"#{normalized_path} #{env[:body]}"
raise Stubs::NotFound, "no stubbed request for #{env[:method]} " \
"#{env[:url]} #{env[:body]} #{env[:headers]}"
end
env[:params] = if (query = env[:url].query)
params_encoder.decode(query)
else
{}
end
block_arity = stub.block.arity
status, headers, body =
if block_arity >= 0
stub.block.call(*[env, meta].take(block_arity))
params = if block_arity >= 0
[env, meta].take(block_arity)
else
stub.block.call(env, meta)
[env, meta]
end
save_response(env, status, body, headers)
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,15 +0,0 @@
# frozen_string_literal: true
module Faraday
class Adapter
# Typhoeus adapter. This class is just a stub, the real adapter is in
# https://github.com/typhoeus/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

@ -1,87 +0,0 @@
# frozen_string_literal: true
module Faraday
# Adds the ability for other modules to manage autoloadable
# constants.
#
# @api private
module AutoloadHelper
# Registers the constants to be auto loaded.
#
# @param prefix [String] The require prefix. If the path is inside Faraday,
# then it will be prefixed with the root path of this loaded
# Faraday version.
# @param options [{ Symbol => String }] library names.
#
# @example
#
# Faraday.autoload_all 'faraday/foo',
# Bar: 'bar'
#
# # requires faraday/foo/bar to load Faraday::Bar.
# Faraday::Bar
#
# @return [void]
def autoload_all(prefix, options)
if prefix.match? %r{^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
# Loads each autoloaded constant. If thread safety is a concern,
# wrap this in a Mutex.
#
# @return [void]
def load_autoloaded_constants
constants.each do |const|
const_get(const) if autoload?(const)
end
end
# Filters the module's contents with those that have been already
# autoloaded.
#
# @return [Array<Class, Module>]
def all_loaded_constants
constants
.map { |c| const_get(c) }
.select { |a| a.respond_to?(:loaded?) && a.loaded? }
end
end
# Adapter is the base class for all Faraday adapters.
# @see lib/faraday/adapter.rb Original class location
class Adapter
extend AutoloadHelper
autoload_all 'faraday/adapter',
Typhoeus: 'typhoeus',
Test: 'test'
end
# Request represents a single HTTP request for a Faraday adapter to make.
# @see lib/faraday/request.rb Original class location
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
# Response represents the returned value of a sent Faraday request.
# @see lib/faraday/response.rb Original class location
class Response
extend AutoloadHelper
autoload_all 'faraday/response',
RaiseError: 'raise_error',
Logger: 'logger'
end
end

View File

@ -6,16 +6,16 @@ module Faraday
#
# @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 %i[get post put delete head patch options trace]
USER_AGENT = "Faraday v#{VERSION}"
USER_AGENT = "Faraday v#{VERSION}".freeze
# @return [Hash] URI query unencoded key/value pairs.
attr_reader :params
@ -64,7 +64,7 @@ module Faraday
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
@ -117,7 +117,7 @@ module Faraday
extend Forwardable
def_delegators :builder, :build, :use, :request, :response, :adapter, :app
def_delegators :builder, :use, :request, :response, :adapter, :app
# Closes the underlying resources and/or connections. In the case of
# persistent connections, this closes all currently open connections
@ -130,10 +130,10 @@ module Faraday
# Makes a GET HTTP request without a body.
# @!scope class
#
# @param url [String] The optional String base URL to use as a prefix for
# @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] Hash of URI query unencoded key/value pairs.
# @param headers [Hash] unencoded HTTP header key/value pairs.
# @param params [Hash, nil] Hash of URI query unencoded key/value pairs.
# @param headers [Hash, nil] unencoded HTTP header key/value pairs.
#
# @example
# conn.get '/items', { page: 1 }, :accept => 'application/json'
@ -152,10 +152,10 @@ module Faraday
# Makes a HEAD HTTP request without a body.
# @!scope class
#
# @param url [String] The optional String base URL to use as a prefix for
# @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] Hash of URI query unencoded key/value pairs.
# @param headers [Hash] unencoded HTTP header key/value pairs.
# @param params [Hash, nil] Hash of URI query unencoded key/value pairs.
# @param headers [Hash, nil] unencoded HTTP header key/value pairs.
#
# @example
# conn.head '/items/1'
@ -167,10 +167,10 @@ module Faraday
# Makes a DELETE HTTP request without a body.
# @!scope class
#
# @param url [String] The optional String base URL to use as a prefix for
# @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] Hash of URI query unencoded key/value pairs.
# @param headers [Hash] unencoded HTTP header key/value pairs.
# @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'
@ -182,10 +182,10 @@ module Faraday
# Makes a TRACE HTTP request without a body.
# @!scope class
#
# @param url [String] The optional String base URL to use as a prefix for
# @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] Hash of URI query unencoded key/value pairs.
# @param headers [Hash] unencoded HTTP header key/value pairs.
# @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'
@ -210,9 +210,9 @@ module Faraday
#
# @overload options(url, params = nil, headers = nil)
# Makes an OPTIONS HTTP request to the given URL.
# @param url [String] String base URL to sue as a prefix for all requests.
# @param params [Hash] Hash of URI query unencoded key/value pairs.
# @param headers [Hash] unencoded HTTP header key/value pairs.
# @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.
#
# @example
# conn.options '/items/1'
@ -220,7 +220,7 @@ module Faraday
# @yield [Faraday::Request] for further request customizations
# @return [Faraday::Response]
def options(*args)
return @options if args.size.zero?
return @options if args.empty?
url, params, headers = *args
run_request(:options, url, nil, headers) do |request|
@ -233,10 +233,10 @@ module Faraday
# Makes a POST HTTP request with a body.
# @!scope class
#
# @param url [String] The optional String base URL to use as a prefix for
# @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] body for the request.
# @param headers [Hash] unencoded HTTP header key/value pairs.
# @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'
@ -255,20 +255,19 @@ module Faraday
# Makes a PUT HTTP request with a body.
# @!scope class
#
# @param url [String] The optional String base URL to use as a prefix for
# @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] body for the request.
# @param headers [Hash] unencoded HTTP header key/value pairs.
# @param body [String, nil] body for the request.
# @param headers [Hash, nil] unencoded HTTP header key/value pairs.
#
# @example
# # TODO: Make it a PUT example
# conn.post '/items', data, content_type: 'application/json'
# conn.put '/products/123', 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', ...)
# # 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
@ -283,77 +282,6 @@ module Faraday
RUBY
end
# Sets up the Authorization header with these credentials, encoded
# with base64.
#
# @param login [String] The authentication login.
# @param pass [String] The authentication password.
#
# @example
#
# conn.basic_auth 'Aladdin', 'open sesame'
# conn.headers['Authorization']
# # => "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
#
# @return [void]
def basic_auth(login, pass)
warn <<~TEXT
WARNING: `Faraday::Connection#basic_auth` is deprecated; it will be removed in version 2.0.
While initializing your connection, use `#request(:basic_auth, ...)` instead.
See https://lostisland.github.io/faraday/middleware/authentication for more usage info.
TEXT
set_authorization_header(:basic_auth, login, pass)
end
# Sets up the Authorization header with the given token.
#
# @param token [String]
# @param options [Hash] extra token options.
#
# @example
#
# conn.token_auth 'abcdef', foo: 'bar'
# conn.headers['Authorization']
# # => "Token token=\"abcdef\",
# foo=\"bar\""
#
# @return [void]
def token_auth(token, options = nil)
warn <<~TEXT
WARNING: `Faraday::Connection#token_auth` is deprecated; it will be removed in version 2.0.
While initializing your connection, use `#request(:token_auth, ...)` instead.
See https://lostisland.github.io/faraday/middleware/authentication for more usage info.
TEXT
set_authorization_header(:token_auth, token, options)
end
# Sets up a custom Authorization header.
#
# @param type [String] authorization type
# @param token [String, Hash] token. A String value is taken literally, and
# a Hash is encoded into comma-separated key/value pairs.
#
# @example
#
# 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\""
#
# @return [void]
def authorization(type, token)
warn <<~TEXT
WARNING: `Faraday::Connection#authorization` is deprecated; it will be removed in version 2.0.
While initializing your connection, use `#request(:authorization, ...)` instead.
See https://lostisland.github.io/faraday/middleware/authentication for more usage info.
TEXT
set_authorization_header(:authorization, type, token)
end
# Check if the adapter is parallel-capable.
#
# @yield if the adapter isn't parallel-capable, or if no adapter is set yet.
@ -386,15 +314,23 @@ module Faraday
#
# @yield a block to execute multiple requests.
# @return [void]
def in_parallel(manager = nil)
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
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
@parallel_manager.run
end
ensure
@parallel_manager = nil
end
@ -420,11 +356,11 @@ module Faraday
# @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
# 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
@ -433,13 +369,18 @@ 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
@proxy = proxy_from_env(url) unless @manual_proxy
end
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.
#
@ -456,20 +397,20 @@ module Faraday
# Takes a relative url for a request and combines it with the defaults
# set on the connection instance.
#
# @param url [String]
# @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
# # => https://httpbingo.org/api/nigiri?token=abc&page=2
#
# conn.build_url("nigiri", page: 2)
# # => https://sushi.com/api/nigiri?token=abc&page=2
# # => https://httpbingo.org/api/nigiri?token=abc&page=2
#
def build_url(url = nil, extra_params = nil)
uri = build_exclusive_url(url)
@ -489,10 +430,10 @@ module Faraday
# Builds and runs the Faraday::Request.
#
# @param method [Symbol] HTTP method.
# @param url [String, URI] String or URI to access.
# @param body [Object] The request body that will eventually be converted to
# a string.
# @param headers [Hash] unencoded HTTP header key/value pairs.
# @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.
#
# @return [Faraday::Response]
def run_request(method, url, body, headers)
@ -528,7 +469,7 @@ module Faraday
# Build an absolute URL based on url_prefix.
#
# @param url [String, URI]
# @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).
@ -537,17 +478,16 @@ module Faraday
def build_exclusive_url(url = nil, params = nil, params_encoder = nil)
url = nil if url.respond_to?(:empty?) && url.empty?
base = url_prefix.dup
if url && base.path && base.path !~ %r{/$}
if url && !base.path.end_with?('/')
base.path = "#{base.path}/" # ensure trailing slash
end
url = url && URI.parse(url.to_s).opaque ? url.to_s.gsub(':', '%3A') : url
# 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
if params
uri.query = params.to_query(params_encoder || options.params_encoder)
end
# rubocop:disable Style/SafeNavigation
uri.query = nil if uri.query && uri.query.empty?
# rubocop:enable Style/SafeNavigation
uri
end
@ -579,19 +519,10 @@ module Faraday
yield(Utils.unescape(uri.user), Utils.unescape(uri.password))
end
def set_authorization_header(header_type, *args)
header = Faraday::Request
.lookup_middleware(header_type)
.header(*args)
headers[Faraday::Request::Authorization::KEY] = header
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)
@ -605,15 +536,11 @@ module Faraday
when nil
uri = find_default_proxy
end
else
warn 'no_proxy is unsupported' if ENV['no_proxy'] || ENV['NO_PROXY']
uri = find_default_proxy
end
ProxyOptions.from(uri) if uri
end
def find_default_proxy
uri = ENV['http_proxy']
uri = ENV.fetch('http_proxy', nil)
return unless uri && !uri.empty?
uri = "http://#{uri}" unless uri.match?(/^http/i)
@ -631,7 +558,7 @@ module Faraday
end
def support_parallel?(adapter)
adapter&.respond_to?(:supports_parallel?) && adapter&.supports_parallel?
adapter.respond_to?(:supports_parallel?) && adapter&.supports_parallel?
end
end
end

View File

@ -1,37 +0,0 @@
# frozen_string_literal: true
module Faraday
# DependencyLoader helps Faraday adapters and middleware load dependencies.
module DependencyLoader
attr_reader :load_error
# Executes a block which should try to require and reference dependent
# libraries
def dependency(lib = nil)
lib ? require(lib) : yield
rescue LoadError, NameError => e
self.load_error = e
end
def new(*)
unless loaded?
raise "missing dependency for #{self}: #{load_error.message}"
end
super
end
def loaded?
load_error.nil?
end
def inherited(subclass)
super
subclass.send(:load_error=, load_error)
end
private
attr_writer :load_error
end
end

View File

@ -62,11 +62,17 @@ module Faraday
end
def encode_array(parent, value)
new_parent = "#{parent}%5B%5D"
return new_parent if value.empty?
return "#{parent}%5B%5D" if value.empty?
buffer = +''
value.each { |val| buffer << "#{encode_pair(new_parent, val)}&" }
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
@ -96,13 +102,13 @@ module Faraday
protected
SUBKEYS_REGEX = /[^\[\]]+(?:\]?\[\])?/.freeze
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 = $` if is_array
subkey = Regexp.last_match.pre_match if is_array
last_subkey = i == subkeys.length - 1
context = prepare_context(context, subkey, is_array, last_subkey)
@ -161,7 +167,7 @@ module Faraday
# for your requests.
module NestedParamsEncoder
class << self
attr_accessor :sort_params
attr_accessor :sort_params, :array_indices
extend Forwardable
def_delegators :'Faraday::Utils', :escape, :unescape
@ -169,6 +175,7 @@ module Faraday
# Useful default for OAuth and caching.
@sort_params = true
@array_indices = false
extend EncodeMethods
extend DecodeMethods

View File

@ -6,7 +6,7 @@ module Faraday
class Error < StandardError
attr_reader :response, :wrapped_exception
def initialize(exc, response = nil)
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))
@ -29,15 +29,21 @@ module Faraday
end
def response_status
@response[:status] if @response
return unless @response
@response.is_a?(Faraday::Response) ? @response.status : @response[:status]
end
def response_headers
@response[:headers] if @response
return unless @response
@response.is_a?(Faraday::Response) ? @response.headers : @response[:headers]
end
def response_body
@response[:body] if @response
return unless @response
@response.is_a?(Faraday::Response) ? @response.body : @response[:body]
end
protected
@ -52,6 +58,7 @@ module Faraday
# :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.
@ -72,15 +79,49 @@ module Faraday
# Pulls out potential parent exception and response hash.
def exc_msg_and_response(exc, response = nil)
return [exc, exc.message, response] if exc.respond_to?(:backtrace)
return [nil, "the server responded with status #{exc[:status]}", exc] \
if exc.respond_to?(:each_key)
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
# Faraday client error class. Represents 4xx status responses.
class ClientError < Error
end
@ -105,6 +146,10 @@ module Faraday
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
@ -113,6 +158,10 @@ module Faraday
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
@ -140,13 +189,11 @@ module Faraday
class SSLError < Error
end
# Raised by FaradayMiddleware::ResponseMiddleware
# Raised by middlewares that parse the response, like the JSON response middleware.
class ParsingError < Error
end
# Exception used to control the Retry middleware.
#
# @see Faraday::Request::Retry
class RetriableResponse < Error
# Raised by Faraday::Middleware and subclasses when invalid default_options are used
class InitializationError < Error
end
end

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