Class: Api::RemoteResource
- Inherits:
-
Object
- Object
- Api::RemoteResource
- Defined in:
- lib/ocean/api_remote_resource.rb
Overview
This class represents an Ocean resource accessed by a URI.
The resource is read lazily. Retries and back off properties are available.
thing = Api::RemoteResource.new("http://api.example.com/things/1")
thing.present? => false
thing['some_attr'] => {"this" => "is", "just" => "an example"}
thing.present? => true
thing.resource_type => 'thing'
thing.status => 200
thing.status_message => "OK"
thing.response => #<an Api::Response instance>
thing.etag => "e4552f0ae517f0352f0ae56222fa0733ea52f0ae5e0"
The last raw body can be read:
thing.raw => nil or {"foo" => {...}}
Headers can be read or set:
thing.headers => {...}
thing.headers['X-Some-Header'] = "Zalagadoola"
Attributes can be read or set:
thing['foo'] = "bar"
thing['foo'] = "newbar"
Hyperlinks can be read:
thing.hyperlink['self'] => {"href"=>"http://api.example.com/things/1",
"type"=>"application/json"}
These are defined for convenience:
thing.href => "http://api.example.com/things/1"
thing.type => "application/json"
The following two are equivalent:
Api::RemoteResource.get("foo") always returns a new RemoteResource
Api::RemoteResource.new("foo").get always returns the RemoteResource
as are:
Api::RemoteResource.get!("foo") returns a new RemoteResource or raises an error
Api::RemoteResource.new("foo").get! returns the RemoteResource or raises an error
thing.get!
returns the RemoteResource if successful. If not, raises an exception. thing.get
does the same, but always returns the RemoteResource. The remote resource can be examined to see its status.
Hyperlinks can be specified to avoid hardcoding API URIs. Simply specify the hyperlink as the first parameter to the instance versions of the HTTP accessors:
x = Api::RemoteResource.new("http://foo.com/x")
x.get(:creator)
x.get!(:creator)['username']
x.put(:confirm, body: {x:2, y:3})
x.post(:login, body: {username: "Bl0feld", password: "SPECTRE"})
x.delete(:expired)
Note the difference between:
x.put(body: {x:2, y:3})
x.put(:self, body: {x:2, y:3})
x.put(:confirm, body: {x:2, y:3})
The first two are logically equivalent: they both make a PUT request to x itself, though in the second case, the self hyperlink is explicit (the first arg defaults to :self). The third case sends a PUT request to x’s hyperlink :confirm. From this follows that the following also are equivalent:
x.get
x.get(:self)
#post, #post!, #put, #put!, #delete, and #delete! are also available and have the same hyperlink handling capabilities.
Exceptions:
GetFailed raised when the GET to obtain the resource has failed.
ConditionalGetFailed raised when a Conditional Get to refresh the resource has failed.
PutFailed raised when a PUT on the resource has failed.
PostFailed raised when a POST to the resource has failed.
DeleteFailed raised when a DELETE of the resource has failed.
UnparseableJson raised when the response body doesn't parse as JSON.
JsonIsNoResource raised when the structure of the parsed JSON body is not a resource.
HyperlinkMissing raised when a hyperlink isn't available.
To parse as a resource, the JSON must be a wrapped Ocean resource of this format:
{"thing": {
"_links": {
"self": {"href": "https://....", type: "application/json"},
...
},
"foo": 2,
"bar": [1,2,3],
...
}
The above is a Thing resource, wrapped with its type. Attributes should appear in the inner hash, which must have at least a _links
hyperlink attribute with a href and a content type.
If any of the four getters (.get!, .get, #get!, and #get) receive an Ocean collection, the instance method #collection
will return an array of RemoteResources. NB: the getters will still, in all cases, return the RemoteResource itself. The collection is always made available as the value of #collection
on the RemoteResource which was used to obtain it.
To refresh a resource using a conditional GET:
thing.refresh
thing.refresh!
Both return the resource itself, so you can do
thing.refresh['updated_at']
NB: this class can also be used to fetch any JSON data. E.g.:
Api::RemoteResource.get("http://example.com/anything").raw
#raw
will return any raw data received, even if it wasn’t recognised as an Ocean resource and JsonIsNoResource
was raised. The .get
will suppress any exceptions. If #raw
returns nil
, you can always chack #status
, #status_message
, and/or #headers
to determine what went wrong. After fetching non-resource data, #present?
will always be false.
Defined Under Namespace
Classes: ConditionalGetFailed, DeleteFailed, GetFailed, HyperlinkMissing, JsonIsNoResource, PostFailed, PutFailed, UnparseableJson
Instance Attribute Summary collapse
-
#args ⇒ Object
readonly
Returns the value of attribute args.
-
#backoff_max ⇒ Object
readonly
Returns the value of attribute backoff_max.
-
#backoff_rate ⇒ Object
readonly
Returns the value of attribute backoff_rate.
-
#backoff_time ⇒ Object
readonly
Returns the value of attribute backoff_time.
-
#collection ⇒ Object
readonly
Returns the value of attribute collection.
-
#content_type ⇒ Object
readonly
Returns the value of attribute content_type.
-
#credentials ⇒ Object
readonly
Returns the value of attribute credentials.
-
#etag ⇒ Object
readonly
Returns the value of attribute etag.
-
#headers ⇒ Object
readonly
Returns the value of attribute headers.
-
#raw ⇒ Object
readonly
Returns the value of attribute raw.
-
#resource ⇒ Object
readonly
Returns the value of attribute resource.
-
#resource_type ⇒ Object
readonly
Returns the value of attribute resource_type.
-
#response ⇒ Object
readonly
Returns the value of attribute response.
-
#retries ⇒ Object
readonly
Returns the value of attribute retries.
-
#status ⇒ Object
readonly
Returns the value of attribute status.
-
#status_message ⇒ Object
readonly
Returns the value of attribute status_message.
-
#uri ⇒ Object
readonly
Returns the value of attribute uri.
-
#x_api_token ⇒ Object
readonly
Returns the value of attribute x_api_token.
Class Method Summary collapse
-
.get(*args) ⇒ Object
Class method to retrieve a resource.
-
.get!(*args) ⇒ Object
Class method to retrieve a resource.
Instance Method Summary collapse
-
#[](key) ⇒ Object
Returns a resource attribute.
-
#[]=(key, value) ⇒ Object
Sets a resource attribute.
-
#delete(hlink = nil, args: nil) ⇒ Object
Instance method to do a DELETE to a resource or any of its hyperlinks.
-
#delete!(hlink = nil, args: nil) ⇒ Object
Instance method to do a DELETE to a resource or any of its hyperlinks.
-
#get(hlink = nil, args: nil) ⇒ Object
Instance method to GET a resource or any of its hyperlinks.
-
#get!(hlink = nil, args: nil) ⇒ Object
Instance method to GET a resource or any of its hyperlinks.
-
#href ⇒ Object
Returns resources own href.
-
#hyperlink ⇒ Object
Returns the hash of hyperlinks.
-
#initialize(uri, type = "application/json", args: nil, credentials: nil, x_api_token: nil, retries: 3, backoff_time: 1, backoff_rate: 0.9, backoff_max: 30) ⇒ RemoteResource
constructor
The credentials and the x_api_token, if both are left unspecified, will default to the local credentials and service token.
-
#post(hlink = nil, args: nil, body: {}) ⇒ Object
Instance method to do a POST to a resource or any of its hyperlinks.
-
#post!(hlink = nil, args: nil, body: {}) ⇒ Object
Instance method to do a POST to a resource or any of its hyperlinks.
-
#present? ⇒ Boolean
True if the resource has been read successfully.
-
#put(hlink = nil, args: nil, body: {}) ⇒ Object
Instance method to do a PUT to a resource or any of its hyperlinks.
-
#put!(hlink = nil, args: nil, body: {}) ⇒ Object
Instance method to do a PUT to a resource or any of its hyperlinks.
-
#refresh ⇒ Object
If the resource is present and has received an ETag in previous requests, will perform a Conditional GET to update the local representation.
-
#refresh! ⇒ Object
If the resource is present and has received an ETag in previous requests, will perform a Conditional GET to update the local representation.
-
#type ⇒ Object
Returns resources own content type.
Constructor Details
#initialize(uri, type = "application/json", args: nil, credentials: nil, x_api_token: nil, retries: 3, backoff_time: 1, backoff_rate: 0.9, backoff_max: 30) ⇒ RemoteResource
The credentials and the x_api_token, if both are left unspecified, will default to the local credentials and service token. If both are specified and different from the default values, they will be used instead. Specifying only one of them is not permitted.
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/ocean/api_remote_resource.rb', line 146 def initialize(uri, type="application/json", args: nil, credentials: nil, x_api_token: nil, retries: 3, backoff_time: 1, backoff_rate: 0.9, backoff_max: 30) super() @uri = uri @args = args @content_type = type @retries = retries @backoff_time = backoff_time @backoff_rate = backoff_rate @backoff_max = backoff_max @present = false @raw = nil @resource = nil @resource_type = nil @status = nil @status_message = nil @headers = nil @credentials = credentials @x_api_token = x_api_token @collection = false end |
Instance Attribute Details
#args ⇒ Object (readonly)
Returns the value of attribute args.
136 137 138 |
# File 'lib/ocean/api_remote_resource.rb', line 136 def args @args end |
#backoff_max ⇒ Object (readonly)
Returns the value of attribute backoff_max.
136 137 138 |
# File 'lib/ocean/api_remote_resource.rb', line 136 def backoff_max @backoff_max end |
#backoff_rate ⇒ Object (readonly)
Returns the value of attribute backoff_rate.
136 137 138 |
# File 'lib/ocean/api_remote_resource.rb', line 136 def backoff_rate @backoff_rate end |
#backoff_time ⇒ Object (readonly)
Returns the value of attribute backoff_time.
136 137 138 |
# File 'lib/ocean/api_remote_resource.rb', line 136 def backoff_time @backoff_time end |
#collection ⇒ Object
Returns the value of attribute collection.
138 139 140 |
# File 'lib/ocean/api_remote_resource.rb', line 138 def collection @collection end |
#content_type ⇒ Object (readonly)
Returns the value of attribute content_type.
136 137 138 |
# File 'lib/ocean/api_remote_resource.rb', line 136 def content_type @content_type end |
#credentials ⇒ Object (readonly)
Returns the value of attribute credentials.
137 138 139 |
# File 'lib/ocean/api_remote_resource.rb', line 137 def credentials @credentials end |
#etag ⇒ Object
Returns the value of attribute etag.
138 139 140 |
# File 'lib/ocean/api_remote_resource.rb', line 138 def etag @etag end |
#headers ⇒ Object
Returns the value of attribute headers.
137 138 139 |
# File 'lib/ocean/api_remote_resource.rb', line 137 def headers @headers end |
#raw ⇒ Object
Returns the value of attribute raw.
137 138 139 |
# File 'lib/ocean/api_remote_resource.rb', line 137 def raw @raw end |
#resource ⇒ Object
Returns the value of attribute resource.
137 138 139 |
# File 'lib/ocean/api_remote_resource.rb', line 137 def resource @resource end |
#resource_type ⇒ Object
Returns the value of attribute resource_type.
137 138 139 |
# File 'lib/ocean/api_remote_resource.rb', line 137 def resource_type @resource_type end |
#response ⇒ Object
Returns the value of attribute response.
138 139 140 |
# File 'lib/ocean/api_remote_resource.rb', line 138 def response @response end |
#retries ⇒ Object (readonly)
Returns the value of attribute retries.
136 137 138 |
# File 'lib/ocean/api_remote_resource.rb', line 136 def retries @retries end |
#status ⇒ Object
Returns the value of attribute status.
137 138 139 |
# File 'lib/ocean/api_remote_resource.rb', line 137 def status @status end |
#status_message ⇒ Object
Returns the value of attribute status_message.
138 139 140 |
# File 'lib/ocean/api_remote_resource.rb', line 138 def @status_message end |
#uri ⇒ Object (readonly)
Returns the value of attribute uri.
136 137 138 |
# File 'lib/ocean/api_remote_resource.rb', line 136 def uri @uri end |
#x_api_token ⇒ Object (readonly)
Returns the value of attribute x_api_token.
137 138 139 |
# File 'lib/ocean/api_remote_resource.rb', line 137 def x_api_token @x_api_token end |
Class Method Details
.get(*args) ⇒ Object
Class method to retrieve a resource. Will not raise exceptions if problems occur, but will always return the resource itself. The args are passed directly to new
.
268 269 270 271 272 |
# File 'lib/ocean/api_remote_resource.rb', line 268 def self.get(*args) rr = new(*args) x = rr.get! rescue nil x || rr end |
.get!(*args) ⇒ Object
Class method to retrieve a resource. Will raise exceptions if problems occur, otherwise returns the resource itself. The args are passed directly to new
.
260 261 262 |
# File 'lib/ocean/api_remote_resource.rb', line 260 def self.get!(*args) new(*args).send :_retrieve end |
Instance Method Details
#[](key) ⇒ Object
Returns a resource attribute. If the resource isn’t present, get!
will be used to retrieve it.
180 181 182 183 |
# File 'lib/ocean/api_remote_resource.rb', line 180 def [](key) get! unless present? resource[key] end |
#[]=(key, value) ⇒ Object
Sets a resource attribute. The resource will not be retrieved if not present.
188 189 190 |
# File 'lib/ocean/api_remote_resource.rb', line 188 def []=(key, value) resource[key] = value end |
#delete(hlink = nil, args: nil) ⇒ Object
Instance method to do a DELETE to a resource or any of its hyperlinks. Will not raise exceptions if they occur, but will always return the resource itself. A missing hyperlink, though, will always raise a HyperlinkMissing exception.
397 398 399 400 401 402 403 404 |
# File 'lib/ocean/api_remote_resource.rb', line 397 def delete(hlink=nil, args: nil) get hlink = (hlink || 'self').to_s hl_data = hyperlink[hlink] raise HyperlinkMissing, "#{resource_type} has no #{hlink} hyperlink" unless hl_data _destroy(hl_data['href'], args: args) rescue nil self end |
#delete!(hlink = nil, args: nil) ⇒ Object
Instance method to do a DELETE to a resource or any of its hyperlinks. Will raise exceptions if they occur, otherwise will return the resource itself.
383 384 385 386 387 388 389 390 |
# File 'lib/ocean/api_remote_resource.rb', line 383 def delete!(hlink=nil, args: nil) get! hlink = (hlink || 'self').to_s hl_data = hyperlink[hlink] raise HyperlinkMissing, "#{resource_type} has no #{hlink} hyperlink" unless hl_data _destroy(hl_data['href'], args: args) self end |
#get(hlink = nil, args: nil) ⇒ Object
Instance method to GET a resource or any of its hyperlinks. Will not raise exceptions if problems occur, but will always return the resource itself. A missing hyperlink, though, will always raise a HyperlinkMissing exception.
297 298 299 300 301 302 303 304 305 306 307 308 |
# File 'lib/ocean/api_remote_resource.rb', line 297 def get(hlink=nil, args: nil) get! rescue nil hlink = hlink.to_s if hlink if !args && (!hlink || hlink == 'self') self else hl_data = hyperlink[hlink] raise HyperlinkMissing, "#{resource_type} has no #{hlink} hyperlink" unless hl_data RemoteResource.get(hl_data['href'], args: args, retries: retries, backoff_time: backoff_time, backoff_rate: backoff_rate, backoff_max: backoff_max) end end |
#get!(hlink = nil, args: nil) ⇒ Object
Instance method to GET a resource or any of its hyperlinks. Will raise exceptions if they occur, otherwise will return the resource itself.
279 280 281 282 283 284 285 286 287 288 289 290 |
# File 'lib/ocean/api_remote_resource.rb', line 279 def get!(hlink=nil, args: nil) _retrieve unless present? hlink = hlink.to_s if hlink if !args && (!hlink || hlink == 'self') self else hl_data = hyperlink[hlink] raise HyperlinkMissing, "#{resource_type} has no #{hlink} hyperlink" unless hl_data RemoteResource.get!(hl_data['href'], args: args, retries: retries, backoff_time: backoff_time, backoff_rate: backoff_rate, backoff_max: backoff_max) end end |
#href ⇒ Object
Returns resources own href. The resource will not be retrieved if not present.
202 203 204 |
# File 'lib/ocean/api_remote_resource.rb', line 202 def href hyperlink['self']['href'] end |
#hyperlink ⇒ Object
Returns the hash of hyperlinks. The resource will not be retrieved if not present.
195 196 197 |
# File 'lib/ocean/api_remote_resource.rb', line 195 def hyperlink self['_links'] end |
#post(hlink = nil, args: nil, body: {}) ⇒ Object
Instance method to do a POST to a resource or any of its hyperlinks. Will not raise exceptions if they occur, but will always return the resource itself. A missing hyperlink, though, will always raise a HyperlinkMissing exception.
370 371 372 373 374 375 376 |
# File 'lib/ocean/api_remote_resource.rb', line 370 def post(hlink=nil, args: nil, body: {}) get hlink = (hlink || !args && 'self').to_s hl_data = hyperlink[hlink] raise HyperlinkMissing, "#{resource_type} has no #{hlink} hyperlink" unless hl_data _create(hl_data['href'], body, args: args) rescue nil end |
#post!(hlink = nil, args: nil, body: {}) ⇒ Object
Instance method to do a POST to a resource or any of its hyperlinks. Will raise exceptions if they occur, otherwise will return the resource itself.
357 358 359 360 361 362 363 |
# File 'lib/ocean/api_remote_resource.rb', line 357 def post!(hlink=nil, args: nil, body: {}) get! hlink = (hlink || !args && 'self').to_s hl_data = hyperlink[hlink] raise HyperlinkMissing, "#{resource_type} has no #{hlink} hyperlink" unless hl_data _create(hl_data['href'], body, args: args) end |
#present? ⇒ Boolean
True if the resource has been read successfully.
172 173 174 |
# File 'lib/ocean/api_remote_resource.rb', line 172 def present? @present end |
#put(hlink = nil, args: nil, body: {}) ⇒ Object
Instance method to do a PUT to a resource or any of its hyperlinks. Will not raise exceptions if they occur, but will always return the resource itself. A missing hyperlink, though, will always raise a HyperlinkMissing exception.
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 |
# File 'lib/ocean/api_remote_resource.rb', line 336 def put(hlink=nil, args: nil, body: {}) get hlink = hlink.to_s if hlink if !args && (!hlink || hlink == 'self') _modify(body) rescue nil self else hl_data = hyperlink[hlink] raise HyperlinkMissing, "#{resource_type} has no #{hlink} hyperlink" unless hl_data hl_res = RemoteResource.new(hl_data['href'], retries: retries, backoff_time: backoff_time, backoff_rate: backoff_rate, backoff_max: backoff_max) hl_res.send :_modify, body, args: args hl_res end end |
#put!(hlink = nil, args: nil, body: {}) ⇒ Object
Instance method to do a PUT to a resource or any of its hyperlinks. Will raise exceptions if they occur, otherwise will return the resource itself.
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 |
# File 'lib/ocean/api_remote_resource.rb', line 315 def put!(hlink=nil, args: nil, body: {}) get! hlink = hlink.to_s if hlink if !args && (!hlink || hlink == 'self') _modify(body) self else hl_data = hyperlink[hlink] raise HyperlinkMissing, "#{resource_type} has no #{hlink} hyperlink" unless hl_data hl_res = RemoteResource.new(hl_data['href'], retries: retries, backoff_time: backoff_time, backoff_rate: backoff_rate, backoff_max: backoff_max) hl_res.send :_modify, body, args: args hl_res end end |
#refresh ⇒ Object
If the resource is present and has received an ETag in previous requests, will perform a Conditional GET to update the local representation. If the resource isn’t present or has no ETag, a normal #get
will be done. The resource will always be returned.
427 428 429 430 431 432 433 |
# File 'lib/ocean/api_remote_resource.rb', line 427 def refresh if present? && etag.present? (_conditional_get rescue nil) || self else get end end |
#refresh! ⇒ Object
If the resource is present and has received an ETag in previous requests, will perform a Conditional GET to update the local representation. If the resource isn’t present or has no ETag, a normal #get!
will be done. If no exception is raised, the resource itself is returned.
413 414 415 416 417 418 419 |
# File 'lib/ocean/api_remote_resource.rb', line 413 def refresh! if present? && etag.present? _conditional_get || self else get! end end |
#type ⇒ Object
Returns resources own content type. The resource will not be retrieved if not present.
209 210 211 |
# File 'lib/ocean/api_remote_resource.rb', line 209 def type hyperlink['self']['type'] end |