reynard 0.8.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 96421332b89c0816b77704aba7b07f267424c0a238fd5b74c8b91aa9d3943c6d
4
- data.tar.gz: a6a714f984bd420fe2254b747972ba804968cc4df6ca534b38c50c1cf2b2687b
3
+ metadata.gz: 2942c304a1a9caaae88253e2bce40188b79bb8a5d25ccd93c8e9a04f7730e386
4
+ data.tar.gz: 12948419634f2926ae083ae364bd35f48a6b79b8f6308df95b80baafe061dce6
5
5
  SHA512:
6
- metadata.gz: 7cbb02d762e3c38b05b59ec25f8320f3a5830b56aabe376249f2347a098b43cff31935829d9dd831edc383a62531a06b78e735d886bf4f2329475e8785820211
7
- data.tar.gz: 767b9ba9f0f5eb3fae98d414f778e481fd6b3c0a928128cec29b3a409db44481057afc44c9ac029a98892b71c3d3e09fd80286e0b2e942e47aef97b2921fab22
6
+ metadata.gz: 2bcf669808d10dfff594861274b301ff77c99038ddea5e121b0ccd61336beb7089e6c20f4e566c9a29e5b813194f5b79d07c7c067c720b6b303de8c07e862944
7
+ data.tar.gz: 64f7877a9a9e44c77cb357ff36d2ecac691cfce668dc2ba2197f0b68a284e0127fab96c099ca3cb99c0390658466a4fcda3569a2e2479e643d73f95d06cf2a16
data/README.md CHANGED
@@ -48,7 +48,7 @@ reynard.base_url(base_url)
48
48
 
49
49
  ## Calling endpoints
50
50
 
51
- Assuming there is an operation called `employeeByUuid` you can it as shown below.
51
+ Assuming there is an operation with the `operationId` set to `employeeByUuid` you can perform a request as shown below. Note that `operationId` is a required property in the specs.
52
52
 
53
53
  ```ruby
54
54
  response = reynard.
@@ -57,7 +57,7 @@ response = reynard.
57
57
  execute
58
58
  ```
59
59
 
60
- When an operation requires a body, you can add it as structured data.
60
+ When an operation requires a body, you can add it as structured data. It will be converted to JSON automatically.
61
61
 
62
62
  ```ruby
63
63
  response = reynard.
@@ -66,13 +66,7 @@ response = reynard.
66
66
  execute
67
67
  ```
68
68
 
69
- In case the response matches a response in the specification it will attempt to build an object using the specified schema.
70
-
71
- ```ruby
72
- response.object.name #=> 'Sam Seven'
73
- ```
74
-
75
- The response object shared much of its interface with `Net::HTTP::Response`.
69
+ The response object shares much of its interface with `Net::HTTP::Response`.
76
70
 
77
71
  ```ruby
78
72
  response.code #=> '200'
@@ -82,6 +76,24 @@ response.body #=> '{"name":"Sam Seven"}'
82
76
  response.parsed_body #=> { "name" => "Sam Seven" }
83
77
  ```
84
78
 
79
+ You can test for groups of response codes, basically matching `1xx` through `5xx`.
80
+
81
+ ```ruby
82
+ response.informational?
83
+ response.success?
84
+ response.redirection?
85
+ response.client_error?
86
+ response.server_error?
87
+ ```
88
+
89
+ In case the response status and content-type matches a response in the specification it will attempt to build an object using the specified schema.
90
+
91
+ ```ruby
92
+ response.object.name #=> 'Sam Seven'
93
+ ```
94
+
95
+ See below for more details about the object builder.
96
+
85
97
  ## Schema and models
86
98
 
87
99
  Reynard has an object builder that allows you to get a value object backed by model classes based on the resource schema.
@@ -189,7 +201,7 @@ There are two alternatives for accessing this property:
189
201
  # parsed JSON on the response object.
190
202
  response.parsed_body["1st-class"]
191
203
  # When you are processing nested models and you don't have access to the
192
- # response object, you can chose to use the `[]` method.
204
+ # response object, you can choose to use the `[]` method.
193
205
  response.object["1st-class"]
194
206
  # Don't use `send` to access the property, this may not work in future
195
207
  # versions.
@@ -198,7 +210,7 @@ response.object.send("1st-class")
198
210
 
199
211
  #### Mapping properties
200
212
 
201
- In case you are forced to access a property through a method, you could chose to map irregular property names to method names globally for all models:
213
+ In case you are forced to access a property through a method, you could choose to map irregular property names to method names globally for all models:
202
214
 
203
215
  ```ruby
204
216
  reynard.snake_cases({ "1st-class" => "first_class" })
@@ -218,6 +230,82 @@ Don't use this to map common property names that would work fine otherwise, beca
218
230
  reynard.snake_cases({ "name" => "naem" })
219
231
  ```
220
232
 
233
+ ### Optional properties
234
+
235
+ The current version of Reynard does not read or enforce the properties defined in the schema, instead it builds the response object based on the properties returned by the service. This was done deliberately to make it easier to access a server with a newer or older schema than the one used to build the Reynard instance.
236
+
237
+ In the code that means that you may have to check if you are receiving certain attributes, you can do this in a number of ways:
238
+
239
+ ```ruby
240
+ response.object.respond_to?(:name)
241
+ response.parsed_body["name"]
242
+ response.object["name"]
243
+ ```
244
+
245
+ ### Taking control of a model
246
+
247
+ As noted earlier there is a deterministic way in which Reynard decides on a model name. This means that you can define the model name before Reynard gets to it.
248
+
249
+ The easiest way to find out how Reynard does this, is to actually perform the operation and look at the response. Let's look at an example where Reynard creates a `Library` model:
250
+
251
+ ```ruby
252
+ response.object.class #=> Reynard::Models::Library
253
+ response.parsed_body #=> {"name" => "Alexandria"}
254
+ ```
255
+
256
+ One way to ensure that the response object has the required attributes is to defined a `valid?` method on it:
257
+
258
+
259
+ ```ruby
260
+ class Reynard
261
+ module Models
262
+ class Library < Reynard::Model
263
+ def valid?
264
+ (%w[name] - @attributes.keys).empty?
265
+ end
266
+ end
267
+ end
268
+ end
269
+ ```
270
+
271
+ Next time you perform a request you can use your version of `Library`:
272
+
273
+ ```ruby
274
+ if response.object.valid?
275
+ puts "The library is valid!"
276
+ else
277
+ puts "The library is not valid :-( #{response.parsed_object.inspect}"
278
+ end
279
+ ```
280
+
281
+ Another way to do this is to override the `attributes=` method.
282
+
283
+ ```ruby
284
+ def attributes=(attributes)
285
+ super # call super or nested attributes and other features will break
286
+ raise_invalid unless valid?
287
+ end
288
+
289
+ private
290
+
291
+ def raise_invalid
292
+ return if valid?
293
+
294
+ raise(
295
+ ArgumentError,
296
+ "Library may not be initialized without all required attributes."
297
+ )
298
+ end
299
+ ```
300
+
301
+ A third way of dealing with optional attributes is to define an accessor yourself.
302
+
303
+ ```ruby
304
+ def name
305
+ @attributes.fetch("name") { "Unnnamed library" }
306
+ end
307
+ ```
308
+
221
309
  ## Logging
222
310
 
223
311
  When you want to know what the Reynard client is doing you can enable logging.
@@ -234,6 +322,19 @@ The logging should be compatible with the Ruby on Rails logger.
234
322
  reynard.logger(Rails.logger).execute
235
323
  ```
236
324
 
325
+ ## Headers
326
+
327
+ You can add request headers at any time to a Reynard context, these are additive so you can easily have global headers for all requests and specific ones for an operation.
328
+
329
+ ```ruby
330
+ reynard = reynard.headers(
331
+ {
332
+ "User-Agent" => "MyApplication/12.1.1 Reynard/#{Reynard::VERSION}",
333
+ "Accept" => "application/json"
334
+ }
335
+ )
336
+ ```
337
+
237
338
  ## Debugging
238
339
 
239
340
  You can turn on debug logging in `Net::HTTP` by setting the `DEBUG` environment variable. After setting this, all HTTP interaction will be written to STDERR.
data/lib/reynard/model.rb CHANGED
@@ -28,7 +28,11 @@ class Reynard
28
28
  # Until we can set accessors based on the schema
29
29
  def method_missing(attribute_name, *)
30
30
  attribute_name = attribute_name.to_s
31
- @attributes[attribute_name] || @attributes.fetch(@snake_cases.fetch(attribute_name))
31
+ if @attributes.key?(attribute_name)
32
+ @attributes[attribute_name]
33
+ else
34
+ @attributes.fetch(@snake_cases.fetch(attribute_name))
35
+ end
32
36
  rescue KeyError
33
37
  raise NoMethodError, "undefined method `#{attribute_name}' for #{inspect}"
34
38
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Reynard
4
- VERSION = '0.8.0'
4
+ VERSION = '0.8.1'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reynard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Manfred Stienstra
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-07 00:00:00.000000000 Z
11
+ date: 2023-07-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: multi_json