requests_ruby 1.0.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 +63 -0
- data/LICENSE +21 -0
- data/README.md +331 -0
- data/lib/cacert.pem +5689 -0
- data/lib/requests/adapters.rb +114 -0
- data/lib/requests/api.rb +25 -0
- data/lib/requests/auth.rb +74 -0
- data/lib/requests/cookies.rb +55 -0
- data/lib/requests/exceptions.rb +56 -0
- data/lib/requests/models.rb +118 -0
- data/lib/requests/sessions.rb +222 -0
- data/lib/requests/status_codes.rb +31 -0
- data/lib/requests/structures.rb +54 -0
- data/lib/requests/utils.rb +55 -0
- data/lib/requests/version.rb +5 -0
- data/lib/requests.rb +19 -0
- data/lib/requests_ruby.rb +3 -0
- metadata +75 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 98c916667505e2bb295cfd13cfd3640a9fb73fe285248115b1f612d2b562a008
|
|
4
|
+
data.tar.gz: e8dc6c58aa8999fdb4ae84040733b05b801140efcac65b7ab9f834f299c8c4e8
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 102260dfeff2781a3cdd337b9a3771e43ad865a1c2968090268202b3ae915320e84b9b2129e6d6ba4698303638c207aa0b49e814782cfd9ef1914718bec73b97
|
|
7
|
+
data.tar.gz: 3b3a024c7adc8e3a47d13289b9668d7ee8f1379c98d8e317f718be6b2be5525f4cfb39ab4821e839a2af20ec6645f15d71be04f6d4857e520a2ef4cea06ecc32
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 2.1.0
|
|
4
|
+
|
|
5
|
+
Big cleanup pass. Split the single `lib/requests.rb` file into a proper
|
|
6
|
+
`lib/requests/*` structure, fixed several real bugs, and filled in a bunch
|
|
7
|
+
of gaps vs. the python `requests` API.
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- **`Content-Type` header silently dropped on redirects.** The request body
|
|
11
|
+
was only built once, but the header carrying its `Content-Type` was set
|
|
12
|
+
on a headers hash that got thrown away and rebuilt on every redirect hop.
|
|
13
|
+
A 307/308 redirect that correctly preserved the POST body would send it
|
|
14
|
+
with no `Content-Type` at all. Body + content type are now computed once
|
|
15
|
+
and carried through the whole redirect chain.
|
|
16
|
+
- **Binary multipart uploads could raise `Encoding::CompatibilityError`.**
|
|
17
|
+
The multipart body was being built as a UTF-8 string; appending raw
|
|
18
|
+
binary file content (an image, a zip, whatever) onto it blew up the
|
|
19
|
+
moment the bytes weren't valid UTF-8. The body is now built as
|
|
20
|
+
`ASCII-8BIT` from the start.
|
|
21
|
+
- **Request bodies silently disappeared on GET/DELETE.** The code only
|
|
22
|
+
attached a body when `request_body_permitted?` was true, which is `false`
|
|
23
|
+
for GET in net/http. Some APIs (Elasticsearch, various search/query
|
|
24
|
+
APIs) intentionally send a JSON body with GET - that's now respected.
|
|
25
|
+
- **Confusing `unexpected token` errors from `Response#json`.** Calling
|
|
26
|
+
`.json` on a response that came back as an HTML error/login page (very
|
|
27
|
+
common when you hit a WAF, an expired-auth redirect, or the wrong host)
|
|
28
|
+
raised a bare `JSON::ParserError`-wrapped message with no context. The
|
|
29
|
+
error now says plainly that it looks like an HTML page, includes the
|
|
30
|
+
status code, and shows a truncated preview of the body.
|
|
31
|
+
- Deflate-compressed bodies missing the zlib header (some servers send raw
|
|
32
|
+
deflate) now fall back to a raw inflate instead of raising.
|
|
33
|
+
- `Requests::Timeout` / `ConnectTimeout` / `ReadTimeout` now share a
|
|
34
|
+
`Requests::Timeoutable` module so you can `rescue Requests::Timeoutable`
|
|
35
|
+
and catch both connect and read timeouts in one line, closer to python's
|
|
36
|
+
`except requests.Timeout`.
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
- `Response#status` (alias of `status_code`), `#is_redirect?`,
|
|
40
|
+
`#is_permanent_redirect?`, `#client_error?`, `#server_error?`.
|
|
41
|
+
- `Response#save_to(path)` to stream a body straight to disk.
|
|
42
|
+
- `Response#request` is now a small `PreparedRequest` object (still
|
|
43
|
+
supports `resp.request[:url]` hash-style access for old code).
|
|
44
|
+
- `Session#mount(prefix, adapter)` + `Requests::HTTPAdapter` - swap out the
|
|
45
|
+
transport layer per URL prefix, loosely modeled on python's adapters.
|
|
46
|
+
- Built-in retry support: `retries:`/`Session#retries` and
|
|
47
|
+
`backoff_factor:` for transient connection errors on idempotent methods.
|
|
48
|
+
- `Session#get!` / `#post!` - like `get`/`post` but raise immediately on
|
|
49
|
+
a non-2xx/3xx response.
|
|
50
|
+
- `Requests.download(url, to: path)` convenience method.
|
|
51
|
+
- `Requests::InvalidSchema` (scheme present but not http/https) as a
|
|
52
|
+
companion to the existing `MissingSchema` (no scheme at all).
|
|
53
|
+
- Cross-host redirect now strips the `Authorization` header instead of
|
|
54
|
+
forwarding your bearer token / basic auth to whatever host the
|
|
55
|
+
`Location` header pointed at.
|
|
56
|
+
- A real test suite under `spec/` (plain minitest, no network calls).
|
|
57
|
+
- `Makefile` with `test`, `console`, `build`, `install`, `release`, `lint`.
|
|
58
|
+
- `Requests::CaseInsensitiveDict` / `Requests::CookieJar` aliases for
|
|
59
|
+
people coming from the python naming.
|
|
60
|
+
|
|
61
|
+
## 1.0.0 / 2.0.0
|
|
62
|
+
|
|
63
|
+
Initial single-file releases.
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 requests_ruby contributors
|
|
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,331 @@
|
|
|
1
|
+
# requests_ruby
|
|
2
|
+
|
|
3
|
+
A zero-dependency, stdlib-only HTTP client for Ruby, modeled closely on Python's beloved [`requests`](https://requests.readthedocs.io/) library. No `Gemfile`, no C extensions, no transitive dependency tree — just Ruby's own `net/http` wrapped in an API that doesn't make you want to throw your laptop.
|
|
4
|
+
|
|
5
|
+
[](https://rubygems.org/gems/requests_ruby)
|
|
6
|
+
[](https://www.ruby-lang.org)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
[](requests_ruby.gemspec)
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Table of Contents
|
|
13
|
+
|
|
14
|
+
- [Why this exists](#-why-this-exists)
|
|
15
|
+
- [Installation](#-installation)
|
|
16
|
+
- [Quick start](#-quick-start)
|
|
17
|
+
- [Feature tour](#-feature-tour)
|
|
18
|
+
- [Query params](#query-params)
|
|
19
|
+
- [Sending data (form / JSON / files)](#sending-data-form--json--files)
|
|
20
|
+
- [Response object](#response-object)
|
|
21
|
+
- [Sessions](#sessions)
|
|
22
|
+
- [Authentication](#authentication)
|
|
23
|
+
- [Errors & exceptions](#errors--exceptions)
|
|
24
|
+
- [Redirects & history](#redirects--history)
|
|
25
|
+
- [Timeouts & retries](#timeouts--retries)
|
|
26
|
+
- [Proxies & SSL](#proxies--ssl)
|
|
27
|
+
- [Cookies](#cookies)
|
|
28
|
+
- [Hooks](#hooks)
|
|
29
|
+
- [Streaming & downloads](#streaming--downloads)
|
|
30
|
+
- [Custom transport adapters](#custom-transport-adapters)
|
|
31
|
+
- [Status codes](#status-codes)
|
|
32
|
+
- [API reference](#-api-reference)
|
|
33
|
+
- [Python parity cheat sheet](#-python-parity-cheat-sheet)
|
|
34
|
+
- [Known limitations](#-known-limitations)
|
|
35
|
+
- [Development](#-development)
|
|
36
|
+
- [Contributing](#-contributing)
|
|
37
|
+
- [License](#-license)
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Why this exists
|
|
42
|
+
|
|
43
|
+
Ruby has plenty of great HTTP gems (`Faraday`, `HTTParty`, `httpx`...) but most either pull in dependencies or don't quite match the ergonomics people already know from Python's `requests`. This gem is for the specific case of: *"I want `requests.get(url).json()` energy, in Ruby, using only what ships with Ruby itself."*
|
|
44
|
+
|
|
45
|
+
If you're coming from Python, the [parity cheat sheet](#-python-parity-cheat-sheet) below will feel like home.
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
Add it to your `Gemfile`:
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
gem 'requests_ruby'
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Or install it directly:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
gem install requests_ruby
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Then, in your code — `require 'requests'` works out of the box (matching the ergonomics of the gem's underlying `Requests` module), and so does `require 'requests_ruby'` if you'd rather match the gem name exactly. Both point at the same code:
|
|
62
|
+
|
|
63
|
+
```ruby
|
|
64
|
+
require 'requests'
|
|
65
|
+
# -- or --
|
|
66
|
+
require 'requests_ruby'
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Quick start
|
|
70
|
+
|
|
71
|
+
```ruby
|
|
72
|
+
require 'requests'
|
|
73
|
+
|
|
74
|
+
r = Requests.get('https://api.example.com/users', params: { page: 1 })
|
|
75
|
+
|
|
76
|
+
r.status_code #=> 200
|
|
77
|
+
r.ok? #=> true
|
|
78
|
+
r.json #=> { "users" => [...] }
|
|
79
|
+
r.text #=> "{\"users\":[...]}"
|
|
80
|
+
r.headers['content-type']
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Feature tour
|
|
84
|
+
|
|
85
|
+
### Query params
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
Requests.get('https://api.example.com/search', params: { q: 'ruby gems', page: 2 })
|
|
89
|
+
# => https://api.example.com/search?q=ruby+gems&page=2
|
|
90
|
+
|
|
91
|
+
# arrays become repeated params
|
|
92
|
+
Requests.get('https://api.example.com/search', params: { tag: ['ruby', 'http'] })
|
|
93
|
+
# => ...?tag=ruby&tag=http
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Sending data (form / JSON / files)
|
|
97
|
+
|
|
98
|
+
```ruby
|
|
99
|
+
# JSON body
|
|
100
|
+
Requests.post('https://api.example.com/login', json: { user: 'ali', pass: 'secret' })
|
|
101
|
+
|
|
102
|
+
# form-encoded body
|
|
103
|
+
Requests.post('https://api.example.com/login', data: { user: 'ali', pass: 'secret' })
|
|
104
|
+
|
|
105
|
+
# multipart file upload
|
|
106
|
+
Requests.post('https://api.example.com/upload',
|
|
107
|
+
data: { title: 'my photo' },
|
|
108
|
+
files: { avatar: ['pic.png', File.read('pic.png'), 'image/png'] })
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Response object
|
|
112
|
+
|
|
113
|
+
```ruby
|
|
114
|
+
r = Requests.get(url)
|
|
115
|
+
|
|
116
|
+
r.status_code # 200
|
|
117
|
+
r.status # alias for status_code
|
|
118
|
+
r.ok? # true if < 400
|
|
119
|
+
r.text # decoded body as a UTF-8 string
|
|
120
|
+
r.content # raw body
|
|
121
|
+
r.json # parsed JSON (raises Requests::JSONDecodeError if it isn't JSON)
|
|
122
|
+
r.headers['etag'] # case-insensitive header access
|
|
123
|
+
r.cookies # cookie jar collected across the request
|
|
124
|
+
r.elapsed # Float seconds
|
|
125
|
+
r.url # final URL after any redirects
|
|
126
|
+
r.history # array of intermediate Response objects
|
|
127
|
+
r.links # parsed Link header, e.g. pagination
|
|
128
|
+
r.request # PreparedRequest - what was actually sent (method/url/headers/body)
|
|
129
|
+
r.redirect? # true for 3xx with a Location header
|
|
130
|
+
r.client_error? # 400-499
|
|
131
|
+
r.server_error? # 500+
|
|
132
|
+
r.save_to('file.bin') # stream raw_body straight to disk
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Sessions
|
|
136
|
+
|
|
137
|
+
Sessions persist headers, cookies, and auth across multiple requests to the same service — and reuse is not just convenient, it avoids re-doing DNS/TLS handshakes on every call.
|
|
138
|
+
|
|
139
|
+
```ruby
|
|
140
|
+
s = Requests::Session.new
|
|
141
|
+
s.headers['Authorization'] = 'Bearer xyz'
|
|
142
|
+
|
|
143
|
+
s.get('https://api.example.com/me')
|
|
144
|
+
s.get('https://api.example.com/orders')
|
|
145
|
+
|
|
146
|
+
# raise immediately instead of checking status_code yourself
|
|
147
|
+
s.get!('https://api.example.com/me')
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Authentication
|
|
151
|
+
|
|
152
|
+
```ruby
|
|
153
|
+
Requests.get(url, auth: Requests::BasicAuth.new('user', 'pass'))
|
|
154
|
+
Requests.get(url, auth: Requests::BearerAuth.new('token'))
|
|
155
|
+
Requests.get(url, auth: Requests::DigestAuth.new('user', 'pass'))
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Write your own by implementing `#call(headers)` — anything that responds to it works as an `auth:` value.
|
|
159
|
+
|
|
160
|
+
### Errors & exceptions
|
|
161
|
+
|
|
162
|
+
```ruby
|
|
163
|
+
begin
|
|
164
|
+
r = Requests.get(url)
|
|
165
|
+
r.raise_for_status
|
|
166
|
+
rescue Requests::HTTPError => e
|
|
167
|
+
puts e.message # "404 Client Error: Not Found for url: ..."
|
|
168
|
+
puts e.response.status_code
|
|
169
|
+
rescue Requests::Timeoutable
|
|
170
|
+
# catches BOTH Requests::ConnectTimeout and Requests::ReadTimeout
|
|
171
|
+
puts 'timed out'
|
|
172
|
+
rescue Requests::ConnectionError => e
|
|
173
|
+
puts e.message
|
|
174
|
+
end
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Exception hierarchy at a glance:
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
Requests::RequestException
|
|
181
|
+
├── Requests::HTTPError
|
|
182
|
+
├── Requests::ConnectionError
|
|
183
|
+
│ ├── Requests::ProxyError
|
|
184
|
+
│ ├── Requests::SSLError
|
|
185
|
+
│ └── Requests::ConnectTimeout (also includes Requests::Timeoutable)
|
|
186
|
+
├── Requests::Timeout (also includes Requests::Timeoutable)
|
|
187
|
+
│ └── Requests::ReadTimeout
|
|
188
|
+
├── Requests::URLRequired
|
|
189
|
+
├── Requests::TooManyRedirects
|
|
190
|
+
├── Requests::MissingSchema (no scheme at all, e.g. "example.com")
|
|
191
|
+
├── Requests::InvalidSchema (unsupported scheme, e.g. "ftp://")
|
|
192
|
+
├── Requests::InvalidURL
|
|
193
|
+
│ └── Requests::InvalidProxyURL
|
|
194
|
+
├── Requests::ChunkedEncodingError
|
|
195
|
+
├── Requests::ContentDecodingError
|
|
196
|
+
├── Requests::StreamConsumedError
|
|
197
|
+
├── Requests::InvalidHeader
|
|
198
|
+
├── Requests::RetryError
|
|
199
|
+
└── Requests::InvalidJSONError
|
|
200
|
+
└── Requests::JSONDecodeError
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Redirects & history
|
|
204
|
+
|
|
205
|
+
```ruby
|
|
206
|
+
r = Requests.get(url)
|
|
207
|
+
r.history # every intermediate 3xx Response, in order
|
|
208
|
+
r.url # the final URL you landed on
|
|
209
|
+
|
|
210
|
+
r = Requests.get(url, allow_redirects: false) # don't follow at all
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Timeouts & retries
|
|
214
|
+
|
|
215
|
+
```ruby
|
|
216
|
+
Requests.get(url, timeout: 5) # 5s for both connect and read
|
|
217
|
+
Requests.get(url, timeout: [3, 10]) # [connect, read]
|
|
218
|
+
|
|
219
|
+
# retry transient connection errors on idempotent methods (GET/HEAD/OPTIONS/PUT/DELETE)
|
|
220
|
+
s = Requests::Session.new
|
|
221
|
+
s.retries = 3
|
|
222
|
+
s.backoff_factor = 0.5 # sleeps 0.5s, 1s, 1.5s between attempts
|
|
223
|
+
s.get(url)
|
|
224
|
+
|
|
225
|
+
# or per-request
|
|
226
|
+
Requests.get(url, retries: 3)
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Proxies & SSL
|
|
230
|
+
|
|
231
|
+
```ruby
|
|
232
|
+
Requests.get(url, proxies: { 'http' => 'http://127.0.0.1:8080', 'https' => 'http://127.0.0.1:8080' })
|
|
233
|
+
Requests.get(url, verify: false) # skip cert verification (careful!)
|
|
234
|
+
Requests.get(url, verify: '/path/to/ca.pem') # custom CA bundle
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
A bundled `cacert.pem` (Mozilla's CA bundle) ships with the gem and is used by default. Override it globally with the `REQUESTS_CA_FILE` environment variable.
|
|
238
|
+
|
|
239
|
+
### Cookies
|
|
240
|
+
|
|
241
|
+
```ruby
|
|
242
|
+
r = Requests.get(url)
|
|
243
|
+
r.cookies['session_id']
|
|
244
|
+
|
|
245
|
+
s = Requests::Session.new
|
|
246
|
+
s.cookies.set('theme', 'dark')
|
|
247
|
+
s.get(url) # sent automatically on every request through this session
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Hooks
|
|
251
|
+
|
|
252
|
+
```ruby
|
|
253
|
+
s = Requests::Session.new
|
|
254
|
+
s.hooks[:response] << ->(resp) { puts "#{resp.request[:method]} #{resp.url} -> #{resp.status_code}" }
|
|
255
|
+
s.get(url)
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Streaming & downloads
|
|
259
|
+
|
|
260
|
+
```ruby
|
|
261
|
+
r = Requests.get(url)
|
|
262
|
+
r.iter_content(chunk_size: 4096) { |chunk| ... }
|
|
263
|
+
r.iter_lines { |line| ... }
|
|
264
|
+
|
|
265
|
+
# convenience one-liner for "just save this to disk"
|
|
266
|
+
Requests.download('https://example.com/file.zip', to: 'file.zip')
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
> ℹ️ Note: unlike Python's `requests`, the body is fully read before `iter_content`/`iter_lines` yield anything — this library deliberately stays stdlib-only, and true lazy streaming would need extra machinery to keep a `net/http` connection open across method calls. See [Known limitations](#-known-limitations).
|
|
270
|
+
|
|
271
|
+
### Custom transport adapters
|
|
272
|
+
|
|
273
|
+
Loosely inspired by Python's `Session.mount()` / `HTTPAdapter`:
|
|
274
|
+
|
|
275
|
+
```ruby
|
|
276
|
+
class LoggingAdapter < Requests::HTTPAdapter
|
|
277
|
+
def send_once(*args)
|
|
278
|
+
puts 'sending a request...'
|
|
279
|
+
super
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
s = Requests::Session.new
|
|
284
|
+
s.mount('https://internal.example.com/', LoggingAdapter.new)
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Status codes
|
|
288
|
+
|
|
289
|
+
```ruby
|
|
290
|
+
Requests.codes.ok # 200
|
|
291
|
+
Requests.codes.not_found # 404
|
|
292
|
+
Requests.codes.im_a_teapot # 418, yes really
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## API reference
|
|
296
|
+
|
|
297
|
+
| Module-level | Session | Response |
|
|
298
|
+
|---|---|---|
|
|
299
|
+
| `Requests.get/post/put/patch/delete/head/options` | `session.get/post/put/patch/delete/head/options` | `status_code`, `status` |
|
|
300
|
+
| `Requests.request(method, url, **opts)` | `session.request(method, url, **opts)` | `ok?`, `redirect?` |
|
|
301
|
+
| `Requests.session` → new `Session` | `session.get!/post!` (raise on error) | `text`, `content`, `json` |
|
|
302
|
+
| `Requests.download(url, to:)` | `session.mount(prefix, adapter)` | `headers`, `cookies` |
|
|
303
|
+
| `Requests.codes` | `session.hooks[:response]` | `elapsed`, `history`, `url` |
|
|
304
|
+
| | `session.headers`, `.cookies`, `.auth`, `.proxies`, `.retries` | `raise_for_status`, `save_to`, `links` |
|
|
305
|
+
|
|
306
|
+
Every request-level method accepts: `params`, `data`, `json`, `headers`, `cookies`, `files`, `auth`, `timeout`, `allow_redirects`, `proxies`, `verify`, `cert`, `hooks`, `retries`.
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
## 🔧 Development
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
git clone https://github.com/requests-ruby/requests_ruby.git
|
|
313
|
+
cd requests_ruby
|
|
314
|
+
make test # run the test suite
|
|
315
|
+
make console # irb with the lib pre-loaded
|
|
316
|
+
make build # build the .gem into pkg/
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
See the [Makefile](Makefile) for the full list of targets.
|
|
320
|
+
|
|
321
|
+
## Contributing
|
|
322
|
+
|
|
323
|
+
Bug reports and pull requests are welcome. A few ground rules:
|
|
324
|
+
|
|
325
|
+
1. No new runtime dependencies — this stays stdlib-only, on purpose.
|
|
326
|
+
2. Add a test in `spec/requests_spec.rb` for anything you fix or add.
|
|
327
|
+
3. Keep the Python-parity naming where it makes sense, but don't force it where it doesn't fit Ruby idiom (`?`-suffixed predicates, etc.).
|
|
328
|
+
|
|
329
|
+
## License
|
|
330
|
+
|
|
331
|
+
[MIT](LICENSE)
|