rest-easy 1.1.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ec1e2b4f51ad07119add9f89dd2075a765fa2fc258766294aa7b05c1bc4e2951
4
- data.tar.gz: 350b2381fd3e0dd4cde1815000684c474238ed5c5f8d438611a8fb5de9e381b8
3
+ metadata.gz: c5f42d44a6677ffb6553237d5be80fc7247a6501946069ee1034b0811a4b6219
4
+ data.tar.gz: 858f63be66e21f33873ea74467eb411215d213c921acab98c489d6db03734fdd
5
5
  SHA512:
6
- metadata.gz: 358c1e91aca70417fc86738b71078bf931da0a562f3ea102875e25d6c32e117c0663337770b39bfc0bf978022dec0eafea220cf27c83e86f9f63f5c3038f6d99
7
- data.tar.gz: 0b6d24c285a668c5dde3a90168d542c60b7b8008f20a75d39579c058448e8dd31482f23bda5fa770c25909736b43804cd03a591f7813345a0aabeccc75ad7b26
6
+ metadata.gz: 5249f3a12786557b868a420b07778c5e8ce17feefc72a8e5e093fcca6c6390caf8113eebd8746c6e3dfb7150b80547c6bdaf38584004f760e2fea6b743c1c060
7
+ data.tar.gz: 2453b54cb4e35ffb47d60dec50417c9d3869f9a8ae10594ca19c2c9dc5c1462254b5792ecf7d0f7e4d03520d0242e72d9e3728daf92135e20509509eeb95867d
data/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [1.2.0] - 2026-05-17
6
+
7
+ ### Added
8
+
9
+ - **`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").
10
+ - **`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.
11
+
5
12
  ## [1.1.2] - 2026-05-15
6
13
 
7
14
  ### Changed
@@ -48,7 +55,8 @@
48
55
 
49
56
  Initial release.
50
57
 
51
- [Unreleased]: https://github.com/accodeing/rest-easy/compare/v1.1.2...HEAD
58
+ [Unreleased]: https://github.com/accodeing/rest-easy/compare/v1.2.0...HEAD
59
+ [1.2.0]: https://github.com/accodeing/rest-easy/compare/v1.1.2...v1.2.0
52
60
  [1.1.2]: https://github.com/accodeing/rest-easy/compare/v1.1.1...v1.1.2
53
61
  [1.1.1]: https://github.com/accodeing/rest-easy/compare/v1.1.0...v1.1.1
54
62
  [1.1.0]: https://github.com/accodeing/rest-easy/compare/v1.0.0...v1.1.0
data/README.md CHANGED
@@ -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.2.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.2.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-17 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: dry-types