Class: HttpResource::Client
- Inherits:
-
Object
- Object
- HttpResource::Client
- Defined in:
- lib/http_resource/client.rb
Overview
Net::HTTP transport for a single REST host. Resource-oriented: the verbs (get/post/put/patch/delete) are the primitives a Resource is built on, and also an escape hatch for endpoints not yet modelled.
client = HttpResource::Client.new(base_url: "https://api.example.org",
auth: HttpResource::Auth.bearer(token))
client.get(["api", "contacts", id]) # GET, id escaped as one segment
client.post(["api", "actions"], { ... }) # POST a JSON body
client.post(["oauth", "token"], form: { ... }) # POST a form body (OAuth, RFC 6749)
Reads return parsed JSON (a Hash/Array, or nil on an empty body). Every call raises an HttpResource::ApiError subclass on a non-2xx response or a transport failure.
SECURITY — path segments are UNTRUSTED. When path is an Array, each segment
is percent-encoded as a single RFC-3986 path component, so an id/email/token
can never escape into a second segment, the host, a query or a header. A
String path is sent VERBATIM (trusted) — NEVER interpolate untrusted input
into a String path; pass an Array.
Constant Summary collapse
- DEFAULT_OPEN_TIMEOUT =
5- DEFAULT_READ_TIMEOUT =
15
Instance Attribute Summary collapse
-
#base_url ⇒ Object
readonly
Returns the value of attribute base_url.
-
#simulation ⇒ Object
readonly
The simulation backend when built with simulation:; nil in real mode.
Class Method Summary collapse
-
.simulation_backend_class ⇒ Object
The Backend class
simulation: trueinstantiates.
Instance Method Summary collapse
- #delete(path, open_timeout: nil, read_timeout: nil) ⇒ Object
-
#get(path, params: nil, open_timeout: nil, read_timeout: nil) ⇒ Object
Low-level REST verbs.
-
#initialize(base_url:, auth: nil, username: nil, password: nil, open_timeout: DEFAULT_OPEN_TIMEOUT, read_timeout: DEFAULT_READ_TIMEOUT, simulation: nil) ⇒ Client
constructor
A new instance of Client.
- #patch(path, payload = nil, form: nil, open_timeout: nil, read_timeout: nil) ⇒ Object
- #post(path, payload = nil, form: nil, open_timeout: nil, read_timeout: nil) ⇒ Object
- #put(path, payload = nil, form: nil, open_timeout: nil, read_timeout: nil) ⇒ Object
Constructor Details
#initialize(base_url:, auth: nil, username: nil, password: nil, open_timeout: DEFAULT_OPEN_TIMEOUT, read_timeout: DEFAULT_READ_TIMEOUT, simulation: nil) ⇒ Client
Returns a new instance of Client.
46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/http_resource/client.rb', line 46 def initialize(base_url:, auth: nil, username: nil, password: nil, open_timeout: DEFAULT_OPEN_TIMEOUT, read_timeout: DEFAULT_READ_TIMEOUT, simulation: nil) raise ConfigurationError, "base_url is required" if blank?(base_url) @base_url = base_url.to_s.sub(%r{/+\z}, "") @auth = auth || default_auth(username, password) @open_timeout = open_timeout @read_timeout = read_timeout @simulation = setup_simulation(simulation) end |
Instance Attribute Details
#base_url ⇒ Object (readonly)
Returns the value of attribute base_url.
33 34 35 |
# File 'lib/http_resource/client.rb', line 33 def base_url @base_url end |
#simulation ⇒ Object (readonly)
The simulation backend when built with simulation:; nil in real mode.
36 37 38 |
# File 'lib/http_resource/client.rb', line 36 def simulation @simulation end |
Class Method Details
.simulation_backend_class ⇒ Object
The Backend class simulation: true instantiates. Client-gem subclasses
override this to point at their own Backend subclass (with its own
registered handlers). Only called after the lazy require, so the
constant resolves.
42 43 44 |
# File 'lib/http_resource/client.rb', line 42 def self.simulation_backend_class Simulation::Backend end |
Instance Method Details
#delete(path, open_timeout: nil, read_timeout: nil) ⇒ Object
87 88 89 |
# File 'lib/http_resource/client.rb', line 87 def delete(path, open_timeout: nil, read_timeout: nil) request(:delete, path, open_timeout:, read_timeout:) end |
#get(path, params: nil, open_timeout: nil, read_timeout: nil) ⇒ Object
Low-level REST verbs. path may be a String ("/api/foo") sent verbatim, or
an Array of segments (["api", "contacts", email]) each individually escaped.
Each verb accepts open_timeout:/read_timeout: to override the client's
budget for that one call (e.g. a short read_timeout on a synchronous read).
The body-bearing verbs (post/put/patch) send EITHER a JSON body — the
positional payload — or a form body — form: {...}, encoded as
application/x-www-form-urlencoded (for the form-encoded endpoints OAuth
consumers hit: RFC 6749 token, RFC 7662 introspection, …). Passing both is
a caller bug and raises ArgumentError. The response side is identical either
way: parsed JSON on a 2xx, a typed ApiError (with #status + #body) on a
non-2xx — so a "400 invalid_grant" is a rescue-able ClientError whose #body
carries the error payload.
71 72 73 |
# File 'lib/http_resource/client.rb', line 71 def get(path, params: nil, open_timeout: nil, read_timeout: nil) request(:get, path, params:, open_timeout:, read_timeout:) end |
#patch(path, payload = nil, form: nil, open_timeout: nil, read_timeout: nil) ⇒ Object
83 84 85 |
# File 'lib/http_resource/client.rb', line 83 def patch(path, payload = nil, form: nil, open_timeout: nil, read_timeout: nil) request(:patch, path, body: payload, form:, open_timeout:, read_timeout:) end |
#post(path, payload = nil, form: nil, open_timeout: nil, read_timeout: nil) ⇒ Object
75 76 77 |
# File 'lib/http_resource/client.rb', line 75 def post(path, payload = nil, form: nil, open_timeout: nil, read_timeout: nil) request(:post, path, body: payload, form:, open_timeout:, read_timeout:) end |
#put(path, payload = nil, form: nil, open_timeout: nil, read_timeout: nil) ⇒ Object
79 80 81 |
# File 'lib/http_resource/client.rb', line 79 def put(path, payload = nil, form: nil, open_timeout: nil, read_timeout: nil) request(:put, path, body: payload, form:, open_timeout:, read_timeout:) end |