philiprehberger-http_client 0.1.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 +7 -0
- data/CHANGELOG.md +20 -0
- data/LICENSE +21 -0
- data/README.md +127 -0
- data/lib/philiprehberger/http_client/client.rb +105 -0
- data/lib/philiprehberger/http_client/connection.rb +91 -0
- data/lib/philiprehberger/http_client/response.rb +35 -0
- data/lib/philiprehberger/http_client/version.rb +7 -0
- data/lib/philiprehberger/http_client.rb +18 -0
- metadata +56 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: d11769686f37911e9a4273468d8ae3d525162853eef921c26fa1f73b73e23a93
|
|
4
|
+
data.tar.gz: 0f290ad715f1ed058381676b87e142c7c239fb8aefcd4c4b3e5bb833391017f7
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: ce4fe073d9cc426661e965f6c1c95e613265a82db24eebc20d82624107b511e6d9f07fd630e8740666895ce6ce6b3b573bc719b19dfccf56ed8163a058bbf4a5
|
|
7
|
+
data.tar.gz: 87f238755a902ff293774f7328697caf14b76f119545f7c1aa41525dadc7fd1753690d12c05d18d55836cec60a08e7f4f1a28fb76667ca824c55d429b675bc61
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-03-10
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Initial release
|
|
13
|
+
- HTTP methods: GET, POST, PUT, PATCH, DELETE
|
|
14
|
+
- Automatic retries on network errors with configurable delay
|
|
15
|
+
- Request/response interceptors via `use` block
|
|
16
|
+
- JSON request and response helpers
|
|
17
|
+
- Response wrapper with `ok?` and `json` convenience methods
|
|
18
|
+
- Zero dependencies — built on Ruby stdlib `net/http`
|
|
19
|
+
|
|
20
|
+
[0.1.0]: https://github.com/philiprehberger/rb-http-client/releases/tag/v0.1.0
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 philiprehberger
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# philiprehberger-http_client
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/rb/philiprehberger-http_client)
|
|
4
|
+
[](https://github.com/philiprehberger/rb-http-client/actions/workflows/ci.yml)
|
|
5
|
+
|
|
6
|
+
Lightweight HTTP client wrapper with retries and interceptors. Zero dependencies — built on Ruby's stdlib `net/http`.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
Add to your Gemfile:
|
|
11
|
+
|
|
12
|
+
```ruby
|
|
13
|
+
gem "philiprehberger-http_client"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Or install directly:
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
gem install philiprehberger-http_client
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
require "philiprehberger/http_client"
|
|
26
|
+
|
|
27
|
+
client = Philiprehberger::HttpClient.new(base_url: "https://api.example.com")
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### GET request
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
response = client.get("/users", params: { page: 1 })
|
|
34
|
+
|
|
35
|
+
puts response.status # => 200
|
|
36
|
+
puts response.ok? # => true
|
|
37
|
+
puts response.json # => [{"id" => 1, "name" => "Alice"}, ...]
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### POST with JSON body
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
response = client.post("/users", json: { name: "Bob", email: "bob@example.com" })
|
|
44
|
+
|
|
45
|
+
puts response.status # => 201
|
|
46
|
+
puts response.json # => {"id" => 2, "name" => "Bob", ...}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Default headers
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
client = Philiprehberger::HttpClient.new(
|
|
53
|
+
base_url: "https://api.example.com",
|
|
54
|
+
headers: { "Authorization" => "Bearer token123" }
|
|
55
|
+
)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Interceptors
|
|
59
|
+
|
|
60
|
+
Add request/response interceptors to log, modify, or inspect traffic:
|
|
61
|
+
|
|
62
|
+
```ruby
|
|
63
|
+
client = Philiprehberger::HttpClient.new(base_url: "https://api.example.com")
|
|
64
|
+
|
|
65
|
+
client.use do |context|
|
|
66
|
+
if context[:response]
|
|
67
|
+
puts "Response: #{context[:response].status}"
|
|
68
|
+
else
|
|
69
|
+
puts "Request: #{context[:request][:method]} #{context[:request][:uri]}"
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
client.get("/health")
|
|
74
|
+
# Prints:
|
|
75
|
+
# Request: GET https://api.example.com/health
|
|
76
|
+
# Response: 200
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Retries
|
|
80
|
+
|
|
81
|
+
Automatically retry on network errors (connection refused, timeouts, etc.):
|
|
82
|
+
|
|
83
|
+
```ruby
|
|
84
|
+
client = Philiprehberger::HttpClient.new(
|
|
85
|
+
base_url: "https://api.example.com",
|
|
86
|
+
retries: 3,
|
|
87
|
+
retry_delay: 2
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
response = client.get("/unstable-endpoint")
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### All HTTP methods
|
|
94
|
+
|
|
95
|
+
```ruby
|
|
96
|
+
client.get("/resource", params: { q: "search" })
|
|
97
|
+
client.post("/resource", json: { key: "value" })
|
|
98
|
+
client.put("/resource/1", json: { key: "updated" })
|
|
99
|
+
client.patch("/resource/1", json: { key: "patched" })
|
|
100
|
+
client.delete("/resource/1")
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## API
|
|
104
|
+
|
|
105
|
+
### `Philiprehberger::HttpClient.new(**options)`
|
|
106
|
+
|
|
107
|
+
| Option | Type | Default | Description |
|
|
108
|
+
|---------------|---------|---------|--------------------------------------|
|
|
109
|
+
| `base_url` | String | — | Base URL for all requests (required) |
|
|
110
|
+
| `headers` | Hash | `{}` | Default headers for every request |
|
|
111
|
+
| `timeout` | Integer | `30` | Read/open timeout in seconds |
|
|
112
|
+
| `retries` | Integer | `0` | Retry attempts on network errors |
|
|
113
|
+
| `retry_delay` | Numeric | `1` | Seconds between retries |
|
|
114
|
+
|
|
115
|
+
### `Response`
|
|
116
|
+
|
|
117
|
+
| Method | Returns | Description |
|
|
118
|
+
|-----------|---------|---------------------------------|
|
|
119
|
+
| `status` | Integer | HTTP status code |
|
|
120
|
+
| `body` | String | Raw response body |
|
|
121
|
+
| `headers` | Hash | Response headers |
|
|
122
|
+
| `ok?` | Boolean | `true` if status is 200-299 |
|
|
123
|
+
| `json` | Hash | Parsed JSON body |
|
|
124
|
+
|
|
125
|
+
## License
|
|
126
|
+
|
|
127
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "uri"
|
|
5
|
+
require "json"
|
|
6
|
+
|
|
7
|
+
module Philiprehberger
|
|
8
|
+
module HttpClient
|
|
9
|
+
class Client
|
|
10
|
+
include Connection
|
|
11
|
+
|
|
12
|
+
# @param base_url [String] Base URL for all requests
|
|
13
|
+
# @param headers [Hash] Default headers applied to every request
|
|
14
|
+
# @param timeout [Integer] Read/open timeout in seconds
|
|
15
|
+
# @param retries [Integer] Number of retry attempts on network errors
|
|
16
|
+
# @param retry_delay [Numeric] Seconds to wait between retries
|
|
17
|
+
def initialize(base_url:, headers: {}, timeout: 30, retries: 0, retry_delay: 1)
|
|
18
|
+
@base_url = base_url.chomp("/")
|
|
19
|
+
@default_headers = headers
|
|
20
|
+
@timeout = timeout
|
|
21
|
+
@retries = retries
|
|
22
|
+
@retry_delay = retry_delay
|
|
23
|
+
@interceptors = []
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Register a request/response interceptor.
|
|
27
|
+
#
|
|
28
|
+
# The block receives a Hash with :request and, after the request completes, :response.
|
|
29
|
+
# It is called twice: once before the request (with :request only) and once after
|
|
30
|
+
# (with both :request and :response).
|
|
31
|
+
#
|
|
32
|
+
# @yield [Hash] context hash with :request and optionally :response
|
|
33
|
+
# @return [self]
|
|
34
|
+
def use(&block)
|
|
35
|
+
@interceptors << block
|
|
36
|
+
self
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Perform a GET request.
|
|
40
|
+
#
|
|
41
|
+
# @param path [String] Request path appended to the base URL
|
|
42
|
+
# @param params [Hash] Query parameters
|
|
43
|
+
# @param headers [Hash] Additional headers for this request
|
|
44
|
+
# @return [Response]
|
|
45
|
+
def get(path, params: {}, headers: {})
|
|
46
|
+
uri = build_uri(path, params)
|
|
47
|
+
request = Net::HTTP::Get.new(uri)
|
|
48
|
+
execute(uri, request, headers)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Perform a POST request.
|
|
52
|
+
#
|
|
53
|
+
# @param path [String] Request path
|
|
54
|
+
# @param body [String, nil] Raw body string
|
|
55
|
+
# @param json [Hash, Array, nil] JSON-serializable body (sets Content-Type automatically)
|
|
56
|
+
# @param headers [Hash] Additional headers
|
|
57
|
+
# @return [Response]
|
|
58
|
+
def post(path, body: nil, json: nil, headers: {})
|
|
59
|
+
uri = build_uri(path)
|
|
60
|
+
request = Net::HTTP::Post.new(uri)
|
|
61
|
+
set_body(request, body, json, headers)
|
|
62
|
+
execute(uri, request, headers)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Perform a PUT request.
|
|
66
|
+
#
|
|
67
|
+
# @param path [String] Request path
|
|
68
|
+
# @param body [String, nil] Raw body string
|
|
69
|
+
# @param json [Hash, Array, nil] JSON-serializable body
|
|
70
|
+
# @param headers [Hash] Additional headers
|
|
71
|
+
# @return [Response]
|
|
72
|
+
def put(path, body: nil, json: nil, headers: {})
|
|
73
|
+
uri = build_uri(path)
|
|
74
|
+
request = Net::HTTP::Put.new(uri)
|
|
75
|
+
set_body(request, body, json, headers)
|
|
76
|
+
execute(uri, request, headers)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Perform a PATCH request.
|
|
80
|
+
#
|
|
81
|
+
# @param path [String] Request path
|
|
82
|
+
# @param body [String, nil] Raw body string
|
|
83
|
+
# @param json [Hash, Array, nil] JSON-serializable body
|
|
84
|
+
# @param headers [Hash] Additional headers
|
|
85
|
+
# @return [Response]
|
|
86
|
+
def patch(path, body: nil, json: nil, headers: {})
|
|
87
|
+
uri = build_uri(path)
|
|
88
|
+
request = Net::HTTP::Patch.new(uri)
|
|
89
|
+
set_body(request, body, json, headers)
|
|
90
|
+
execute(uri, request, headers)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Perform a DELETE request.
|
|
94
|
+
#
|
|
95
|
+
# @param path [String] Request path
|
|
96
|
+
# @param headers [Hash] Additional headers
|
|
97
|
+
# @return [Response]
|
|
98
|
+
def delete(path, headers: {})
|
|
99
|
+
uri = build_uri(path)
|
|
100
|
+
request = Net::HTTP::Delete.new(uri)
|
|
101
|
+
execute(uri, request, headers)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Philiprehberger
|
|
4
|
+
module HttpClient
|
|
5
|
+
# Internal helpers for building URIs, HTTP connections, executing requests,
|
|
6
|
+
# and constructing Response objects. Mixed into Client to keep it concise.
|
|
7
|
+
module Connection
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def build_uri(path, params = {})
|
|
11
|
+
url = "#{@base_url}/#{path.sub(%r{^/}, '')}"
|
|
12
|
+
uri = URI.parse(url)
|
|
13
|
+
unless params.empty?
|
|
14
|
+
query = URI.encode_www_form(params)
|
|
15
|
+
uri.query = uri.query ? "#{uri.query}&#{query}" : query
|
|
16
|
+
end
|
|
17
|
+
uri
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def set_body(request, body, json_body, headers)
|
|
21
|
+
if json_body
|
|
22
|
+
request.body = JSON.generate(json_body)
|
|
23
|
+
headers["content-type"] ||= "application/json"
|
|
24
|
+
elsif body
|
|
25
|
+
request.body = body
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def apply_headers(request, extra_headers)
|
|
30
|
+
merged = @default_headers.merge(extra_headers)
|
|
31
|
+
merged.each { |key, value| request[key] = value }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def execute(uri, request, extra_headers)
|
|
35
|
+
apply_headers(request, extra_headers)
|
|
36
|
+
|
|
37
|
+
context = { request: { uri: uri, method: request.method, headers: request.to_hash } }
|
|
38
|
+
run_interceptors(context)
|
|
39
|
+
|
|
40
|
+
response = perform_with_retries(uri, request)
|
|
41
|
+
context[:response] = response
|
|
42
|
+
run_interceptors(context)
|
|
43
|
+
|
|
44
|
+
response
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def perform_with_retries(uri, request)
|
|
48
|
+
attempts = 0
|
|
49
|
+
begin
|
|
50
|
+
perform_request(uri, request)
|
|
51
|
+
rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ETIMEDOUT,
|
|
52
|
+
Net::OpenTimeout, Net::ReadTimeout, SocketError => e
|
|
53
|
+
attempts += 1
|
|
54
|
+
raise e unless attempts <= @retries
|
|
55
|
+
|
|
56
|
+
sleep(@retry_delay)
|
|
57
|
+
retry
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def perform_request(uri, request)
|
|
62
|
+
http = build_http(uri)
|
|
63
|
+
raw = http.request(request)
|
|
64
|
+
build_response(raw)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def build_http(uri)
|
|
68
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
69
|
+
http.use_ssl = uri.scheme == "https"
|
|
70
|
+
http.open_timeout = @timeout
|
|
71
|
+
http.read_timeout = @timeout
|
|
72
|
+
http
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def build_response(raw)
|
|
76
|
+
response_headers = {}
|
|
77
|
+
raw.each_header { |k, v| response_headers[k] = v }
|
|
78
|
+
|
|
79
|
+
Response.new(
|
|
80
|
+
status: raw.code.to_i,
|
|
81
|
+
body: raw.body || "",
|
|
82
|
+
headers: response_headers
|
|
83
|
+
)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def run_interceptors(context)
|
|
87
|
+
@interceptors.each { |interceptor| interceptor.call(context) }
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module Philiprehberger
|
|
6
|
+
module HttpClient
|
|
7
|
+
class Response
|
|
8
|
+
attr_reader :status, :body, :headers
|
|
9
|
+
|
|
10
|
+
# @param status [Integer] HTTP status code
|
|
11
|
+
# @param body [String] Response body
|
|
12
|
+
# @param headers [Hash] Response headers
|
|
13
|
+
def initialize(status:, body:, headers: {})
|
|
14
|
+
@status = status
|
|
15
|
+
@body = body
|
|
16
|
+
@headers = headers
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Returns true if the status code is in the 2xx range.
|
|
20
|
+
#
|
|
21
|
+
# @return [Boolean]
|
|
22
|
+
def ok?
|
|
23
|
+
status >= 200 && status < 300
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Parses the response body as JSON.
|
|
27
|
+
#
|
|
28
|
+
# @return [Hash, Array] Parsed JSON
|
|
29
|
+
# @raise [JSON::ParserError] If the body is not valid JSON
|
|
30
|
+
def json
|
|
31
|
+
@json ||= JSON.parse(body)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "http_client/version"
|
|
4
|
+
require_relative "http_client/response"
|
|
5
|
+
require_relative "http_client/connection"
|
|
6
|
+
require_relative "http_client/client"
|
|
7
|
+
|
|
8
|
+
module Philiprehberger
|
|
9
|
+
module HttpClient
|
|
10
|
+
# Convenience constructor.
|
|
11
|
+
#
|
|
12
|
+
# @param options [Hash] Forwarded to {Client#initialize}
|
|
13
|
+
# @return [Client]
|
|
14
|
+
def self.new(**options)
|
|
15
|
+
Client.new(**options)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: philiprehberger-http_client
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Philip Rehberger
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-03-10 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: A zero-dependency HTTP client built on Ruby's net/http with automatic
|
|
14
|
+
retries, request/response interceptors, and a clean API for JSON services.
|
|
15
|
+
email:
|
|
16
|
+
- me@philiprehberger.com
|
|
17
|
+
executables: []
|
|
18
|
+
extensions: []
|
|
19
|
+
extra_rdoc_files: []
|
|
20
|
+
files:
|
|
21
|
+
- CHANGELOG.md
|
|
22
|
+
- LICENSE
|
|
23
|
+
- README.md
|
|
24
|
+
- lib/philiprehberger/http_client.rb
|
|
25
|
+
- lib/philiprehberger/http_client/client.rb
|
|
26
|
+
- lib/philiprehberger/http_client/connection.rb
|
|
27
|
+
- lib/philiprehberger/http_client/response.rb
|
|
28
|
+
- lib/philiprehberger/http_client/version.rb
|
|
29
|
+
homepage: https://github.com/philiprehberger/rb-http-client
|
|
30
|
+
licenses:
|
|
31
|
+
- MIT
|
|
32
|
+
metadata:
|
|
33
|
+
homepage_uri: https://github.com/philiprehberger/rb-http-client
|
|
34
|
+
source_code_uri: https://github.com/philiprehberger/rb-http-client
|
|
35
|
+
changelog_uri: https://github.com/philiprehberger/rb-http-client/blob/main/CHANGELOG.md
|
|
36
|
+
rubygems_mfa_required: 'true'
|
|
37
|
+
post_install_message:
|
|
38
|
+
rdoc_options: []
|
|
39
|
+
require_paths:
|
|
40
|
+
- lib
|
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
42
|
+
requirements:
|
|
43
|
+
- - ">="
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '3.1'
|
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
47
|
+
requirements:
|
|
48
|
+
- - ">="
|
|
49
|
+
- !ruby/object:Gem::Version
|
|
50
|
+
version: '0'
|
|
51
|
+
requirements: []
|
|
52
|
+
rubygems_version: 3.5.22
|
|
53
|
+
signing_key:
|
|
54
|
+
specification_version: 4
|
|
55
|
+
summary: Lightweight HTTP client wrapper with retries and interceptors
|
|
56
|
+
test_files: []
|