shaf_client 0.6.2 → 1.1.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.tar.gz.sig +0 -0
- data/bin/shaf_client +30 -0
- data/lib/faraday_http_cache_patch.rb +17 -0
- data/lib/shaf_client.rb +27 -19
- data/lib/shaf_client/alps/descriptor.rb +60 -0
- data/lib/shaf_client/alps/extension.rb +35 -0
- data/lib/shaf_client/alps_json.rb +44 -0
- data/lib/shaf_client/api_error.rb +2 -1
- data/lib/shaf_client/base_resource.rb +63 -23
- data/lib/shaf_client/content_type_map.rb +53 -0
- data/lib/shaf_client/curie.rb +4 -0
- data/lib/shaf_client/empty_resource.rb +1 -1
- data/lib/shaf_client/hal_form.rb +1 -1
- data/lib/shaf_client/hypertext_cache_strategy.rb +43 -0
- data/lib/shaf_client/link.rb +2 -2
- data/lib/shaf_client/mime_types.rb +8 -0
- data/lib/shaf_client/problem_json.rb +38 -0
- data/lib/shaf_client/resource.rb +74 -10
- data/lib/shaf_client/resource_extension.rb +36 -0
- data/lib/shaf_client/resource_extension/alps_http_method.rb +67 -0
- data/lib/shaf_client/resource_extension/base.rb +13 -0
- data/lib/shaf_client/resource_mapper.rb +86 -10
- data/lib/shaf_client/shaf_form.rb +3 -2
- data/lib/shaf_client/status_codes.rb +70 -0
- data/lib/shaf_client/test/stubbing.rb +16 -0
- data/lib/shaf_client/unknown_resource.rb +3 -3
- data/lib/shaf_client/version.rb +3 -0
- metadata +58 -29
- metadata.gz.sig +0 -0
@@ -1,18 +1,26 @@
|
|
1
1
|
require 'shaf_client/error'
|
2
|
+
require 'shaf_client/content_type_map'
|
3
|
+
require 'shaf_client/resource_extension'
|
2
4
|
|
3
5
|
class ShafClient
|
4
|
-
|
6
|
+
module ResourceMapper
|
5
7
|
class << self
|
6
|
-
def for(content_type)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
def for(content_type:, headers: {}, payload: nil, client: nil)
|
9
|
+
content_type = content_type&.to_sym
|
10
|
+
profile = profile_from(content_type, headers, payload)
|
11
|
+
clazz, extensions = result_for(content_type, payload, profile, client)
|
12
|
+
|
13
|
+
raise_unsupported_error(content_type) unless clazz
|
14
|
+
|
15
|
+
[clazz, extensions]
|
16
|
+
end
|
17
|
+
|
18
|
+
def register(content_type, profile = nil, clazz)
|
19
|
+
mapping[content_type&.to_sym, profile] = clazz
|
12
20
|
end
|
13
21
|
|
14
|
-
def
|
15
|
-
mapping
|
22
|
+
def unregister(content_type, profile = nil)
|
23
|
+
mapping.delete(content_type.to_sym, profile)
|
16
24
|
end
|
17
25
|
|
18
26
|
def default=(clazz)
|
@@ -22,7 +30,75 @@ class ShafClient
|
|
22
30
|
private
|
23
31
|
|
24
32
|
def mapping
|
25
|
-
@mapping ||=
|
33
|
+
@mapping ||= ContentTypeMap.new
|
34
|
+
end
|
35
|
+
|
36
|
+
def result_for(content_type, payload, profile, client)
|
37
|
+
clazz = nil
|
38
|
+
extensions = []
|
39
|
+
|
40
|
+
# Note: mapping typically has a default value, so we need to check that the key really exist
|
41
|
+
if mapping.key? content_type, profile
|
42
|
+
# Registered classes with profile takes precedence over linked profiles
|
43
|
+
clazz = mapping[content_type, profile]
|
44
|
+
else
|
45
|
+
clazz = mapping[content_type]
|
46
|
+
extensions = extensions_for(clazz, profile, payload, client) if profile
|
47
|
+
end
|
48
|
+
|
49
|
+
[clazz, extensions]
|
50
|
+
end
|
51
|
+
|
52
|
+
def profile_from(content_type, headers, payload)
|
53
|
+
profile_from_content_type(content_type) ||
|
54
|
+
profile_from_link_header(headers) ||
|
55
|
+
profile_from_payload_link(content_type, payload)
|
56
|
+
rescue StandardError => err
|
57
|
+
warn "Exception while looking up profile link relation: #{err}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def profile_from_content_type(content_type)
|
61
|
+
return unless content_type
|
62
|
+
|
63
|
+
content_type[/profile="?([^"\s;]*)/, 1]
|
64
|
+
end
|
65
|
+
|
66
|
+
def profile_from_link_header(headers)
|
67
|
+
links = String(headers["link"] || headers["Link"]).split(',')
|
68
|
+
profile_link = links.find { |link| link.match?(/rel="?profile"?/) }
|
69
|
+
profile_link[/<(.*)>/, 1] if profile_link
|
70
|
+
end
|
71
|
+
|
72
|
+
def profile_from_payload_link(content_type, payload)
|
73
|
+
clazz = mapping[content_type]
|
74
|
+
resource = clazz&.new(nil, payload)
|
75
|
+
return unless resource.respond_to? :link
|
76
|
+
|
77
|
+
link = resource.link(:profile) { nil }
|
78
|
+
link&.href
|
79
|
+
end
|
80
|
+
|
81
|
+
def extensions_for(clazz, profile, payload, client)
|
82
|
+
return [] unless clazz && profile && client
|
83
|
+
|
84
|
+
profile_resource = fetch_profile(profile, client)
|
85
|
+
link_relations = clazz.new(nil, payload).actions if payload
|
86
|
+
|
87
|
+
ResourceExtension.for(profile_resource, clazz, link_relations, client)
|
88
|
+
rescue StandardError => err
|
89
|
+
warn "Exception while resolving extensions for profile " \
|
90
|
+
"#{profile_resource&.name || profile}: #{err}"
|
91
|
+
[]
|
92
|
+
end
|
93
|
+
|
94
|
+
def fetch_profile(profile, client)
|
95
|
+
return unless profile&.start_with? %r{https?://}
|
96
|
+
|
97
|
+
client.get(profile)
|
98
|
+
end
|
99
|
+
|
100
|
+
def raise_unsupported_error(content_type)
|
101
|
+
raise UnSupportedContentType, "Can't handle Content-Type: #{content_type}"
|
26
102
|
end
|
27
103
|
end
|
28
104
|
end
|
@@ -3,7 +3,8 @@ require 'shaf_client/form'
|
|
3
3
|
class ShafClient
|
4
4
|
class ShafForm < Form
|
5
5
|
|
6
|
-
profile 'shaf-form'
|
6
|
+
profile 'shaf-form' # Legacy profiles
|
7
|
+
profile 'urn:shaf:form' # New style. Shaf version >= 2.1.0
|
7
8
|
|
8
9
|
def title
|
9
10
|
attribute(:title)
|
@@ -27,7 +28,7 @@ class ShafClient
|
|
27
28
|
|
28
29
|
def fields
|
29
30
|
attribute(:fields).map do |values|
|
30
|
-
Field.new(values.transform_keys(&:to_sym))
|
31
|
+
Field.new(**values.transform_keys(&:to_sym))
|
31
32
|
end
|
32
33
|
end
|
33
34
|
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
class ShafClient
|
2
|
+
module StatusCodes
|
3
|
+
StatusCode = {
|
4
|
+
100 => 'Continue',
|
5
|
+
101 => 'Switching Protocols',
|
6
|
+
102 => 'Processing',
|
7
|
+
103 => 'Early Hints',
|
8
|
+
200 => 'OK',
|
9
|
+
201 => 'Created',
|
10
|
+
202 => 'Accepted',
|
11
|
+
203 => 'Non-Authoritative Information',
|
12
|
+
204 => 'No Content',
|
13
|
+
205 => 'Reset Content',
|
14
|
+
206 => 'Partial Content',
|
15
|
+
207 => 'Multi-Status',
|
16
|
+
208 => 'Already Reported',
|
17
|
+
226 => 'IM Used',
|
18
|
+
300 => 'Multiple Choices',
|
19
|
+
301 => 'Moved Permanently',
|
20
|
+
302 => 'Found',
|
21
|
+
303 => 'See Other',
|
22
|
+
304 => 'Not Modified',
|
23
|
+
305 => 'Use Proxy',
|
24
|
+
306 => '(Unused)',
|
25
|
+
307 => 'Temporary Redirect',
|
26
|
+
308 => 'Permanent Redirect',
|
27
|
+
400 => 'Bad Request',
|
28
|
+
401 => 'Unauthorized',
|
29
|
+
402 => 'Payment Required',
|
30
|
+
403 => 'Forbidden',
|
31
|
+
404 => 'Not Found',
|
32
|
+
405 => 'Method Not Allowed',
|
33
|
+
406 => 'Not Acceptable',
|
34
|
+
407 => 'Proxy Authentication Required',
|
35
|
+
408 => 'Request Timeout',
|
36
|
+
409 => 'Conflict',
|
37
|
+
410 => 'Gone',
|
38
|
+
411 => 'Length Required',
|
39
|
+
412 => 'Precondition Failed',
|
40
|
+
413 => 'Payload Too Large',
|
41
|
+
414 => 'URI Too Long',
|
42
|
+
415 => 'Unsupported Media Type',
|
43
|
+
416 => 'Range Not Satisfiable',
|
44
|
+
417 => 'Expectation Failed',
|
45
|
+
421 => 'Misdirected Request',
|
46
|
+
422 => 'Unprocessable Entity',
|
47
|
+
423 => 'Locked',
|
48
|
+
424 => 'Failed Dependency',
|
49
|
+
425 => 'Too Early',
|
50
|
+
426 => 'Upgrade Required',
|
51
|
+
428 => 'Precondition Required',
|
52
|
+
429 => 'Too Many Requests',
|
53
|
+
431 => 'Request Header Fields Too Large',
|
54
|
+
451 => 'Unavailable For Legal Reasons',
|
55
|
+
500 => 'Internal Server Error',
|
56
|
+
501 => 'Not Implemented',
|
57
|
+
502 => 'Bad Gateway',
|
58
|
+
503 => 'Service Unavailable',
|
59
|
+
504 => 'Gateway Timeout',
|
60
|
+
505 => 'HTTP Version Not Supported',
|
61
|
+
506 => 'Variant Also Negotiates',
|
62
|
+
507 => 'Insufficient Storage',
|
63
|
+
508 => 'Loop Detected',
|
64
|
+
510 => 'Not Extended',
|
65
|
+
511 => 'Network Authentication Required',
|
66
|
+
}
|
67
|
+
StatusCode.default = 'Unassigned'
|
68
|
+
StatusCode.freeze
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class ShafClient
|
2
|
+
module Test
|
3
|
+
module Stubbing
|
4
|
+
def stubs
|
5
|
+
return unless @adapter == :test
|
6
|
+
@stubs ||= Faraday::Adapter::Test::Stubs.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def adapter_args
|
10
|
+
args = super
|
11
|
+
args << stubs if @adapter == :test
|
12
|
+
args
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -2,9 +2,9 @@ require 'shaf_client/resource'
|
|
2
2
|
|
3
3
|
class ShafClient
|
4
4
|
class UnknownResource < Resource
|
5
|
-
|
5
|
+
default_resource_class!
|
6
6
|
|
7
|
-
|
7
|
+
attr_reader :http_status, :headers, :body
|
8
8
|
|
9
9
|
def initialize(_client, payload, status = nil, headers = {})
|
10
10
|
@body = payload.freeze
|
@@ -22,7 +22,7 @@ class ShafClient
|
|
22
22
|
|
23
23
|
%i[get put post delete patch, get_doc, reload!].each do |method|
|
24
24
|
define_method(method) do |*_args|
|
25
|
-
raise "UnknownResource: #{method} not available"
|
25
|
+
raise Error, "UnknownResource: #{method} not available"
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shaf_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sammy Henningsson
|
@@ -10,27 +10,26 @@ bindir: bin
|
|
10
10
|
cert_chain:
|
11
11
|
- |
|
12
12
|
-----BEGIN CERTIFICATE-----
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
M40=
|
13
|
+
MIIDVjCCAj6gAwIBAgIBATANBgkqhkiG9w0BAQsFADAqMSgwJgYDVQQDDB9zYW1t
|
14
|
+
eS5oZW5uaW5nc3Nvbi9EQz1oZXkvREM9Y29tMB4XDTIxMDIwMjEzNTY1OFoXDTIy
|
15
|
+
MDIwMjEzNTY1OFowKjEoMCYGA1UEAwwfc2FtbXkuaGVubmluZ3Nzb24vREM9aGV5
|
16
|
+
L0RDPWNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK+SDC1mfyhu
|
17
|
+
cJ6Va21rIHUGscEtQrdvyBqxFG1s2TgPMAv4RbqwdJVPa7kjtbCzslADlUE1oru2
|
18
|
+
C+rcJsMtVGX02ukMIPHT1OjTyy0/EMqLqSy3WeRI8APyDSxCVbe+h5BMf3zZnYfd
|
19
|
+
dR6AeG7ln09T1P/tX+9lTMc+I+DW1fUlQgY48CNUayvtJR61svXvXMrhLhi29SQi
|
20
|
+
g1qmH6Zoe22/JgH+m2JksPndY5Ep3gqfDc6Imwu2vGvmGErJD63FB0XQ/wb4WVH4
|
21
|
+
l7sHQSTfKDp8SImCt1xqNgIyjw578ZG2geGLoncuxgDrbQ/UFIJ11lDZd4vLevMh
|
22
|
+
nIxTSJpPr2cCAwEAAaOBhjCBgzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNV
|
23
|
+
HQ4EFgQUukjj1Cd2ea6IOHDLZe0ymzs2jWkwJAYDVR0RBB0wG4EZc2FtbXkuaGVu
|
24
|
+
bmluZ3Nzb25AaGV5LmNvbTAkBgNVHRIEHTAbgRlzYW1teS5oZW5uaW5nc3NvbkBo
|
25
|
+
ZXkuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQBt310FZ56E/fp/y5Wym1xb4C0owfnI
|
26
|
+
LzUqOjXWZTO7RezlBJV/qIwqt6bEjYDQR56zULJFSp4YdoDsratmQ+/kwtbHF7xf
|
27
|
+
WYkSE36mhLP2ggQFH9fXtX6XdyIlwFqwEfNW73ZrkBXGjMxLVKIS9uHdN7PoNhbS
|
28
|
+
0YjOZZD/rq1Jf+klwl/G7bBDPjn58DWlUmwzoj49goGS/UBG37RssQxRwPelKHZh
|
29
|
+
5ZlcHq9h5CxVt380OKaU6wMg95RJBd/kUJqmPxxlxMH8QDQinTwZmmFA9wW7PJdy
|
30
|
+
wAx8px9LkSjTs0GVLH7VtVRWAELllsswCJktz63Adelx9fmIMgrTYgZM
|
32
31
|
-----END CERTIFICATE-----
|
33
|
-
date:
|
32
|
+
date: 2021-04-07 00:00:00.000000000 Z
|
34
33
|
dependencies:
|
35
34
|
- !ruby/object:Gem::Dependency
|
36
35
|
name: faraday
|
@@ -38,14 +37,14 @@ dependencies:
|
|
38
37
|
requirements:
|
39
38
|
- - "~>"
|
40
39
|
- !ruby/object:Gem::Version
|
41
|
-
version: '0
|
40
|
+
version: '1.0'
|
42
41
|
type: :runtime
|
43
42
|
prerelease: false
|
44
43
|
version_requirements: !ruby/object:Gem::Requirement
|
45
44
|
requirements:
|
46
45
|
- - "~>"
|
47
46
|
- !ruby/object:Gem::Version
|
48
|
-
version: '0
|
47
|
+
version: '1.0'
|
49
48
|
- !ruby/object:Gem::Dependency
|
50
49
|
name: faraday-http-cache
|
51
50
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,14 +65,14 @@ dependencies:
|
|
66
65
|
requirements:
|
67
66
|
- - "~>"
|
68
67
|
- !ruby/object:Gem::Version
|
69
|
-
version: '
|
68
|
+
version: '13.0'
|
70
69
|
type: :development
|
71
70
|
prerelease: false
|
72
71
|
version_requirements: !ruby/object:Gem::Requirement
|
73
72
|
requirements:
|
74
73
|
- - "~>"
|
75
74
|
- !ruby/object:Gem::Version
|
76
|
-
version: '
|
75
|
+
version: '13.0'
|
77
76
|
- !ruby/object:Gem::Dependency
|
78
77
|
name: minitest
|
79
78
|
requirement: !ruby/object:Gem::Requirement
|
@@ -83,7 +82,7 @@ dependencies:
|
|
83
82
|
version: '5'
|
84
83
|
- - ">="
|
85
84
|
- !ruby/object:Gem::Version
|
86
|
-
version:
|
85
|
+
version: 5.14.3
|
87
86
|
type: :development
|
88
87
|
prerelease: false
|
89
88
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -93,28 +92,58 @@ dependencies:
|
|
93
92
|
version: '5'
|
94
93
|
- - ">="
|
95
94
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
95
|
+
version: 5.14.3
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
name: minitest-hooks
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '1'
|
103
|
+
type: :development
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '1'
|
97
110
|
description: A HAL client customized for Shaf APIs
|
98
111
|
email: sammy.henningsson@gmail.com
|
99
|
-
executables:
|
112
|
+
executables:
|
113
|
+
- shaf_client
|
100
114
|
extensions: []
|
101
115
|
extra_rdoc_files: []
|
102
116
|
files:
|
117
|
+
- bin/shaf_client
|
118
|
+
- lib/faraday_http_cache_patch.rb
|
103
119
|
- lib/shaf_client.rb
|
120
|
+
- lib/shaf_client/alps/descriptor.rb
|
121
|
+
- lib/shaf_client/alps/extension.rb
|
122
|
+
- lib/shaf_client/alps_json.rb
|
104
123
|
- lib/shaf_client/api_error.rb
|
105
124
|
- lib/shaf_client/base_resource.rb
|
125
|
+
- lib/shaf_client/content_type_map.rb
|
106
126
|
- lib/shaf_client/curie.rb
|
107
127
|
- lib/shaf_client/empty_resource.rb
|
108
128
|
- lib/shaf_client/error.rb
|
109
129
|
- lib/shaf_client/field.rb
|
110
130
|
- lib/shaf_client/form.rb
|
111
131
|
- lib/shaf_client/hal_form.rb
|
132
|
+
- lib/shaf_client/hypertext_cache_strategy.rb
|
112
133
|
- lib/shaf_client/link.rb
|
113
134
|
- lib/shaf_client/middleware/redirect.rb
|
135
|
+
- lib/shaf_client/mime_types.rb
|
136
|
+
- lib/shaf_client/problem_json.rb
|
114
137
|
- lib/shaf_client/resource.rb
|
138
|
+
- lib/shaf_client/resource_extension.rb
|
139
|
+
- lib/shaf_client/resource_extension/alps_http_method.rb
|
140
|
+
- lib/shaf_client/resource_extension/base.rb
|
115
141
|
- lib/shaf_client/resource_mapper.rb
|
116
142
|
- lib/shaf_client/shaf_form.rb
|
143
|
+
- lib/shaf_client/status_codes.rb
|
144
|
+
- lib/shaf_client/test/stubbing.rb
|
117
145
|
- lib/shaf_client/unknown_resource.rb
|
146
|
+
- lib/shaf_client/version.rb
|
118
147
|
homepage: https://github.com/sammyhenningsson/shaf_client
|
119
148
|
licenses:
|
120
149
|
- MIT
|
@@ -134,7 +163,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
134
163
|
- !ruby/object:Gem::Version
|
135
164
|
version: '0'
|
136
165
|
requirements: []
|
137
|
-
rubygems_version: 3.0.
|
166
|
+
rubygems_version: 3.0.3
|
138
167
|
signing_key:
|
139
168
|
specification_version: 4
|
140
169
|
summary: HAL client for Shaf
|
metadata.gz.sig
CHANGED
Binary file
|