rest-easy 1.1.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ec1e2b4f51ad07119add9f89dd2075a765fa2fc258766294aa7b05c1bc4e2951
4
- data.tar.gz: 350b2381fd3e0dd4cde1815000684c474238ed5c5f8d438611a8fb5de9e381b8
3
+ metadata.gz: c9ea82724f82c4030a6844a7bad0eec6abe406c1dbdb7d75697431f7273cafd4
4
+ data.tar.gz: 704c05fc995113d8aeacf92d86c55d0d6acb4d034ac0f98016bca627ed9b0156
5
5
  SHA512:
6
- metadata.gz: 358c1e91aca70417fc86738b71078bf931da0a562f3ea102875e25d6c32e117c0663337770b39bfc0bf978022dec0eafea220cf27c83e86f9f63f5c3038f6d99
7
- data.tar.gz: 0b6d24c285a668c5dde3a90168d542c60b7b8008f20a75d39579c058448e8dd31482f23bda5fa770c25909736b43804cd03a591f7813345a0aabeccc75ad7b26
6
+ metadata.gz: 73c06f4654242606bd99af1b1f75f8feb3cf6cea6973513cc54d5ad6e7d62cf0e2ea783e62b1676c8c9e33adbf95c0bd3062c1df9aa79cd84a2618f95de8c342
7
+ data.tar.gz: eedad48faafdac8442419d1890e06632e0d92fac7d7946714d9dea9cad0ab30e5917f119ec7393858ad73e70bfc169ea18d9cd3e633356a0c39e9513c8154249
data/CHANGELOG.md CHANGED
@@ -2,6 +2,27 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [1.3.0] - 2026-05-19
6
+
7
+ ### Added
8
+
9
+ - `base64` is now an explicit runtime dependency. It stopped being a
10
+ default gem in Ruby 3.4, so it must be declared for the basic-auth
11
+ strategy to load.
12
+
13
+ ### Changed
14
+
15
+ - **Minimum Ruby version raised to 3.2.** Ruby 3.1 reached end-of-life
16
+ in March 2025 and is no longer supported or tested. Consumers on Ruby
17
+ 3.1 are held at the previous release by Bundler.
18
+
19
+ ## [1.2.0] - 2026-05-17
20
+
21
+ ### Added
22
+
23
+ - **`logger` setting.** When set to a `Logger`-compatible instance, Faraday's built-in logger middleware is attached to the connection and logs HTTP request/response lines and headers. Unset by default — no overhead when not in use. The standard auth-bearing headers (`Authorization`, `Proxy-Authorization`, `Cookie`, `Set-Cookie`) are always filtered to `[FILTERED]`; consumer gems are responsible for redacting domain-specific secrets in non-standard headers or response bodies (see README "Redacting domain-specific secrets").
24
+ - **`log_bodies` setting** (default `false`). Opt-in toggle for logging request/response bodies. Off by default because bodies often carry domain-specific secrets that RestEasy cannot recognize.
25
+
5
26
  ## [1.1.2] - 2026-05-15
6
27
 
7
28
  ### Changed
@@ -48,7 +69,9 @@
48
69
 
49
70
  Initial release.
50
71
 
51
- [Unreleased]: https://github.com/accodeing/rest-easy/compare/v1.1.2...HEAD
72
+ [Unreleased]: https://github.com/accodeing/rest-easy/compare/v1.3.0...HEAD
73
+ [1.3.0]: https://github.com/accodeing/rest-easy/compare/v1.2.0...v1.3.0
74
+ [1.2.0]: https://github.com/accodeing/rest-easy/compare/v1.1.2...v1.2.0
52
75
  [1.1.2]: https://github.com/accodeing/rest-easy/compare/v1.1.1...v1.1.2
53
76
  [1.1.1]: https://github.com/accodeing/rest-easy/compare/v1.1.0...v1.1.1
54
77
  [1.1.0]: https://github.com/accodeing/rest-easy/compare/v1.0.0...v1.1.0
data/README.md CHANGED
@@ -20,7 +20,7 @@ Or your Gemfile:
20
20
  gem "rest-easy", "~> 1.0"
21
21
  ```
22
22
 
23
- Requires Ruby >= 3.1.
23
+ Requires Ruby >= 3.2.
24
24
 
25
25
  ## Quick start
26
26
 
@@ -92,17 +92,100 @@ end
92
92
 
93
93
  ### Available settings
94
94
 
95
- | Setting | Default | Description |
96
- |----------------------------------|----------------------------|---------------------------------------------------|
97
- | `base_url` | `"https://example.com"` | Base URL for all requests |
98
- | `max_retries` | `3` | Retry count on request failure |
99
- | `authentication` | `Auth::Null.new` | Authentication strategy |
100
- | `conversions.json_attributes` | `:PascalCase` | Naming convention for JSON response/request fields|
101
- | `conversions.query_parameters` | `nil` (no transformation) | Naming convention for query parameter keys |
95
+ | Setting | Default | Description |
96
+ |----------------------------------|----------------------------|--------------------------------------------------------------------------------------------|
97
+ | `authentication` | `Auth::Null.new` | Authentication strategy |
98
+ | `base_url` | `"https://example.com"` | Base URL for all requests |
99
+ | `conversions.json_attributes` | `:PascalCase` | Naming convention for JSON response/request fields |
100
+ | `conversions.query_parameters` | `nil` (no transformation) | Naming convention for query parameter keys |
101
+ | `log_bodies` | `false` | When `true`, request/response bodies are logged. Off by default to avoid leaking domain secrets |
102
+ | `logger` | `nil` | When set, attaches Faraday's logger middleware and writes HTTP request/response details to it |
103
+ | `max_retries` | `3` | Retry count on request failure |
104
+
105
+ ### Logging HTTP traffic
106
+
107
+ Set `logger` to any `Logger`-compatible instance to log HTTP request and response details. The middleware is Faraday's built-in `Faraday::Response::Logger` and is only attached when the setting is non-nil — no overhead when unset.
108
+
109
+ ```ruby
110
+ module Acme
111
+ extend RestEasy
112
+
113
+ configure do |config|
114
+ config.logger = Logger.new($stdout)
115
+ end
116
+ end
117
+ ```
118
+
119
+ By default, RestEasy logs request/response **lines and headers only**, with the following standard headers always filtered to `[FILTERED]`:
120
+
121
+ - `Authorization`
122
+ - `Proxy-Authorization`
123
+ - `Cookie`
124
+ - `Set-Cookie`
125
+
126
+ Request and response **bodies are not logged by default**, because bodies frequently carry API-specific secrets (OAuth token responses, signed payloads, PII) that RestEasy has no way to recognize.
127
+
128
+ > **Note:** The Faraday connection is built lazily on the first request and cached for the lifetime of the process. Changes to `logger` or `log_bodies` after the first request take effect only after restart.
129
+
130
+ #### Logging request/response bodies
131
+
132
+ If your API's bodies are safe to log — or you've added domain-specific scrubbing (see below) — opt in:
133
+
134
+ ```ruby
135
+ module Acme
136
+ extend RestEasy
137
+
138
+ configure do |config|
139
+ config.logger = Logger.new($stdout)
140
+ config.log_bodies = true
141
+ end
142
+ end
143
+ ```
144
+
145
+ #### Redacting domain-specific secrets
146
+
147
+ RestEasy only knows about HTTP-standard auth headers. If your API returns secrets in response bodies (e.g. an access-token endpoint), or uses non-standard headers like `X-Acme-Api-Key`, your consumer gem is responsible for scrubbing them. The simplest pattern is to wrap the `Logger` instance before handing it to RestEasy — sketched here as a `SimpleDelegator`:
148
+
149
+ ```ruby
150
+ # Sketch — wrap the Logger in your gem so it scrubs your
151
+ # domain secrets out of each line before it's written.
152
+
153
+ class RedactingLogger < SimpleDelegator
154
+ # ...your scrubbing logic, applied to each log message...
155
+ end
156
+
157
+ module Acme
158
+ extend RestEasy
159
+
160
+ configure do |config|
161
+ config.logger = RedactingLogger.new(Logger.new($stdout))
162
+ config.log_bodies = true
163
+ end
164
+ end
165
+ ```
166
+
167
+ #### Exposing a debug switch in your consumer gem
168
+
169
+ RestEasy does not read any environment variable itself — that decision belongs to the gem that wraps it. If you want consumers of your gem to flip logging on without editing code, expose your own env var and wire it to `config.logger`:
170
+
171
+ ```ruby
172
+ module Acme
173
+ extend RestEasy
174
+
175
+ configure do |config|
176
+ if ENV["ACME_DEBUG"]
177
+ config.logger = RedactingLogger.new(Logger.new($stdout))
178
+ config.log_bodies = true
179
+ end
180
+ end
181
+ end
182
+ ```
183
+
184
+ Now `ACME_DEBUG=1 bundle exec ...` turns on wire logging — with Acme-aware scrubbing — without any code changes in the consuming application.
102
185
 
103
186
  ### Faraday middleware
104
187
 
105
- Configure the underlying Faraday connection with a `connection` block:
188
+ For middleware beyond the built-in logger, configure the underlying Faraday connection with a `connection` block:
106
189
 
107
190
  ```ruby
108
191
  module Acme
@@ -6,14 +6,16 @@ module RestEasy
6
6
  class Settings
7
7
  extend Dry::Configurable
8
8
 
9
+ setting :attribute_convention # deprecated — propagated to conversions.json_attributes in configure
10
+ setting :authentication, default: Auth::Null.new, reader: true
9
11
  setting :base_url, default: "https://example.com", reader: true
12
+ setting :log_bodies, default: false, reader: true
13
+ setting :logger, reader: true
10
14
  setting :max_retries, default: 3, reader: true
11
- setting :authentication, default: Auth::Null.new, reader: true
12
- setting :attribute_convention # deprecated — propagated to conversions.json_attributes in configure
13
15
 
14
16
  setting :conversions do
15
- setting :query_parameters, default: nil, reader: true
16
17
  setting :json_attributes, default: Conventions::DEFAULT, reader: true
18
+ setting :query_parameters, default: nil, reader: true
17
19
  end
18
20
  end
19
21
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RestEasy
4
- VERSION = "1.1.2"
4
+ VERSION = "1.3.0"
5
5
  end
data/lib/rest_easy.rb CHANGED
@@ -66,6 +66,9 @@ module RestEasy
66
66
  # ── Module extension (ClassMethods) ──────────────────────────────────
67
67
 
68
68
  module ClassMethods
69
+ STANDARD_AUTH_HEADERS = %w[Authorization Proxy-Authorization Cookie Set-Cookie].freeze
70
+ private_constant :STANDARD_AUTH_HEADERS
71
+
69
72
  def config
70
73
  self::Settings.config
71
74
  end
@@ -107,6 +110,16 @@ module RestEasy
107
110
  @faraday_connection ||= Faraday.new(url: config.base_url) do |f|
108
111
  f.request :json
109
112
  f.response :json
113
+ if config.logger
114
+ # Faraday's logger emits headers as `Name: "value"` — the filters
115
+ # depend on that format. If the format changes, redaction silently
116
+ # breaks; the integration specs catch the common case.
117
+ f.response :logger, config.logger, bodies: config.log_bodies do |l|
118
+ STANDARD_AUTH_HEADERS.each do |name|
119
+ l.filter(/(#{Regexp.escape(name)}:\s*")[^"]+/i, '\1[FILTERED]')
120
+ end
121
+ end
122
+ end
110
123
  @connection_block&.call(f)
111
124
  end
112
125
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rest-easy
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonas Schubert Erlandsson
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2026-05-15 00:00:00.000000000 Z
13
+ date: 2026-05-19 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: dry-types
@@ -68,6 +68,20 @@ dependencies:
68
68
  - - "~>"
69
69
  - !ruby/object:Gem::Version
70
70
  version: '2.0'
71
+ - !ruby/object:Gem::Dependency
72
+ name: base64
73
+ requirement: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - "~>"
76
+ - !ruby/object:Gem::Version
77
+ version: '0.2'
78
+ type: :runtime
79
+ prerelease: false
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - "~>"
83
+ - !ruby/object:Gem::Version
84
+ version: '0.2'
71
85
  - !ruby/object:Gem::Dependency
72
86
  name: bundler
73
87
  requirement: !ruby/object:Gem::Requirement
@@ -145,14 +159,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
145
159
  requirements:
146
160
  - - ">="
147
161
  - !ruby/object:Gem::Version
148
- version: 3.1.0
162
+ version: 3.2.0
149
163
  required_rubygems_version: !ruby/object:Gem::Requirement
150
164
  requirements:
151
165
  - - ">="
152
166
  - !ruby/object:Gem::Version
153
167
  version: '0'
154
168
  requirements: []
155
- rubygems_version: 3.4.6
169
+ rubygems_version: 3.4.19
156
170
  signing_key:
157
171
  specification_version: 4
158
172
  summary: Boilerplate for REST API libraries, using on dry-rb