petail 0.3.0 → 0.4.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/README.adoc +25 -9
- data/lib/petail/payload.rb +14 -8
- data/petail.gemspec +1 -1
- data.tar.gz.sig +0 -0
- metadata +1 -1
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 90ccb34a36bfc17201ce4b4881e8f37acbbc3714f076c5de0e7cf1d5ad373346
|
4
|
+
data.tar.gz: 0a2ee99b2cd3191aa9ec08473a218436bd259576f3b0e6e31c8779eddcbfe5b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b663a7f90af61259298cd14a8f23c63afbd0d0e6aab80c3c38c0242e7cc240418563021623bcf95e7af88e3368788bdad8ac30178431788f4cc3e552219815b7
|
7
|
+
data.tar.gz: 6efc822522e3e828df9c2d81953a8b2a2344e6ec9aec462ebe063cb32feffcc10552b4f874b67888d3e347875a805621df317b429d2a57227ecb55e061530611
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/README.adoc
CHANGED
@@ -86,6 +86,17 @@ payload.to_xml
|
|
86
86
|
|
87
87
|
💡 You can also use `Petail.new` to create instances if you don't like `Petail.[]`, as shown above, but `.[]` is preferred.
|
88
88
|
|
89
|
+
=== Members
|
90
|
+
|
91
|
+
As briefly shown above, the minimum members (attributes) that make up problem details are:
|
92
|
+
|
93
|
+
* `type` (optional): The full (or relative) URI that links to additional documentation. Default: `"about:blank"`.
|
94
|
+
* `status` (optional): The link:https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status[HTTP status code] (or symbol) that must match your HTTP status code. Default: `nil`.
|
95
|
+
* `title` (optional): The HTTP status label that must match your HTTP status code label. Default: HTTP status label (dynamically computed based on code unless overwritten).
|
96
|
+
* `detail` (optional): The human readable reason for the error (should not include debugging information). Default: `nil`.
|
97
|
+
* `instance` (optional): The full (or relative) URI that represents the cause of the error. Default: `nil`.
|
98
|
+
* `extensions` (optional): A free form hash of additional details. Default: `{}`.
|
99
|
+
|
89
100
|
=== Media Types
|
90
101
|
|
91
102
|
For convenience, you can obtain the necessary media types for your HTTP headers as follows:
|
@@ -187,7 +198,7 @@ This means you can serialize as follows:
|
|
187
198
|
[source,ruby]
|
188
199
|
----
|
189
200
|
payload.to_json
|
190
|
-
# {"type"
|
201
|
+
# "{\"type\":\"https://test.io/problem_details/out_of_credit\",\"title\":\"You do not have enough credit.\",\"status\":403,\"detail\":\"Your current balance is 30, but that costs 50.\",\"instance\":\"/accounts/1\",\"balance\":30,\"accounts\":[\"/accounts/1\",\"/accounts/10\"]}"
|
191
202
|
|
192
203
|
payload.to_json indent: " ", space: " ", object_nl: "\n", array_nl: "\n"
|
193
204
|
# {
|
@@ -196,13 +207,11 @@ payload.to_json indent: " ", space: " ", object_nl: "\n", array_nl: "\n"
|
|
196
207
|
# "status": 403,
|
197
208
|
# "detail": "Your current balance is 30, but that costs 50.",
|
198
209
|
# "instance": "/accounts/1",
|
199
|
-
# "
|
200
|
-
#
|
201
|
-
# "accounts"
|
202
|
-
#
|
203
|
-
#
|
204
|
-
# ]
|
205
|
-
# }
|
210
|
+
# "balance": 30,
|
211
|
+
# "accounts": [
|
212
|
+
# "/accounts/1",
|
213
|
+
# "/accounts/10"
|
214
|
+
# ]
|
206
215
|
# }
|
207
216
|
----
|
208
217
|
|
@@ -212,7 +221,7 @@ You can also deserialize by taking the result of the above and turning the raw J
|
|
212
221
|
|
213
222
|
[source,ruby]
|
214
223
|
----
|
215
|
-
Petail.from_json "{\"type\":\"https://test.io/problem_details/out_of_credit\",\"title\":\"You do not have enough credit.\",\"status\":403,\"detail\":\"Your current balance is 30, but that costs 50.\",\"instance\":\"/accounts/1\",\"
|
224
|
+
Petail.from_json "{\"type\":\"https://test.io/problem_details/out_of_credit\",\"title\":\"You do not have enough credit.\",\"status\":403,\"detail\":\"Your current balance is 30, but that costs 50.\",\"instance\":\"/accounts/1\",\"balance\":30,\"accounts\":[\"/accounts/1\",\"/accounts/10\"]}"
|
216
225
|
|
217
226
|
# #<Struct:Petail::Payload:0x00007670
|
218
227
|
# detail = "Your current balance is 30, but that costs 50.",
|
@@ -353,6 +362,13 @@ To test, run:
|
|
353
362
|
bin/rake
|
354
363
|
----
|
355
364
|
|
365
|
+
== Resources
|
366
|
+
|
367
|
+
You can find additional resources here:
|
368
|
+
|
369
|
+
* link:https://www.iana.org/assignments/http-problem-types/http-problem-types.xhtml[IANA Hypertext Transfer Protocol (HTTP) Problem Types]: A registered list of problem types you can use.
|
370
|
+
* link:https://github.com/protocol-registries/http-problem-types[HTTP Problem Type Registration Requests]: Where you can register new problem types.
|
371
|
+
|
356
372
|
== link:https://alchemists.io/policies/license[License]
|
357
373
|
|
358
374
|
== link:https://alchemists.io/policies/security[Security]
|
data/lib/petail/payload.rb
CHANGED
@@ -5,8 +5,10 @@ require "rack/utils"
|
|
5
5
|
require "rexml"
|
6
6
|
|
7
7
|
module Petail
|
8
|
+
PRIMARY_KEYS = %i[type title status detail instance].freeze
|
9
|
+
|
8
10
|
# Models the problem details response payload.
|
9
|
-
Payload = Struct.new
|
11
|
+
Payload = Struct.new(*PRIMARY_KEYS, :extensions) do
|
10
12
|
def self.for(**attributes)
|
11
13
|
status = attributes.delete(:status).then { Rack::Utils.status_code it if it }
|
12
14
|
title = attributes.delete(:title).then { it || Rack::Utils::HTTP_STATUS_CODES[status] }
|
@@ -14,18 +16,23 @@ module Petail
|
|
14
16
|
new title:, status:, **attributes
|
15
17
|
end
|
16
18
|
|
17
|
-
def self.from_json
|
19
|
+
def self.from_json body
|
20
|
+
attributes = JSON body, symbolize_names: true
|
21
|
+
extensions = attributes.reject { |key| PRIMARY_KEYS.include? key }
|
22
|
+
|
23
|
+
self.for(**attributes.slice(*PRIMARY_KEYS), extensions:)
|
24
|
+
end
|
18
25
|
|
19
26
|
# :reek:TooManyStatements
|
20
27
|
def self.from_xml body, deserializer: XML::Deserializer
|
21
28
|
elements = REXML::Document.new(body).root.elements
|
22
29
|
|
23
30
|
attributes = elements.each_with_object({extensions: {}}) do |element, collection|
|
24
|
-
name = element.name
|
31
|
+
name = element.name.to_sym
|
25
32
|
text = element.text
|
26
33
|
|
27
34
|
case name
|
28
|
-
when
|
35
|
+
when *PRIMARY_KEYS then collection[name] = text
|
29
36
|
else collection[:extensions].merge! deserializer.call(element)
|
30
37
|
end
|
31
38
|
end
|
@@ -48,11 +55,12 @@ module Petail
|
|
48
55
|
|
49
56
|
def extension?(name) = extensions.key? name
|
50
57
|
|
51
|
-
def to_h =
|
58
|
+
def to_h = {type:, title:, status:, detail:, instance:, **extensions}.compact
|
52
59
|
|
53
60
|
def to_json(*) = to_h.to_json(*)
|
54
61
|
|
55
62
|
# :reek:TooManyStatements
|
63
|
+
# :reek:FeatureEnvy
|
56
64
|
def to_xml(serializer: XML::Serializer, **options)
|
57
65
|
document = REXML::Document.new
|
58
66
|
document.add REXML::XMLDecl.new("1.0", "UTF-8")
|
@@ -60,9 +68,7 @@ module Petail
|
|
60
68
|
problem = REXML::Element.new("problem").add_namespace("urn:ietf:rfc:7807")
|
61
69
|
document.add problem
|
62
70
|
|
63
|
-
|
64
|
-
attributes.merge! attributes.delete :extensions if extensions.any?
|
65
|
-
attributes.each { |name, value| serializer.call name, value, problem }
|
71
|
+
to_h.each { |name, value| serializer.call name, value, problem }
|
66
72
|
|
67
73
|
"".dup.tap { document.write(**options, output: it) }
|
68
74
|
end
|
data/petail.gemspec
CHANGED
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
metadata.gz.sig
CHANGED
Binary file
|