jsapi 0.7.3 → 0.8.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
- data/lib/jsapi/controller/{error_result.rb → error.rb} +1 -1
- data/lib/jsapi/controller/methods.rb +49 -38
- data/lib/jsapi/controller/parameters.rb +4 -2
- data/lib/jsapi/controller/response.rb +82 -64
- data/lib/jsapi/controller.rb +1 -1
- data/lib/jsapi/{helpers/invalid_value_helper.rb → invalid_value_helper.rb} +1 -1
- data/lib/jsapi/json/array.rb +7 -7
- data/lib/jsapi/json/object.rb +6 -6
- data/lib/jsapi/json.rb +4 -4
- data/lib/jsapi/version.rb +1 -1
- data/lib/jsapi.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 41bcc8f72dc668c6df55dfc73e6e2c9cc6fde569ebe008e503586100e0b3bba1
|
4
|
+
data.tar.gz: 9667a2661824e0d3a47675e835f3372cfd22bff71ab8c7bb3bde3c0e56cc78be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 576422bac22ee56e77ab160e50033a78ba1f02039fd5a7686583d0778f049e331892bb5d7692dcdc428c9b250706f13bf6e585db4472d40e31d63537116d9f37
|
7
|
+
data.tar.gz: e3ef8964a2a55d6f245a8982e7dcad76f564d066af119eec43edb1b5bc579f1771ce87e747924e5cd2d6b650e07e44515ff7e722860a4c4ee8c6fa7e8b0360cb
|
@@ -27,14 +27,18 @@ module Jsapi
|
|
27
27
|
# that the model passed to the block is invalid if there are any request parameters
|
28
28
|
# that can't be mapped to a parameter or a request body property of the operation.
|
29
29
|
#
|
30
|
-
# The +:omit+ option specifies on which conditions properties are omitted.
|
30
|
+
# The +:omit+ option specifies on which conditions properties are omitted in responses.
|
31
31
|
# Possible values are:
|
32
32
|
#
|
33
33
|
# - +:empty+ - All of the properties whose value is empty are omitted.
|
34
34
|
# - +:nil+ - All of the properties whose value is +nil+ are omitted.
|
35
35
|
#
|
36
|
-
# Raises an
|
37
|
-
def api_operation(operation_name = nil,
|
36
|
+
# Raises an +ArgumentError+ when +:omit+ is other than +:empty+, +:nil+ or +nil+.
|
37
|
+
def api_operation(operation_name = nil,
|
38
|
+
omit: nil,
|
39
|
+
status: nil,
|
40
|
+
strong: false,
|
41
|
+
&block)
|
38
42
|
_api_operation(
|
39
43
|
operation_name,
|
40
44
|
bang: false,
|
@@ -52,7 +56,11 @@ module Jsapi
|
|
52
56
|
# # ...
|
53
57
|
# end
|
54
58
|
#
|
55
|
-
def api_operation!(operation_name = nil,
|
59
|
+
def api_operation!(operation_name = nil,
|
60
|
+
omit: nil,
|
61
|
+
status: nil,
|
62
|
+
strong: false,
|
63
|
+
&block)
|
56
64
|
_api_operation(
|
57
65
|
operation_name,
|
58
66
|
bang: true,
|
@@ -97,13 +105,13 @@ module Jsapi
|
|
97
105
|
# - +:empty+ - All of the properties whose value is empty are omitted.
|
98
106
|
# - +:nil+ - All of the properties whose value is +nil+ are omitted.
|
99
107
|
#
|
100
|
-
# Raises an
|
108
|
+
# Raises an +ArgumentError+ when +:omit+ is other than +:empty+, +:nil+ or +nil+.
|
101
109
|
def api_response(result, operation_name = nil, omit: nil, status: nil)
|
102
110
|
definitions = api_definitions
|
103
111
|
operation = _find_api_operation(operation_name, definitions)
|
104
|
-
|
112
|
+
response_model = _api_response(operation, status, definitions)
|
105
113
|
|
106
|
-
Response.new(result,
|
114
|
+
Response.new(result, response_model, api_definitions, omit: omit)
|
107
115
|
end
|
108
116
|
|
109
117
|
private
|
@@ -111,40 +119,43 @@ module Jsapi
|
|
111
119
|
def _api_operation(operation_name, bang:, omit:, status:, strong:, &block)
|
112
120
|
definitions = api_definitions
|
113
121
|
operation = _find_api_operation(operation_name, definitions)
|
114
|
-
response = _api_response(operation, status, definitions)
|
115
|
-
|
116
|
-
if block
|
117
|
-
params = _api_params(operation, definitions, strong: strong)
|
118
|
-
result = begin
|
119
|
-
raise ParametersInvalid.new(params) if bang && params.invalid?
|
120
|
-
|
121
|
-
block.call(params)
|
122
|
-
rescue StandardError => e
|
123
|
-
# Lookup a rescue handler
|
124
|
-
rescue_handler = definitions.rescue_handler_for(e)
|
125
|
-
raise e if rescue_handler.nil?
|
126
|
-
|
127
|
-
# Change the HTTP status code and response schema
|
128
|
-
status = rescue_handler.status
|
129
|
-
response = operation.response(status)&.resolve(definitions)
|
130
|
-
raise e if response.nil?
|
131
|
-
|
132
|
-
# Call on_rescue callbacks
|
133
|
-
definitions.on_rescue_callbacks.each do |callback|
|
134
|
-
if callback.respond_to?(:call)
|
135
|
-
callback.call(e)
|
136
|
-
else
|
137
|
-
send(callback, e)
|
138
|
-
end
|
139
|
-
end
|
140
122
|
|
141
|
-
|
123
|
+
# Perform operation
|
124
|
+
response_model = _api_response(operation, status, definitions)
|
125
|
+
head(status) && return unless block
|
126
|
+
|
127
|
+
params = _api_params(operation, definitions, strong: strong)
|
128
|
+
|
129
|
+
result = begin
|
130
|
+
raise ParametersInvalid.new(params) if bang && params.invalid?
|
131
|
+
|
132
|
+
block.call(params)
|
133
|
+
rescue StandardError => e
|
134
|
+
# Lookup a rescue handler
|
135
|
+
rescue_handler = definitions.rescue_handler_for(e)
|
136
|
+
raise e if rescue_handler.nil?
|
137
|
+
|
138
|
+
# Change the HTTP status code and response model
|
139
|
+
status = rescue_handler.status
|
140
|
+
response_model = operation.response(status)&.resolve(definitions)
|
141
|
+
raise e if response_model.nil?
|
142
|
+
|
143
|
+
# Call on_rescue callbacks
|
144
|
+
definitions.on_rescue_callbacks.each do |callback|
|
145
|
+
if callback.respond_to?(:call)
|
146
|
+
callback.call(e)
|
147
|
+
else
|
148
|
+
send(callback, e)
|
149
|
+
end
|
142
150
|
end
|
143
|
-
|
144
|
-
|
145
|
-
head(status)
|
151
|
+
|
152
|
+
Error.new(e, status: status)
|
146
153
|
end
|
147
|
-
|
154
|
+
response = Response.new(result, response_model, definitions, omit: omit)
|
155
|
+
|
156
|
+
# Write response
|
157
|
+
self.content_type = response_model.content_type
|
158
|
+
render(json: response, status: status)
|
148
159
|
end
|
149
160
|
|
150
161
|
def _api_params(operation, definitions, strong:)
|
@@ -27,7 +27,8 @@ module Jsapi
|
|
27
27
|
@raw_attributes[name] = JSON.wrap(
|
28
28
|
parameter_model.in == 'header' ? headers[name] : @params[name],
|
29
29
|
parameter_model.schema.resolve(definitions),
|
30
|
-
definitions
|
30
|
+
definitions,
|
31
|
+
context: :request
|
31
32
|
)
|
32
33
|
end
|
33
34
|
|
@@ -38,7 +39,8 @@ module Jsapi
|
|
38
39
|
request_body = JSON.wrap(
|
39
40
|
@params.except(*operation.parameters.keys),
|
40
41
|
request_body_schema,
|
41
|
-
definitions
|
42
|
+
definitions,
|
43
|
+
context: :request
|
42
44
|
)
|
43
45
|
@raw_attributes.merge!(request_body.raw_attributes)
|
44
46
|
@raw_additional_attributes = request_body.raw_additional_attributes
|
@@ -2,10 +2,20 @@
|
|
2
2
|
|
3
3
|
module Jsapi
|
4
4
|
module Controller
|
5
|
-
# Used to
|
5
|
+
# Used to jsonify a response.
|
6
6
|
class Response
|
7
|
+
class JsonifyError < RuntimeError # :nodoc:
|
8
|
+
def message
|
9
|
+
[@path&.delete_prefix('.') || 'response body', super].join(' ')
|
10
|
+
end
|
11
|
+
|
12
|
+
def prepend(origin)
|
13
|
+
@path = "#{origin}#{@path}"
|
14
|
+
self
|
15
|
+
end
|
16
|
+
end
|
7
17
|
|
8
|
-
# Creates a new instance to
|
18
|
+
# Creates a new instance to jsonify +object+ according to +response+. References
|
9
19
|
# are resolved to API components in +definitions+.
|
10
20
|
#
|
11
21
|
# The +:omit+ option specifies on which conditions properties are omitted.
|
@@ -14,111 +24,119 @@ module Jsapi
|
|
14
24
|
# - +:empty+ - All of the properties whose value is empty are omitted.
|
15
25
|
# - +:nil+ - All of the properties whose value is +nil+ are omitted.
|
16
26
|
#
|
17
|
-
# Raises an
|
27
|
+
# Raises an +ArgumentError+ when +:omit+ is other than +:empty+, +:nil+ or +nil+.
|
18
28
|
def initialize(object, response, definitions, omit: nil)
|
19
|
-
if [:empty, :nil, nil].exclude?(omit)
|
20
|
-
raise InvalidArgumentError.new('omit', omit, valid_values: %i[empty nil])
|
21
|
-
end
|
22
|
-
|
23
29
|
@object = object
|
24
30
|
@response = response
|
25
31
|
@definitions = definitions
|
26
|
-
|
32
|
+
|
33
|
+
@omittable_check =
|
34
|
+
case omit
|
35
|
+
when nil
|
36
|
+
nil
|
37
|
+
when :nil
|
38
|
+
->(value, schema) { schema.omittable? && value.nil? }
|
39
|
+
when :empty
|
40
|
+
->(value, schema) { schema.omittable? && value.try(:empty?) }
|
41
|
+
else
|
42
|
+
raise InvalidArgumentError.new('omit', omit, valid_values: %i[empty nil])
|
43
|
+
end
|
27
44
|
end
|
28
45
|
|
29
46
|
def inspect # :nodoc:
|
30
47
|
"#<#{self.class.name} #{@object.inspect}>"
|
31
48
|
end
|
32
49
|
|
33
|
-
# Returns the JSON representation of the response as a
|
50
|
+
# Returns the \JSON representation of the response as a string.
|
34
51
|
def to_json(*)
|
35
52
|
schema = @response.schema.resolve(@definitions)
|
36
53
|
if @response.locale
|
37
|
-
I18n.with_locale(@response.locale)
|
38
|
-
serialize(@object, schema)
|
39
|
-
end
|
54
|
+
I18n.with_locale(@response.locale) { jsonify(@object, schema) }
|
40
55
|
else
|
41
|
-
|
56
|
+
jsonify(@object, schema)
|
42
57
|
end.to_json
|
43
58
|
end
|
44
59
|
|
45
60
|
private
|
46
61
|
|
47
|
-
def
|
62
|
+
def jsonify(object, schema)
|
48
63
|
object = schema.default_value(@definitions, context: :response) if object.nil?
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
case schema.type
|
54
|
-
when 'array'
|
55
|
-
serialize_array(object, schema, path)
|
56
|
-
when 'integer'
|
57
|
-
schema.convert(object.to_i)
|
58
|
-
when 'number'
|
59
|
-
schema.convert(object.to_f)
|
60
|
-
when 'object'
|
61
|
-
serialize_object(object, schema, path)
|
62
|
-
when 'string'
|
63
|
-
schema.convert(
|
64
|
-
case schema.format
|
65
|
-
when 'date'
|
66
|
-
object.to_date
|
67
|
-
when 'date-time'
|
68
|
-
object.to_datetime
|
69
|
-
when 'duration'
|
70
|
-
object.iso8601
|
71
|
-
else
|
72
|
-
object.to_s
|
73
|
-
end
|
74
|
-
)
|
64
|
+
|
65
|
+
if object.nil?
|
66
|
+
raise JsonifyError, "can't be nil" unless schema.nullable?
|
75
67
|
else
|
76
|
-
|
68
|
+
case schema.type
|
69
|
+
when 'array'
|
70
|
+
jsonify_array(object, schema)
|
71
|
+
when 'boolean'
|
72
|
+
object
|
73
|
+
when 'integer'
|
74
|
+
schema.convert(object.to_i)
|
75
|
+
when 'number'
|
76
|
+
schema.convert(object.to_f)
|
77
|
+
when 'object'
|
78
|
+
jsonify_object(object, schema)
|
79
|
+
when 'string'
|
80
|
+
schema.convert(
|
81
|
+
case schema.format
|
82
|
+
when 'date'
|
83
|
+
object.to_date
|
84
|
+
when 'date-time'
|
85
|
+
object.to_datetime
|
86
|
+
when 'duration'
|
87
|
+
object.iso8601
|
88
|
+
else
|
89
|
+
object.to_s
|
90
|
+
end
|
91
|
+
)
|
92
|
+
else
|
93
|
+
raise JsonifyError, "has an invalid type: #{schema.type.inspect}"
|
94
|
+
end
|
77
95
|
end
|
78
96
|
end
|
79
97
|
|
80
|
-
def
|
98
|
+
def jsonify_array(array, schema)
|
81
99
|
item_schema = schema.items.resolve(@definitions)
|
82
|
-
|
100
|
+
index = 0
|
101
|
+
|
102
|
+
Array(array).map do |item|
|
103
|
+
item = jsonify(item, item_schema)
|
104
|
+
index += 1
|
105
|
+
item
|
106
|
+
rescue JsonifyError => e
|
107
|
+
raise e.prepend("[#{index}]")
|
108
|
+
end
|
83
109
|
end
|
84
110
|
|
85
|
-
def
|
111
|
+
def jsonify_object(object, schema)
|
86
112
|
schema = schema.resolve_schema(object, @definitions, context: :response)
|
87
113
|
properties = {}
|
88
114
|
|
89
|
-
#
|
90
|
-
schema.resolve_properties(@definitions, context: :response).
|
115
|
+
# Add properties
|
116
|
+
schema.resolve_properties(@definitions, context: :response).each_value do |property|
|
91
117
|
property_schema = property.schema.resolve(@definitions)
|
92
118
|
property_value = property.reader.call(object)
|
93
119
|
property_value = property_schema.default if property_value.nil?
|
120
|
+
next if @omittable_check&.call(property_value, property_schema)
|
94
121
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
properties[key] = serialize(
|
100
|
-
property_value,
|
101
|
-
property_schema,
|
102
|
-
path.nil? ? property.name : "#{path}.#{property.name}"
|
103
|
-
)
|
122
|
+
properties[property.name] = jsonify(property_value, property_schema)
|
123
|
+
rescue JsonifyError => e
|
124
|
+
raise e.prepend(".#{property.name}")
|
104
125
|
end
|
105
|
-
#
|
126
|
+
# Add additional properties
|
106
127
|
if (additional_properties = schema.additional_properties)
|
107
128
|
additional_properties_schema = additional_properties.schema.resolve(@definitions)
|
108
129
|
|
109
130
|
additional_properties.source.call(object)&.each do |key, value|
|
110
|
-
# Don't replace the property with the same key
|
111
131
|
next if properties.key?(key = key.to_s)
|
112
132
|
|
113
|
-
properties[key] =
|
114
|
-
|
115
|
-
|
116
|
-
path.nil? ? key : "#{path}.#{key}"
|
117
|
-
)
|
133
|
+
properties[key] = jsonify(value, additional_properties_schema)
|
134
|
+
rescue JsonifyError => e
|
135
|
+
raise e.prepend(".#{key}")
|
118
136
|
end
|
119
137
|
end
|
120
|
-
|
121
|
-
properties
|
138
|
+
|
139
|
+
properties.presence
|
122
140
|
end
|
123
141
|
end
|
124
142
|
end
|
data/lib/jsapi/controller.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'controller/parameters_invalid'
|
4
|
-
require_relative 'controller/
|
4
|
+
require_relative 'controller/error'
|
5
5
|
require_relative 'controller/parameters'
|
6
6
|
require_relative 'controller/response'
|
7
7
|
require_relative 'controller/methods'
|
data/lib/jsapi/json/array.rb
CHANGED
@@ -4,30 +4,30 @@ module Jsapi
|
|
4
4
|
module JSON
|
5
5
|
# Represents a JSON array.
|
6
6
|
class Array < Value
|
7
|
-
def initialize(
|
7
|
+
def initialize(array, schema, definitions, context: nil)
|
8
8
|
super(schema)
|
9
|
-
@
|
10
|
-
JSON.wrap(
|
9
|
+
@json_values = Array(array).map do |item|
|
10
|
+
JSON.wrap(item, schema.items, definitions, context: context)
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
14
|
# Returns true if it contains no elements, false otherwise.
|
15
15
|
def empty?
|
16
|
-
@
|
16
|
+
@json_values.empty?
|
17
17
|
end
|
18
18
|
|
19
19
|
def inspect # :nodoc:
|
20
|
-
"#<#{self.class.name} [#{@
|
20
|
+
"#<#{self.class.name} [#{@json_values.map(&:inspect).join(', ')}]>"
|
21
21
|
end
|
22
22
|
|
23
23
|
def validate(errors) # :nodoc:
|
24
24
|
return false unless super
|
25
25
|
|
26
|
-
@
|
26
|
+
@json_values.map { |element| element.validate(errors) }.all?
|
27
27
|
end
|
28
28
|
|
29
29
|
def value
|
30
|
-
@value ||= @
|
30
|
+
@value ||= @json_values.map(&:value)
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
data/lib/jsapi/json/object.rb
CHANGED
@@ -8,20 +8,20 @@ module Jsapi
|
|
8
8
|
|
9
9
|
attr_reader :raw_additional_attributes, :raw_attributes
|
10
10
|
|
11
|
-
def initialize(
|
12
|
-
schema = schema.resolve_schema(
|
13
|
-
properties = schema.resolve_properties(definitions, context:
|
11
|
+
def initialize(hash, schema, definitions, context: nil)
|
12
|
+
schema = schema.resolve_schema(hash, definitions, context: context)
|
13
|
+
properties = schema.resolve_properties(definitions, context: context)
|
14
14
|
|
15
15
|
@raw_attributes = properties.transform_values do |property|
|
16
|
-
JSON.wrap(
|
16
|
+
JSON.wrap(hash[property.name], property.schema, definitions, context: context)
|
17
17
|
end
|
18
18
|
|
19
19
|
@raw_additional_attributes =
|
20
20
|
if (additional_properties = schema.additional_properties)
|
21
21
|
additional_properties_schema = additional_properties.schema.resolve(definitions)
|
22
22
|
|
23
|
-
|
24
|
-
JSON.wrap(value, additional_properties_schema, definitions)
|
23
|
+
hash.except(*properties.keys).transform_values do |value|
|
24
|
+
JSON.wrap(value, additional_properties_schema, definitions, context: context)
|
25
25
|
end
|
26
26
|
end || {}
|
27
27
|
|
data/lib/jsapi/json.rb
CHANGED
@@ -13,15 +13,15 @@ module Jsapi
|
|
13
13
|
# Provides a DOM for JSON values.
|
14
14
|
module JSON
|
15
15
|
class << self
|
16
|
-
def wrap(object, schema, definitions = nil)
|
16
|
+
def wrap(object, schema, definitions = nil, context: nil)
|
17
17
|
schema = schema.resolve(definitions) unless definitions.nil?
|
18
18
|
|
19
|
-
object = schema.default_value(definitions, context:
|
19
|
+
object = schema.default_value(definitions, context: context) if object.nil?
|
20
20
|
return Null.new(schema) if object.nil?
|
21
21
|
|
22
22
|
case schema.type
|
23
23
|
when 'array'
|
24
|
-
Array.new(object, schema, definitions)
|
24
|
+
Array.new(object, schema, definitions, context: context)
|
25
25
|
when 'boolean'
|
26
26
|
Boolean.new(object, schema)
|
27
27
|
when 'integer'
|
@@ -29,7 +29,7 @@ module Jsapi
|
|
29
29
|
when 'number'
|
30
30
|
Number.new(object, schema)
|
31
31
|
when 'object'
|
32
|
-
Object.new(object, schema, definitions)
|
32
|
+
Object.new(object, schema, definitions, context: context)
|
33
33
|
when 'string'
|
34
34
|
String.new(object, schema)
|
35
35
|
else
|
data/lib/jsapi/version.rb
CHANGED
data/lib/jsapi.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsapi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Denis Göller
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-09-
|
11
|
+
date: 2024-09-29 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Jsapi can be used to read requests, produce responses and create OpenAPI
|
14
14
|
documents
|
@@ -20,7 +20,7 @@ files:
|
|
20
20
|
- lib/jsapi.rb
|
21
21
|
- lib/jsapi/controller.rb
|
22
22
|
- lib/jsapi/controller/base.rb
|
23
|
-
- lib/jsapi/controller/
|
23
|
+
- lib/jsapi/controller/error.rb
|
24
24
|
- lib/jsapi/controller/methods.rb
|
25
25
|
- lib/jsapi/controller/parameters.rb
|
26
26
|
- lib/jsapi/controller/parameters_invalid.rb
|
@@ -40,9 +40,9 @@ files:
|
|
40
40
|
- lib/jsapi/dsl/request_body.rb
|
41
41
|
- lib/jsapi/dsl/response.rb
|
42
42
|
- lib/jsapi/dsl/schema.rb
|
43
|
-
- lib/jsapi/helpers/invalid_value_helper.rb
|
44
43
|
- lib/jsapi/invalid_argument_error.rb
|
45
44
|
- lib/jsapi/invalid_value_error.rb
|
45
|
+
- lib/jsapi/invalid_value_helper.rb
|
46
46
|
- lib/jsapi/json.rb
|
47
47
|
- lib/jsapi/json/array.rb
|
48
48
|
- lib/jsapi/json/boolean.rb
|