philiprehberger-http_client 0.12.0 → 0.13.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: 211aea712ab77e8a14f5a565d0a235113b1b5a5630e38e13ddcfb2f92c61b141
4
- data.tar.gz: d9a7e6996c9ca7cc6ba296c837db466cdc692abb489bb179c24aea3e888e274b
3
+ metadata.gz: a22fdf41ff535b768c6ac9783ad358b8367cf7aa9f666368cd098c30ef36231c
4
+ data.tar.gz: 62bb80048febfa5be44bfef001cd082bf447866a2a4d5afe76717e2e829e9423
5
5
  SHA512:
6
- metadata.gz: 9cf88a13252d7b73c94b747a0ce54cc5027dbdb28aceaefeca3cf5c4d5c2818b09d8b7b9c92e7cbda000a8343fda30aff88f9110a0d96eccb0b9cada3e84d67e
7
- data.tar.gz: 716b066adc90993966528dc3100dcb1b6d4e9130926673ee1279d2931e2f0089a2f0999e22fcfade122e9afd1a641e2e7a6c566594845efd8864ac9b0683bfdf
6
+ metadata.gz: 75d9a2a474f77b8358ea76fb131acdcb2f11c9fdc31b46d4dc65ec6364139de9e6fd66b085f65b294afde442b0e9b12a73c1775cbc5c7ad2f3275544bb5d58ae
7
+ data.tar.gz: f728d0e5d12a7642e098c75fca3af7ef75aff526329982678e224c4917cd921164170319db294ad33ba1ca3bd923f39b442082bbb17f8a1fd8140873125325ce
data/CHANGELOG.md CHANGED
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.13.0] - 2026-10-30
11
+
12
+ ### Added
13
+ - `Response#raise_for_status!` — returns `self` on 2xx/3xx responses and raises `HttpError` (with `.response`) on 4xx/5xx, enabling chained calls like `client.get(path).raise_for_status!.json`
14
+ - `Response#content_type` — media type from the `Content-Type` header without parameters (e.g. `"application/json"`), `nil` if absent
15
+ - `Response#content_length` — `Content-Length` header as an Integer, `nil` if absent or invalid
16
+
17
+ ### Changed
18
+ - Aligned `.gitignore` with the standard gem template
19
+ - Aligned CI workflow with the standard template (`ruby` matrix key, glob gemspec in build/push)
20
+
10
21
  ## [0.12.0] - 2026-07-15
11
22
 
12
23
  ### Added
@@ -211,7 +222,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
211
222
  - Response wrapper with `ok?` and `json` convenience methods
212
223
  - Zero dependencies — built on Ruby stdlib `net/http`
213
224
 
214
- [Unreleased]: https://github.com/philiprehberger/rb-http-client/compare/v0.12.0...HEAD
225
+ [Unreleased]: https://github.com/philiprehberger/rb-http-client/compare/v0.13.0...HEAD
226
+ [0.13.0]: https://github.com/philiprehberger/rb-http-client/compare/v0.12.0...v0.13.0
215
227
  [0.12.0]: https://github.com/philiprehberger/rb-http-client/compare/v0.11.1...v0.12.0
216
228
  [0.11.1]: https://github.com/philiprehberger/rb-http-client/compare/v0.11.0...v0.11.1
217
229
  [0.11.0]: https://github.com/philiprehberger/rb-http-client/compare/v0.10.0...v0.11.0
data/README.md CHANGED
@@ -467,6 +467,25 @@ response.header("etag") # works for any casing
467
467
  response.header("X-Missing") # => nil
468
468
  ```
469
469
 
470
+ ### Content metadata and status checks
471
+
472
+ `Response#content_type` returns the media type without parameters, `Response#content_length` parses the `Content-Length` header, and `Response#raise_for_status!` raises `HttpError` on 4xx/5xx while returning the response otherwise:
473
+
474
+ ```ruby
475
+ response = client.get("/report")
476
+
477
+ response.content_type # => "application/json" (from "application/json; charset=utf-8")
478
+ response.content_length # => 2048, or nil if the header is absent
479
+
480
+ data = client.get("/users").raise_for_status!.json
481
+
482
+ begin
483
+ client.get("/missing").raise_for_status!
484
+ rescue Philiprehberger::HttpClient::HttpError => e
485
+ e.response.status # => 404
486
+ end
487
+ ```
488
+
470
489
  ## API
471
490
 
472
491
  ### `Philiprehberger::HttpClient.new(**options)`
@@ -545,6 +564,9 @@ response.header("X-Missing") # => nil
545
564
  | `server_error?` | Boolean | Returns true for 5xx status codes |
546
565
  | `json` | Hash | Parsed JSON body |
547
566
  | `json?` | Boolean | `true` if `Content-Type` is `application/json` or `+json` suffix |
567
+ | `content_type` | String | Media type without parameters (e.g. `"application/json"`), `nil` if absent |
568
+ | `content_length` | Integer | `Content-Length` header as an Integer, `nil` if absent or invalid |
569
+ | `raise_for_status!` | Response | Returns `self` on 1xx-3xx, raises `HttpError` (with `.response`) on 4xx/5xx |
548
570
  | `streaming?` | Boolean | `true` if response was streamed |
549
571
  | `metrics` | Metrics | Request timing breakdown (total_time, first_byte_time, etc.) |
550
572
  | `redirects` | Array | Redirect chain URLs (empty if no redirects) |
@@ -83,6 +83,45 @@ module Philiprehberger
83
83
  primary == 'application/json' || primary.end_with?('+json')
84
84
  end
85
85
 
86
+ # Returns the media type from the `Content-Type` header without any
87
+ # parameters (e.g. `"application/json"` for
88
+ # `"application/json; charset=utf-8"`). The value is downcased.
89
+ #
90
+ # @return [String, nil] the media type, or `nil` if the header is absent or blank
91
+ def content_type
92
+ value = header('content-type')
93
+ return nil if value.nil?
94
+
95
+ media_type = value.to_s.split(';').first.to_s.strip.downcase
96
+ media_type.empty? ? nil : media_type
97
+ end
98
+
99
+ # Returns the `Content-Length` header as an Integer.
100
+ #
101
+ # @return [Integer, nil] the declared body length, or `nil` if the header
102
+ # is absent or not a valid non-negative integer
103
+ def content_length
104
+ value = header('content-length')
105
+ return nil if value.nil?
106
+
107
+ length = Integer(value.to_s.strip, 10, exception: false)
108
+ length&.negative? ? nil : length
109
+ end
110
+
111
+ # Raises {HttpError} if the response has a 4xx or 5xx status code.
112
+ # Returns `self` otherwise so the call can be chained.
113
+ #
114
+ # @example
115
+ # data = client.get('/users').raise_for_status!.json
116
+ #
117
+ # @return [self]
118
+ # @raise [HttpError] if the status code is 400 or greater
119
+ def raise_for_status!
120
+ raise HttpError, self if status >= 400
121
+
122
+ self
123
+ end
124
+
86
125
  # Returns request timing metrics (nil if not available).
87
126
  #
88
127
  # @return [Metrics, nil]
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Philiprehberger
4
4
  module HttpClient
5
- VERSION = '0.12.0'
5
+ VERSION = '0.13.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: philiprehberger-http_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Philip Rehberger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-07-16 00:00:00.000000000 Z
11
+ date: 2026-10-30 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A zero-dependency HTTP client built on Ruby's net/http with automatic
14
14
  retries, request/response interceptors, and a clean API for JSON services.