apiwork 0.0.0.pre → 0.1.1
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/LICENSE.txt +2 -2
- data/README.md +117 -1
- data/Rakefile +5 -3
- data/app/controllers/apiwork/errors_controller.rb +13 -0
- data/app/controllers/apiwork/exports_controller.rb +22 -0
- data/lib/apiwork/abstractable.rb +26 -0
- data/lib/apiwork/adapter/base.rb +369 -0
- data/lib/apiwork/adapter/builder/api/base.rb +66 -0
- data/lib/apiwork/adapter/builder/contract/base.rb +86 -0
- data/lib/apiwork/adapter/capability/api/base.rb +51 -0
- data/lib/apiwork/adapter/capability/api/scope.rb +64 -0
- data/lib/apiwork/adapter/capability/base.rb +291 -0
- data/lib/apiwork/adapter/capability/contract/base.rb +37 -0
- data/lib/apiwork/adapter/capability/contract/scope.rb +110 -0
- data/lib/apiwork/adapter/capability/operation/base.rb +172 -0
- data/lib/apiwork/adapter/capability/operation/metadata_shape.rb +165 -0
- data/lib/apiwork/adapter/capability/result.rb +21 -0
- data/lib/apiwork/adapter/capability/runner.rb +56 -0
- data/lib/apiwork/adapter/capability/transformer/request/base.rb +72 -0
- data/lib/apiwork/adapter/capability/transformer/response/base.rb +45 -0
- data/lib/apiwork/adapter/registry.rb +16 -0
- data/lib/apiwork/adapter/serializer/error/base.rb +72 -0
- data/lib/apiwork/adapter/serializer/error/default/api_builder.rb +32 -0
- data/lib/apiwork/adapter/serializer/error/default.rb +37 -0
- data/lib/apiwork/adapter/serializer/resource/base.rb +84 -0
- data/lib/apiwork/adapter/serializer/resource/default/contract_builder.rb +209 -0
- data/lib/apiwork/adapter/serializer/resource/default.rb +39 -0
- data/lib/apiwork/adapter/standard/capability/filtering/api_builder.rb +75 -0
- data/lib/apiwork/adapter/standard/capability/filtering/constants.rb +37 -0
- data/lib/apiwork/adapter/standard/capability/filtering/contract_builder.rb +193 -0
- data/lib/apiwork/adapter/standard/capability/filtering/operation/filter/builder.rb +47 -0
- data/lib/apiwork/adapter/standard/capability/filtering/operation/filter/operator_builder.rb +36 -0
- data/lib/apiwork/adapter/standard/capability/filtering/operation/filter.rb +462 -0
- data/lib/apiwork/adapter/standard/capability/filtering/operation.rb +22 -0
- data/lib/apiwork/adapter/standard/capability/filtering/request_transformer.rb +47 -0
- data/lib/apiwork/adapter/standard/capability/filtering.rb +18 -0
- data/lib/apiwork/adapter/standard/capability/including/contract_builder.rb +169 -0
- data/lib/apiwork/adapter/standard/capability/including/operation.rb +20 -0
- data/lib/apiwork/adapter/standard/capability/including.rb +16 -0
- data/lib/apiwork/adapter/standard/capability/pagination/api_builder.rb +34 -0
- data/lib/apiwork/adapter/standard/capability/pagination/contract_builder.rb +35 -0
- data/lib/apiwork/adapter/standard/capability/pagination/operation/paginate/cursor.rb +84 -0
- data/lib/apiwork/adapter/standard/capability/pagination/operation/paginate/offset.rb +66 -0
- data/lib/apiwork/adapter/standard/capability/pagination/operation/paginate.rb +24 -0
- data/lib/apiwork/adapter/standard/capability/pagination/operation.rb +24 -0
- data/lib/apiwork/adapter/standard/capability/pagination.rb +21 -0
- data/lib/apiwork/adapter/standard/capability/sorting/api_builder.rb +19 -0
- data/lib/apiwork/adapter/standard/capability/sorting/contract_builder.rb +84 -0
- data/lib/apiwork/adapter/standard/capability/sorting/operation/sort.rb +83 -0
- data/lib/apiwork/adapter/standard/capability/sorting/operation.rb +22 -0
- data/lib/apiwork/adapter/standard/capability/sorting.rb +17 -0
- data/lib/apiwork/adapter/standard/capability/writing/constants.rb +15 -0
- data/lib/apiwork/adapter/standard/capability/writing/contract_builder.rb +253 -0
- data/lib/apiwork/adapter/standard/capability/writing/operation/issue_mapper.rb +210 -0
- data/lib/apiwork/adapter/standard/capability/writing/operation.rb +32 -0
- data/lib/apiwork/adapter/standard/capability/writing/request_transformer.rb +37 -0
- data/lib/apiwork/adapter/standard/capability/writing.rb +17 -0
- data/lib/apiwork/adapter/standard/includes_resolver.rb +106 -0
- data/lib/apiwork/adapter/standard.rb +22 -0
- data/lib/apiwork/adapter/wrapper/base.rb +70 -0
- data/lib/apiwork/adapter/wrapper/collection/base.rb +60 -0
- data/lib/apiwork/adapter/wrapper/collection/default.rb +47 -0
- data/lib/apiwork/adapter/wrapper/error/base.rb +30 -0
- data/lib/apiwork/adapter/wrapper/error/default.rb +34 -0
- data/lib/apiwork/adapter/wrapper/member/base.rb +58 -0
- data/lib/apiwork/adapter/wrapper/member/default.rb +40 -0
- data/lib/apiwork/adapter/wrapper/shape.rb +203 -0
- data/lib/apiwork/adapter.rb +50 -0
- data/lib/apiwork/api/base.rb +802 -0
- data/lib/apiwork/api/element.rb +110 -0
- data/lib/apiwork/api/enum_registry/definition.rb +51 -0
- data/lib/apiwork/api/enum_registry.rb +98 -0
- data/lib/apiwork/api/info/contact.rb +67 -0
- data/lib/apiwork/api/info/license.rb +50 -0
- data/lib/apiwork/api/info/server.rb +50 -0
- data/lib/apiwork/api/info.rb +221 -0
- data/lib/apiwork/api/object.rb +235 -0
- data/lib/apiwork/api/registry.rb +33 -0
- data/lib/apiwork/api/representation_registry.rb +76 -0
- data/lib/apiwork/api/resource/action.rb +41 -0
- data/lib/apiwork/api/resource.rb +648 -0
- data/lib/apiwork/api/router.rb +104 -0
- data/lib/apiwork/api/type_registry/definition.rb +117 -0
- data/lib/apiwork/api/type_registry.rb +99 -0
- data/lib/apiwork/api/union.rb +49 -0
- data/lib/apiwork/api.rb +85 -0
- data/lib/apiwork/configurable.rb +71 -0
- data/lib/apiwork/configuration/option.rb +125 -0
- data/lib/apiwork/configuration/validatable.rb +25 -0
- data/lib/apiwork/configuration.rb +95 -0
- data/lib/apiwork/configuration_error.rb +6 -0
- data/lib/apiwork/constraint_error.rb +20 -0
- data/lib/apiwork/contract/action/request.rb +79 -0
- data/lib/apiwork/contract/action/response.rb +87 -0
- data/lib/apiwork/contract/action.rb +258 -0
- data/lib/apiwork/contract/base.rb +714 -0
- data/lib/apiwork/contract/element.rb +130 -0
- data/lib/apiwork/contract/object/coercer.rb +194 -0
- data/lib/apiwork/contract/object/deserializer.rb +101 -0
- data/lib/apiwork/contract/object/transformer.rb +95 -0
- data/lib/apiwork/contract/object/validator/result.rb +27 -0
- data/lib/apiwork/contract/object/validator.rb +734 -0
- data/lib/apiwork/contract/object.rb +566 -0
- data/lib/apiwork/contract/request_parser/result.rb +25 -0
- data/lib/apiwork/contract/request_parser.rb +72 -0
- data/lib/apiwork/contract/response_parser/result.rb +25 -0
- data/lib/apiwork/contract/response_parser.rb +35 -0
- data/lib/apiwork/contract/union.rb +56 -0
- data/lib/apiwork/contract_error.rb +9 -0
- data/lib/apiwork/controller.rb +300 -0
- data/lib/apiwork/domain_error.rb +13 -0
- data/lib/apiwork/element.rb +386 -0
- data/lib/apiwork/engine.rb +20 -0
- data/lib/apiwork/error.rb +6 -0
- data/lib/apiwork/error_code/definition.rb +63 -0
- data/lib/apiwork/error_code/registry.rb +18 -0
- data/lib/apiwork/error_code.rb +132 -0
- data/lib/apiwork/export/base.rb +291 -0
- data/lib/apiwork/export/open_api.rb +600 -0
- data/lib/apiwork/export/pipeline/writer.rb +66 -0
- data/lib/apiwork/export/pipeline.rb +84 -0
- data/lib/apiwork/export/registry.rb +16 -0
- data/lib/apiwork/export/surface_resolver.rb +189 -0
- data/lib/apiwork/export/type_analysis.rb +170 -0
- data/lib/apiwork/export/type_script.rb +23 -0
- data/lib/apiwork/export/type_script_mapper.rb +349 -0
- data/lib/apiwork/export/zod.rb +39 -0
- data/lib/apiwork/export/zod_mapper.rb +421 -0
- data/lib/apiwork/export.rb +80 -0
- data/lib/apiwork/http_error.rb +16 -0
- data/lib/apiwork/introspection/action/request.rb +66 -0
- data/lib/apiwork/introspection/action/response.rb +57 -0
- data/lib/apiwork/introspection/action.rb +124 -0
- data/lib/apiwork/introspection/api/info/contact.rb +59 -0
- data/lib/apiwork/introspection/api/info/license.rb +49 -0
- data/lib/apiwork/introspection/api/info/server.rb +50 -0
- data/lib/apiwork/introspection/api/info.rb +107 -0
- data/lib/apiwork/introspection/api/resource.rb +83 -0
- data/lib/apiwork/introspection/api.rb +92 -0
- data/lib/apiwork/introspection/contract.rb +63 -0
- data/lib/apiwork/introspection/dump/action.rb +101 -0
- data/lib/apiwork/introspection/dump/api.rb +119 -0
- data/lib/apiwork/introspection/dump/contract.rb +129 -0
- data/lib/apiwork/introspection/dump/param.rb +486 -0
- data/lib/apiwork/introspection/dump/resource.rb +112 -0
- data/lib/apiwork/introspection/dump/type.rb +339 -0
- data/lib/apiwork/introspection/dump.rb +17 -0
- data/lib/apiwork/introspection/enum.rb +63 -0
- data/lib/apiwork/introspection/error_code.rb +44 -0
- data/lib/apiwork/introspection/param/array.rb +88 -0
- data/lib/apiwork/introspection/param/base.rb +285 -0
- data/lib/apiwork/introspection/param/binary.rb +73 -0
- data/lib/apiwork/introspection/param/boolean.rb +73 -0
- data/lib/apiwork/introspection/param/date.rb +73 -0
- data/lib/apiwork/introspection/param/date_time.rb +73 -0
- data/lib/apiwork/introspection/param/decimal.rb +121 -0
- data/lib/apiwork/introspection/param/integer.rb +131 -0
- data/lib/apiwork/introspection/param/literal.rb +45 -0
- data/lib/apiwork/introspection/param/number.rb +121 -0
- data/lib/apiwork/introspection/param/object.rb +59 -0
- data/lib/apiwork/introspection/param/reference.rb +45 -0
- data/lib/apiwork/introspection/param/string.rb +122 -0
- data/lib/apiwork/introspection/param/time.rb +73 -0
- data/lib/apiwork/introspection/param/union.rb +57 -0
- data/lib/apiwork/introspection/param/unknown.rb +26 -0
- data/lib/apiwork/introspection/param/uuid.rb +73 -0
- data/lib/apiwork/introspection/param.rb +31 -0
- data/lib/apiwork/introspection/type.rb +129 -0
- data/lib/apiwork/introspection.rb +28 -0
- data/lib/apiwork/issue.rb +80 -0
- data/lib/apiwork/json_pointer.rb +21 -0
- data/lib/apiwork/object.rb +1618 -0
- data/lib/apiwork/reference_generator.rb +622 -0
- data/lib/apiwork/registry.rb +56 -0
- data/lib/apiwork/representation/association.rb +391 -0
- data/lib/apiwork/representation/attribute.rb +335 -0
- data/lib/apiwork/representation/base.rb +819 -0
- data/lib/apiwork/representation/deserializer.rb +95 -0
- data/lib/apiwork/representation/element.rb +128 -0
- data/lib/apiwork/representation/inheritance.rb +78 -0
- data/lib/apiwork/representation/model_detector.rb +75 -0
- data/lib/apiwork/representation/root_key.rb +35 -0
- data/lib/apiwork/representation/serializer.rb +127 -0
- data/lib/apiwork/request.rb +79 -0
- data/lib/apiwork/response.rb +56 -0
- data/lib/apiwork/union.rb +102 -0
- data/lib/apiwork/version.rb +2 -2
- data/lib/apiwork.rb +61 -3
- data/lib/generators/apiwork/api_generator.rb +38 -0
- data/lib/generators/apiwork/contract_generator.rb +25 -0
- data/lib/generators/apiwork/install_generator.rb +27 -0
- data/lib/generators/apiwork/representation_generator.rb +25 -0
- data/lib/generators/apiwork/templates/api/api.rb.tt +4 -0
- data/lib/generators/apiwork/templates/contract/contract.rb.tt +6 -0
- data/lib/generators/apiwork/templates/install/application_contract.rb.tt +5 -0
- data/lib/generators/apiwork/templates/install/application_representation.rb.tt +5 -0
- data/lib/generators/apiwork/templates/representation/representation.rb.tt +6 -0
- data/lib/tasks/apiwork.rake +102 -0
- metadata +319 -19
- data/.rubocop.yml +0 -8
- data/sig/apiwork.rbs +0 -4
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Apiwork
|
|
4
|
+
class Element
|
|
5
|
+
# @!attribute [r] custom_type
|
|
6
|
+
# @api public
|
|
7
|
+
# The custom type name for this element.
|
|
8
|
+
#
|
|
9
|
+
# @return [Symbol, nil]
|
|
10
|
+
# @!attribute [r] discriminator
|
|
11
|
+
# @api public
|
|
12
|
+
# The discriminator for this element.
|
|
13
|
+
#
|
|
14
|
+
# @return [Symbol, nil]
|
|
15
|
+
# @!attribute [r] enum
|
|
16
|
+
# @api public
|
|
17
|
+
# The allowed values for this element.
|
|
18
|
+
#
|
|
19
|
+
# @return [Array, Symbol, nil]
|
|
20
|
+
# @!attribute [r] format
|
|
21
|
+
# @api public
|
|
22
|
+
# The format hint for this element.
|
|
23
|
+
#
|
|
24
|
+
# @return [Symbol, nil]
|
|
25
|
+
# @!attribute [r] inner
|
|
26
|
+
# @api public
|
|
27
|
+
# The inner element for nested arrays.
|
|
28
|
+
#
|
|
29
|
+
# @return [Element, nil]
|
|
30
|
+
# @!attribute [r] max
|
|
31
|
+
# @api public
|
|
32
|
+
# The maximum constraint for this element.
|
|
33
|
+
#
|
|
34
|
+
# @return [Numeric, nil]
|
|
35
|
+
# @!attribute [r] min
|
|
36
|
+
# @api public
|
|
37
|
+
# The minimum constraint for this element.
|
|
38
|
+
#
|
|
39
|
+
# @return [Numeric, nil]
|
|
40
|
+
# @!attribute [r] shape
|
|
41
|
+
# @api public
|
|
42
|
+
# The shape for this element.
|
|
43
|
+
#
|
|
44
|
+
# @return [Object, nil]
|
|
45
|
+
# @!attribute [r] type
|
|
46
|
+
# @api public
|
|
47
|
+
# The type for this element.
|
|
48
|
+
#
|
|
49
|
+
# @return [Symbol, nil]
|
|
50
|
+
# @!attribute [r] value
|
|
51
|
+
# @api public
|
|
52
|
+
# The literal value for this element.
|
|
53
|
+
#
|
|
54
|
+
# @return [Object, nil]
|
|
55
|
+
attr_reader :custom_type,
|
|
56
|
+
:discriminator,
|
|
57
|
+
:enum,
|
|
58
|
+
:format,
|
|
59
|
+
:inner,
|
|
60
|
+
:max,
|
|
61
|
+
:min,
|
|
62
|
+
:shape,
|
|
63
|
+
:type,
|
|
64
|
+
:value
|
|
65
|
+
|
|
66
|
+
def initialize
|
|
67
|
+
@custom_type = nil
|
|
68
|
+
@defined = false
|
|
69
|
+
@discriminator = nil
|
|
70
|
+
@enum = nil
|
|
71
|
+
@format = nil
|
|
72
|
+
@inner = nil
|
|
73
|
+
@max = nil
|
|
74
|
+
@min = nil
|
|
75
|
+
@shape = nil
|
|
76
|
+
@type = nil
|
|
77
|
+
@value = nil
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# @api public
|
|
81
|
+
# Defines a string.
|
|
82
|
+
#
|
|
83
|
+
# @param enum [Array, Symbol, nil] (nil)
|
|
84
|
+
# The allowed values.
|
|
85
|
+
# @param format [Symbol, nil] (nil) [:date, :datetime, :email, :hostname, :ipv4, :ipv6, :password, :url, :uuid]
|
|
86
|
+
# Format hint for exports. Does not change the type, but exports may add validation or documentation based on it.
|
|
87
|
+
# Valid formats by type: `:string`.
|
|
88
|
+
# @param max [Integer, nil] (nil)
|
|
89
|
+
# The maximum length.
|
|
90
|
+
# @param min [Integer, nil] (nil)
|
|
91
|
+
# The minimum length.
|
|
92
|
+
# @return [void]
|
|
93
|
+
#
|
|
94
|
+
# @example Basic string
|
|
95
|
+
# array :tags do
|
|
96
|
+
# string
|
|
97
|
+
# end
|
|
98
|
+
#
|
|
99
|
+
# @example With length constraints
|
|
100
|
+
# array :tags do
|
|
101
|
+
# string min: 1, max: 50
|
|
102
|
+
# end
|
|
103
|
+
def string(enum: nil, format: nil, max: nil, min: nil)
|
|
104
|
+
of(:string, enum:, format:, max:, min:)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# @api public
|
|
108
|
+
# Defines an integer.
|
|
109
|
+
#
|
|
110
|
+
# @param enum [Array, Symbol, nil] (nil)
|
|
111
|
+
# The allowed values.
|
|
112
|
+
# @param max [Integer, nil] (nil)
|
|
113
|
+
# The maximum value.
|
|
114
|
+
# @param min [Integer, nil] (nil)
|
|
115
|
+
# The minimum value.
|
|
116
|
+
# @return [void]
|
|
117
|
+
#
|
|
118
|
+
# @example Basic integer
|
|
119
|
+
# array :counts do
|
|
120
|
+
# integer
|
|
121
|
+
# end
|
|
122
|
+
#
|
|
123
|
+
# @example With range constraints
|
|
124
|
+
# array :scores do
|
|
125
|
+
# integer min: 0, max: 100
|
|
126
|
+
# end
|
|
127
|
+
def integer(enum: nil, max: nil, min: nil)
|
|
128
|
+
of(:integer, enum:, max:, min:)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# @api public
|
|
132
|
+
# Defines a decimal.
|
|
133
|
+
#
|
|
134
|
+
# @param max [Numeric, nil] (nil)
|
|
135
|
+
# The maximum value.
|
|
136
|
+
# @param min [Numeric, nil] (nil)
|
|
137
|
+
# The minimum value.
|
|
138
|
+
# @return [void]
|
|
139
|
+
#
|
|
140
|
+
# @example Basic decimal
|
|
141
|
+
# array :amounts do
|
|
142
|
+
# decimal
|
|
143
|
+
# end
|
|
144
|
+
#
|
|
145
|
+
# @example With range constraints
|
|
146
|
+
# array :prices do
|
|
147
|
+
# decimal min: 0
|
|
148
|
+
# end
|
|
149
|
+
def decimal(max: nil, min: nil)
|
|
150
|
+
of(:decimal, max:, min:)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# @api public
|
|
154
|
+
# Defines a number.
|
|
155
|
+
#
|
|
156
|
+
# @param max [Numeric, nil] (nil)
|
|
157
|
+
# The maximum value.
|
|
158
|
+
# @param min [Numeric, nil] (nil)
|
|
159
|
+
# The minimum value.
|
|
160
|
+
# @return [void]
|
|
161
|
+
#
|
|
162
|
+
# @example Basic number
|
|
163
|
+
# array :coordinates do
|
|
164
|
+
# number
|
|
165
|
+
# end
|
|
166
|
+
#
|
|
167
|
+
# @example With range constraints
|
|
168
|
+
# array :latitudes do
|
|
169
|
+
# number min: -90, max: 90
|
|
170
|
+
# end
|
|
171
|
+
def number(max: nil, min: nil)
|
|
172
|
+
of(:number, max:, min:)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# @api public
|
|
176
|
+
# Defines a boolean.
|
|
177
|
+
#
|
|
178
|
+
# @return [void]
|
|
179
|
+
#
|
|
180
|
+
# @example
|
|
181
|
+
# array :flags do
|
|
182
|
+
# boolean
|
|
183
|
+
# end
|
|
184
|
+
def boolean
|
|
185
|
+
of(:boolean)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# @api public
|
|
189
|
+
# Defines a datetime.
|
|
190
|
+
#
|
|
191
|
+
# @return [void]
|
|
192
|
+
#
|
|
193
|
+
# @example
|
|
194
|
+
# array :timestamps do
|
|
195
|
+
# datetime
|
|
196
|
+
# end
|
|
197
|
+
def datetime
|
|
198
|
+
of(:datetime)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# @api public
|
|
202
|
+
# Defines a date.
|
|
203
|
+
#
|
|
204
|
+
# @return [void]
|
|
205
|
+
#
|
|
206
|
+
# @example
|
|
207
|
+
# array :dates do
|
|
208
|
+
# date
|
|
209
|
+
# end
|
|
210
|
+
def date
|
|
211
|
+
of(:date)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# @api public
|
|
215
|
+
# Defines a UUID.
|
|
216
|
+
#
|
|
217
|
+
# @return [void]
|
|
218
|
+
#
|
|
219
|
+
# @example
|
|
220
|
+
# array :ids do
|
|
221
|
+
# uuid
|
|
222
|
+
# end
|
|
223
|
+
def uuid
|
|
224
|
+
of(:uuid)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# @api public
|
|
228
|
+
# Defines a time.
|
|
229
|
+
#
|
|
230
|
+
# @return [void]
|
|
231
|
+
#
|
|
232
|
+
# @example
|
|
233
|
+
# array :times do
|
|
234
|
+
# time
|
|
235
|
+
# end
|
|
236
|
+
def time
|
|
237
|
+
of(:time)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# @api public
|
|
241
|
+
# Defines a binary.
|
|
242
|
+
#
|
|
243
|
+
# @return [void]
|
|
244
|
+
#
|
|
245
|
+
# @example
|
|
246
|
+
# array :blobs do
|
|
247
|
+
# binary
|
|
248
|
+
# end
|
|
249
|
+
def binary
|
|
250
|
+
of(:binary)
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# @api public
|
|
254
|
+
# Defines an object.
|
|
255
|
+
#
|
|
256
|
+
# @yield block defining nested structure
|
|
257
|
+
# @yieldparam object [Object]
|
|
258
|
+
# @return [void]
|
|
259
|
+
#
|
|
260
|
+
# @example instance_eval style
|
|
261
|
+
# array :items do
|
|
262
|
+
# object do
|
|
263
|
+
# string :name
|
|
264
|
+
# decimal :price
|
|
265
|
+
# end
|
|
266
|
+
# end
|
|
267
|
+
#
|
|
268
|
+
# @example yield style
|
|
269
|
+
# array :items do |element|
|
|
270
|
+
# element.object do |object|
|
|
271
|
+
# object.string :name
|
|
272
|
+
# object.decimal :price
|
|
273
|
+
# end
|
|
274
|
+
# end
|
|
275
|
+
def object(&block)
|
|
276
|
+
of(:object, &block)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
# @api public
|
|
280
|
+
# Defines an array.
|
|
281
|
+
#
|
|
282
|
+
# @yield block defining element type
|
|
283
|
+
# @yieldparam element [Element]
|
|
284
|
+
# @return [void]
|
|
285
|
+
#
|
|
286
|
+
# @example instance_eval style
|
|
287
|
+
# array :matrix do
|
|
288
|
+
# array do
|
|
289
|
+
# integer
|
|
290
|
+
# end
|
|
291
|
+
# end
|
|
292
|
+
#
|
|
293
|
+
# @example yield style
|
|
294
|
+
# array :matrix do |element|
|
|
295
|
+
# element.array do |inner|
|
|
296
|
+
# inner.integer
|
|
297
|
+
# end
|
|
298
|
+
# end
|
|
299
|
+
def array(&block)
|
|
300
|
+
of(:array, &block)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# @api public
|
|
304
|
+
# Defines a union.
|
|
305
|
+
#
|
|
306
|
+
# @param discriminator [Symbol, nil] (nil)
|
|
307
|
+
# The discriminator field name.
|
|
308
|
+
# @yield block defining union variants
|
|
309
|
+
# @yieldparam union [Union]
|
|
310
|
+
# @return [void]
|
|
311
|
+
#
|
|
312
|
+
# @example instance_eval style
|
|
313
|
+
# array :payments do
|
|
314
|
+
# union discriminator: :type do
|
|
315
|
+
# variant tag: 'card' do
|
|
316
|
+
# object do
|
|
317
|
+
# string :last_four
|
|
318
|
+
# end
|
|
319
|
+
# end
|
|
320
|
+
# end
|
|
321
|
+
# end
|
|
322
|
+
#
|
|
323
|
+
# @example yield style
|
|
324
|
+
# array :payments do |element|
|
|
325
|
+
# element.union discriminator: :type do |union|
|
|
326
|
+
# union.variant tag: 'card' do |variant|
|
|
327
|
+
# variant.object do |object|
|
|
328
|
+
# object.string :last_four
|
|
329
|
+
# end
|
|
330
|
+
# end
|
|
331
|
+
# end
|
|
332
|
+
# end
|
|
333
|
+
def union(discriminator: nil, &block)
|
|
334
|
+
of(:union, discriminator:, &block)
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
# @api public
|
|
338
|
+
# Defines a literal value.
|
|
339
|
+
#
|
|
340
|
+
# @param value [Object]
|
|
341
|
+
# The literal value.
|
|
342
|
+
# @return [void]
|
|
343
|
+
#
|
|
344
|
+
# @example
|
|
345
|
+
# variant tag: 'card' do
|
|
346
|
+
# literal value: 'card'
|
|
347
|
+
# end
|
|
348
|
+
def literal(value:)
|
|
349
|
+
of(:literal, value:)
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
# @api public
|
|
353
|
+
# Defines a reference to a named type.
|
|
354
|
+
#
|
|
355
|
+
# @param type_name [Symbol]
|
|
356
|
+
# The type to reference.
|
|
357
|
+
# @return [void]
|
|
358
|
+
#
|
|
359
|
+
# @example
|
|
360
|
+
# array :items do
|
|
361
|
+
# reference :item
|
|
362
|
+
# end
|
|
363
|
+
def reference(type_name)
|
|
364
|
+
of(type_name)
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
def validate!
|
|
368
|
+
raise ArgumentError, 'must define exactly one type' unless @defined
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
def of(type, **options, &block)
|
|
372
|
+
raise NotImplementedError, "#{self.class} must implement #of"
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
private
|
|
376
|
+
|
|
377
|
+
def set_type(type_value, enum: nil, format: nil, max: nil, min: nil)
|
|
378
|
+
@type = type_value
|
|
379
|
+
@enum = enum
|
|
380
|
+
@format = format
|
|
381
|
+
@max = max
|
|
382
|
+
@min = min
|
|
383
|
+
@defined = true
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Apiwork
|
|
4
|
+
class Engine < ::Rails::Engine
|
|
5
|
+
isolate_namespace Apiwork
|
|
6
|
+
engine_name 'apiwork'
|
|
7
|
+
|
|
8
|
+
rake_tasks do
|
|
9
|
+
load File.expand_path('../tasks/apiwork.rake', __dir__)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
initializer 'apiwork.i18n' do
|
|
13
|
+
config.i18n.load_path += Dir[File.expand_path('../../config/locales/**/*.yml', __dir__)]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
config.to_prepare do
|
|
17
|
+
Apiwork.prepare!
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Apiwork
|
|
4
|
+
module ErrorCode
|
|
5
|
+
# @api public
|
|
6
|
+
# Represents a registered error code.
|
|
7
|
+
#
|
|
8
|
+
# Error codes define HTTP status codes and behavior for API errors.
|
|
9
|
+
# Retrieved via {ErrorCode.find} or {ErrorCode.find!}.
|
|
10
|
+
#
|
|
11
|
+
# @!attribute [r] key
|
|
12
|
+
# @api public
|
|
13
|
+
# The key for this error code.
|
|
14
|
+
#
|
|
15
|
+
# @return [Symbol]
|
|
16
|
+
#
|
|
17
|
+
# @!attribute [r] status
|
|
18
|
+
# @api public
|
|
19
|
+
# The status for this error code.
|
|
20
|
+
#
|
|
21
|
+
# @return [Integer]
|
|
22
|
+
#
|
|
23
|
+
# @example
|
|
24
|
+
# error_code = Apiwork::ErrorCode.find!(:not_found)
|
|
25
|
+
# error_code.key # => :not_found
|
|
26
|
+
# error_code.status # => 404
|
|
27
|
+
# error_code.attach_path? # => true
|
|
28
|
+
Definition = Struct.new(:key, :status, :attach_path, keyword_init: true) do
|
|
29
|
+
# @api public
|
|
30
|
+
# Whether this error code attaches the request path.
|
|
31
|
+
#
|
|
32
|
+
# @return [Boolean]
|
|
33
|
+
def attach_path?
|
|
34
|
+
attach_path
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @api public
|
|
38
|
+
# The description for this error code.
|
|
39
|
+
#
|
|
40
|
+
# @param locale_key [String, nil] (nil)
|
|
41
|
+
# The I18n namespace for API-specific translations.
|
|
42
|
+
# @return [String]
|
|
43
|
+
#
|
|
44
|
+
# @example
|
|
45
|
+
# error_code = Apiwork::ErrorCode.find!(:not_found)
|
|
46
|
+
# error_code.description # => "Not Found"
|
|
47
|
+
# error_code.description(locale_key: 'api/v1') # apiwork.apis.api/v1.error_codes.not_found.description
|
|
48
|
+
def description(locale_key: nil)
|
|
49
|
+
if locale_key
|
|
50
|
+
api_key = :"apiwork.apis.#{locale_key}.error_codes.#{key}.description"
|
|
51
|
+
result = I18n.translate(api_key, default: nil)
|
|
52
|
+
return result if result
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
global_key = :"apiwork.error_codes.#{key}.description"
|
|
56
|
+
result = I18n.translate(global_key, default: nil)
|
|
57
|
+
return result if result
|
|
58
|
+
|
|
59
|
+
key.to_s.titleize
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Apiwork
|
|
4
|
+
module ErrorCode
|
|
5
|
+
class Registry < Apiwork::Registry
|
|
6
|
+
class << self
|
|
7
|
+
def register(key, attach_path: false, status:)
|
|
8
|
+
key = normalize_key(key)
|
|
9
|
+
status = Integer(status)
|
|
10
|
+
|
|
11
|
+
raise ArgumentError, "Status must be 400-599, got #{status}" unless (400..599).cover?(status)
|
|
12
|
+
|
|
13
|
+
store[key] = Definition.new(attach_path:, key:, status:)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Apiwork
|
|
4
|
+
# @api public
|
|
5
|
+
module ErrorCode
|
|
6
|
+
DEFAULTS = {
|
|
7
|
+
bad_gateway: {
|
|
8
|
+
status: 502,
|
|
9
|
+
},
|
|
10
|
+
bad_request: {
|
|
11
|
+
status: 400,
|
|
12
|
+
},
|
|
13
|
+
conflict: {
|
|
14
|
+
status: 409,
|
|
15
|
+
},
|
|
16
|
+
forbidden: {
|
|
17
|
+
status: 403,
|
|
18
|
+
},
|
|
19
|
+
gateway_timeout: {
|
|
20
|
+
status: 504,
|
|
21
|
+
},
|
|
22
|
+
gone: {
|
|
23
|
+
status: 410,
|
|
24
|
+
},
|
|
25
|
+
internal_server_error: {
|
|
26
|
+
status: 500,
|
|
27
|
+
},
|
|
28
|
+
locked: {
|
|
29
|
+
status: 423,
|
|
30
|
+
},
|
|
31
|
+
method_not_allowed: {
|
|
32
|
+
status: 405,
|
|
33
|
+
},
|
|
34
|
+
not_acceptable: {
|
|
35
|
+
status: 406,
|
|
36
|
+
},
|
|
37
|
+
not_found: {
|
|
38
|
+
attach_path: true,
|
|
39
|
+
status: 404,
|
|
40
|
+
},
|
|
41
|
+
not_implemented: {
|
|
42
|
+
status: 501,
|
|
43
|
+
},
|
|
44
|
+
payment_required: {
|
|
45
|
+
status: 402,
|
|
46
|
+
},
|
|
47
|
+
precondition_failed: {
|
|
48
|
+
status: 412,
|
|
49
|
+
},
|
|
50
|
+
request_timeout: {
|
|
51
|
+
status: 408,
|
|
52
|
+
},
|
|
53
|
+
service_unavailable: {
|
|
54
|
+
status: 503,
|
|
55
|
+
},
|
|
56
|
+
too_many_requests: {
|
|
57
|
+
status: 429,
|
|
58
|
+
},
|
|
59
|
+
unauthorized: {
|
|
60
|
+
status: 401,
|
|
61
|
+
},
|
|
62
|
+
unprocessable_entity: {
|
|
63
|
+
status: 422,
|
|
64
|
+
},
|
|
65
|
+
unsupported_media_type: {
|
|
66
|
+
status: 415,
|
|
67
|
+
},
|
|
68
|
+
}.freeze
|
|
69
|
+
|
|
70
|
+
class << self
|
|
71
|
+
# @!method find(key)
|
|
72
|
+
# @api public
|
|
73
|
+
# Finds an error code by key.
|
|
74
|
+
# @param key [Symbol]
|
|
75
|
+
# The error code key.
|
|
76
|
+
# @return [ErrorCode::Definition, nil]
|
|
77
|
+
# @see .find!
|
|
78
|
+
# @example
|
|
79
|
+
# Apiwork::ErrorCode.find(:not_found)
|
|
80
|
+
#
|
|
81
|
+
# @!method find!(key)
|
|
82
|
+
# @api public
|
|
83
|
+
# Finds an error code by key.
|
|
84
|
+
# @param key [Symbol]
|
|
85
|
+
# The error code key.
|
|
86
|
+
# @return [ErrorCode::Definition]
|
|
87
|
+
# @raise [KeyError] if the error code is not found
|
|
88
|
+
# @see .find
|
|
89
|
+
# @example
|
|
90
|
+
# Apiwork::ErrorCode.find!(:not_found)
|
|
91
|
+
#
|
|
92
|
+
# @!method register(key, attach_path: false, status:)
|
|
93
|
+
# @api public
|
|
94
|
+
# Registers a custom error code for use in API responses.
|
|
95
|
+
#
|
|
96
|
+
# Error codes are used with `raises` declarations and `expose_error`
|
|
97
|
+
# in controllers. Built-in codes (400-504) are pre-registered.
|
|
98
|
+
#
|
|
99
|
+
# @param key [Symbol]
|
|
100
|
+
# The unique identifier for the error code.
|
|
101
|
+
# @param attach_path [Boolean] (false)
|
|
102
|
+
# Include request path in error response.
|
|
103
|
+
# @param status [Integer]
|
|
104
|
+
# The HTTP status code (must be 400-599).
|
|
105
|
+
# @return [ErrorCode::Definition]
|
|
106
|
+
# @raise [ArgumentError] if status is outside 400-599 range
|
|
107
|
+
# @see Issue
|
|
108
|
+
#
|
|
109
|
+
# @example Register custom error code
|
|
110
|
+
# Apiwork::ErrorCode.register :resource_locked, status: 423
|
|
111
|
+
#
|
|
112
|
+
# @example With path attachment
|
|
113
|
+
# Apiwork::ErrorCode.register :not_found, status: 404, attach_path: true
|
|
114
|
+
delegate :clear!,
|
|
115
|
+
:exists?,
|
|
116
|
+
:find,
|
|
117
|
+
:find!,
|
|
118
|
+
:keys,
|
|
119
|
+
:register,
|
|
120
|
+
:values,
|
|
121
|
+
to: Registry
|
|
122
|
+
|
|
123
|
+
def key_for_status(status)
|
|
124
|
+
DEFAULTS.find { |_key, config| config[:status] == status }&.first
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def register_defaults!
|
|
128
|
+
DEFAULTS.each { |key, options| register(key, **options) }
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|