gitlab-grape-openapi 0.6.0 → 0.7.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/README.md +41 -4
- data/lib/gitlab/grape_openapi/converters/cross_field_validation_resolver.rb +9 -1
- data/lib/gitlab/grape_openapi/converters/operation_converter.rb +13 -8
- data/lib/gitlab/grape_openapi/converters/path_converter.rb +6 -2
- data/lib/gitlab/grape_openapi/converters/request_body_converter.rb +7 -5
- data/lib/gitlab/grape_openapi/generator.rb +31 -1
- data/lib/gitlab/grape_openapi/operation_id_registry.rb +24 -0
- data/lib/gitlab/grape_openapi/request_body_registry.rb +3 -33
- data/lib/gitlab/grape_openapi/version.rb +1 -1
- data/lib/gitlab-grape-openapi.rb +4 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b864030f21b5380efa37ccb02b953f5c8d07b2f4d2fe90eb66334e155674e2bc
|
|
4
|
+
data.tar.gz: 37b0f04c277c0b1f1027bdb5f0839f06641a3c6e11fd2e9498cb9a192899914b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d7e270e89449c2f1dbdfa2f6acb4bb841abf7bbb25adf064a3f41fbf2a61eb8e9f86f698d8c826cdb111cf19aa6f21269984453913fc53554ce6f7f8eb502ba8
|
|
7
|
+
data.tar.gz: a6e772a0f79d6d1e010ddddf7a6504a96da9d94c2ad34db08bbf58d80e7bffd8df0364dc09b361c0da5cce3d2b163a2dc24cb5d57604a543926a2c1ddc4ed5fa
|
data/README.md
CHANGED
|
@@ -17,6 +17,28 @@
|
|
|
17
17
|
|
|
18
18
|
Internal gem for generating [OpenAPI 3.0](https://spec.openapis.org/oas/v3.0.0) specifications from [Grape](https://github.com/ruby-grape/grape) API definitions, used by [`gitlab-org/gitlab`](https://gitlab.com/gitlab-org/gitlab) to publish its REST API reference.
|
|
19
19
|
|
|
20
|
+
## Table of contents
|
|
21
|
+
|
|
22
|
+
- [Installation](#installation)
|
|
23
|
+
- [Configuration](#configuration)
|
|
24
|
+
- [Configuration Options](#configuration-options)
|
|
25
|
+
- [Annotations](#annotations)
|
|
26
|
+
- [Usage](#usage)
|
|
27
|
+
- [Generating an OpenAPI Specification](#generating-an-openapi-specification)
|
|
28
|
+
- [Usage with `gitlab-org/gitlab`](#usage-with-gitlab-orggitlab)
|
|
29
|
+
- [Architecture](#architecture)
|
|
30
|
+
- [Parameter constraints](#parameter-constraints)
|
|
31
|
+
- [Registries](#registries)
|
|
32
|
+
- [Response media types](#response-media-types)
|
|
33
|
+
- [Optional path segments](#optional-path-segments)
|
|
34
|
+
- [Operation IDs and request body schemas](#operation-ids-and-request-body-schemas)
|
|
35
|
+
- [Development](#development)
|
|
36
|
+
- [Running Tests](#running-tests)
|
|
37
|
+
- [Linting](#linting)
|
|
38
|
+
- [Releasing](#releasing)
|
|
39
|
+
- [Contributing](#contributing)
|
|
40
|
+
- [License](#license)
|
|
41
|
+
|
|
20
42
|
## Installation
|
|
21
43
|
|
|
22
44
|
Add to your Gemfile:
|
|
@@ -44,6 +66,8 @@ Gitlab::GrapeOpenapi.configure do |config|
|
|
|
44
66
|
version: 'v1',
|
|
45
67
|
terms_of_service: 'https://example.com/terms'
|
|
46
68
|
)
|
|
69
|
+
# A plain Hash (symbol or string keys) is also accepted and wrapped in Models::Info:
|
|
70
|
+
# config.info = { title: 'My API', version: 'v1' }
|
|
47
71
|
|
|
48
72
|
# API path configuration
|
|
49
73
|
config.api_prefix = "api" # Default: "api"
|
|
@@ -103,7 +127,7 @@ end
|
|
|
103
127
|
|
|
104
128
|
| Option | Type | Default | Description |
|
|
105
129
|
| ---------------------- | ------------------------------- | ------- | ---------------------------------------------------------------- |
|
|
106
|
-
| `info` | `Models::Info`
|
|
130
|
+
| `info` | `Models::Info` or `Hash` | `nil` | **Required.** API metadata (title, description, version, terms of service). `title` and `version` must be present and non-blank (not empty or whitespace-only), otherwise generation raises `Gitlab::GrapeOpenapi::ConfigurationError`. A `Hash` is wrapped in `Models::Info`; any other type also raises `ConfigurationError`. |
|
|
107
131
|
| `api_prefix` | `String` | `"api"` | URL prefix for API routes |
|
|
108
132
|
| `api_version` | `String` | `"v1"` | API version string |
|
|
109
133
|
| `servers` | `Array<Models::Server>` | `[]` | Server definitions for the API |
|
|
@@ -123,6 +147,7 @@ The `annotations` configuration maps Grape route settings to OpenAPI vendor exte
|
|
|
123
147
|
config.annotations = {
|
|
124
148
|
lifecycle: 'x-gitlab-lifecycle'
|
|
125
149
|
}
|
|
150
|
+
```
|
|
126
151
|
|
|
127
152
|
When a Grape endpoint has:
|
|
128
153
|
|
|
@@ -205,13 +230,15 @@ Generator
|
|
|
205
230
|
The gem documents Grape's cross-field param constraints by appending a note to
|
|
206
231
|
each affected parameter's (or request-body property's) `description` — for both
|
|
207
232
|
query/path params (`GET`/`DELETE`) and request-body params
|
|
208
|
-
(`POST`/`PUT`/`PATCH`).
|
|
233
|
+
(`POST`/`PUT`/`PATCH`). All four of Grape's cross-field constraints are
|
|
234
|
+
supported:
|
|
209
235
|
|
|
210
236
|
| Grape declaration | Note appended to every member |
|
|
211
237
|
|-------------------|-------------------------------|
|
|
212
238
|
| `mutually_exclusive :author_id, :author_username` | ``Mutually exclusive with `author_username`.`` |
|
|
213
239
|
| `exactly_one_of :project_id, :project_path` | ``Exactly one of `project_id`, `project_path` must be provided.`` |
|
|
214
240
|
| `at_least_one_of :assignee_id, :reviewer_id` | ``At least one of `assignee_id`, `reviewer_id` must be provided.`` |
|
|
241
|
+
| `all_or_none_of :extern_uid, :provider` | ``All or none of `extern_uid`, `provider` must be provided.`` |
|
|
215
242
|
|
|
216
243
|
OpenAPI 3.0 has no cross-parameter constraint keyword, and the target renderer
|
|
217
244
|
(Scalar) does not render JSON Schema `not`/`allOf`, so the constraint is stated
|
|
@@ -241,8 +268,7 @@ param into the route's query params, a constraint nested inside a `Hash` *query*
|
|
|
241
268
|
filter is documented the same as a top-level one. A constraint nested inside a
|
|
242
269
|
request-body object property has no top-level property to attach to and is
|
|
243
270
|
skipped; when `warnings` is enabled the gem logs one line per skipped group so it
|
|
244
|
-
is visible in source.
|
|
245
|
-
yet supported.
|
|
271
|
+
is visible in source.
|
|
246
272
|
|
|
247
273
|
### Registries
|
|
248
274
|
|
|
@@ -336,6 +362,17 @@ Generating the combinatorial set of paths for routes with more than one
|
|
|
336
362
|
param-bearing optional segment is **not** supported: such a route raises
|
|
337
363
|
`Gitlab::GrapeOpenapi::MultipleOptionalSegmentsError`.
|
|
338
364
|
|
|
365
|
+
### Operation IDs and request body schemas
|
|
366
|
+
|
|
367
|
+
Operation IDs are derived from the HTTP method and normalized route path. If
|
|
368
|
+
two routes produce the same ID, the later operation receives a numeric suffix
|
|
369
|
+
such as `_2`, keeping IDs unique without renaming unaffected operations.
|
|
370
|
+
|
|
371
|
+
Inline request bodies are emitted as component schemas named
|
|
372
|
+
`<operationId>Request`. The name is independent of the body shape, so adding or
|
|
373
|
+
changing a field does not rename the generated schema; identical bodies on
|
|
374
|
+
different operations retain their own operation-specific names.
|
|
375
|
+
|
|
339
376
|
## Development
|
|
340
377
|
|
|
341
378
|
```bash
|
|
@@ -69,7 +69,15 @@ module Gitlab
|
|
|
69
69
|
notes: GROUP_SENTENCE.call('At least one of')
|
|
70
70
|
}.freeze
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
ALL_OR_NONE_OF = {
|
|
73
|
+
classes: [
|
|
74
|
+
'Grape::Validations::Validators::AllOrNoneOfValidator' # Grape all versions
|
|
75
|
+
].freeze,
|
|
76
|
+
summary_format: '%d related parameters must be provided together, or not at all.',
|
|
77
|
+
notes: GROUP_SENTENCE.call('All or none of')
|
|
78
|
+
}.freeze
|
|
79
|
+
|
|
80
|
+
CONSTRAINTS = [MUTUALLY_EXCLUSIVE, EXACTLY_ONE_OF, AT_LEAST_ONE_OF, ALL_OR_NONE_OF].freeze
|
|
73
81
|
|
|
74
82
|
# For callers that need notes alone, which is every caller that has no
|
|
75
83
|
# nested scope to skip - see `#notes`.
|
|
@@ -10,23 +10,25 @@ module Gitlab
|
|
|
10
10
|
|
|
11
11
|
def self.convert(
|
|
12
12
|
route, schema_registry, request_body_registry, inherited_path_params: {},
|
|
13
|
-
path_override: nil, removed_params: [])
|
|
13
|
+
path_override: nil, removed_params: [], operation_id_registry: nil)
|
|
14
14
|
new(
|
|
15
15
|
route,
|
|
16
16
|
schema_registry,
|
|
17
17
|
request_body_registry,
|
|
18
18
|
inherited_path_params: inherited_path_params,
|
|
19
19
|
path_override: path_override,
|
|
20
|
-
removed_params: removed_params
|
|
20
|
+
removed_params: removed_params,
|
|
21
|
+
operation_id_registry: operation_id_registry
|
|
21
22
|
).convert
|
|
22
23
|
end
|
|
23
24
|
|
|
24
25
|
def initialize(
|
|
25
26
|
route, schema_registry, request_body_registry, inherited_path_params: {},
|
|
26
|
-
path_override: nil, removed_params: [])
|
|
27
|
+
path_override: nil, removed_params: [], operation_id_registry: nil)
|
|
27
28
|
@route = route
|
|
28
29
|
@schema_registry = schema_registry
|
|
29
30
|
@request_body_registry = request_body_registry
|
|
31
|
+
@operation_id_registry = operation_id_registry
|
|
30
32
|
@inherited_path_params = inherited_path_params
|
|
31
33
|
# @path_override and @removed_params are set together when optional-path-segment variants exist
|
|
32
34
|
@path_override = path_override
|
|
@@ -38,8 +40,10 @@ module Gitlab
|
|
|
38
40
|
end
|
|
39
41
|
|
|
40
42
|
def convert
|
|
43
|
+
id = operation_id_registry ? operation_id_registry.register(operation_id) : operation_id
|
|
44
|
+
|
|
41
45
|
Models::Operation.new.tap do |operation|
|
|
42
|
-
operation.operation_id =
|
|
46
|
+
operation.operation_id = id
|
|
43
47
|
operation.summary = extract_description
|
|
44
48
|
operation.description = annotate_oversized_constraints(extract_detail)
|
|
45
49
|
operation.tags = extract_tags
|
|
@@ -47,7 +51,7 @@ module Gitlab
|
|
|
47
51
|
operation.hidden = extract_hidden
|
|
48
52
|
operation.parameters = extract_parameters
|
|
49
53
|
operation.responses = ResponseConverter.new(@route, @schema_registry).convert
|
|
50
|
-
operation.request_body = extract_request_body || {}
|
|
54
|
+
operation.request_body = extract_request_body(id) || {}
|
|
51
55
|
operation.annotations = extract_annotations
|
|
52
56
|
end
|
|
53
57
|
end
|
|
@@ -55,7 +59,7 @@ module Gitlab
|
|
|
55
59
|
private
|
|
56
60
|
|
|
57
61
|
attr_reader :config, :route, :options, :pattern, :endpoint, :schema_registry, :request_body_registry,
|
|
58
|
-
:inherited_path_params, :path_override, :removed_params
|
|
62
|
+
:inherited_path_params, :path_override, :removed_params, :operation_id_registry
|
|
59
63
|
|
|
60
64
|
def route_method
|
|
61
65
|
@route.request_method
|
|
@@ -301,12 +305,13 @@ module Gitlab
|
|
|
301
305
|
GrapeCompat.validations_for(route, attribute)
|
|
302
306
|
end
|
|
303
307
|
|
|
304
|
-
def extract_request_body
|
|
308
|
+
def extract_request_body(id)
|
|
305
309
|
RequestBodyConverter.convert(
|
|
306
310
|
route: route,
|
|
307
311
|
options: options,
|
|
308
312
|
params: options[:params],
|
|
309
|
-
request_body_registry: request_body_registry
|
|
313
|
+
request_body_registry: request_body_registry,
|
|
314
|
+
operation_id: id
|
|
310
315
|
)
|
|
311
316
|
end
|
|
312
317
|
end
|
|
@@ -31,6 +31,7 @@ module Gitlab
|
|
|
31
31
|
@routes = routes
|
|
32
32
|
@schema_registry = schema_registry
|
|
33
33
|
@request_body_registry = request_body_registry
|
|
34
|
+
@operation_id_registry = OperationIdRegistry.new
|
|
34
35
|
@config = Gitlab::GrapeOpenapi.configuration
|
|
35
36
|
@inherited_path_params = {}
|
|
36
37
|
end
|
|
@@ -116,15 +117,18 @@ module Gitlab
|
|
|
116
117
|
|
|
117
118
|
def build_path_item(routes_for_path, variant)
|
|
118
119
|
path_item = Models::PathItem.new
|
|
120
|
+
routes_by_method = routes_for_path.group_by { |route| extract_method(route) }
|
|
121
|
+
.transform_values(&:last)
|
|
119
122
|
|
|
120
|
-
|
|
123
|
+
routes_by_method.each_value do |route|
|
|
121
124
|
operation = OperationConverter.convert(
|
|
122
125
|
route,
|
|
123
126
|
schema_registry,
|
|
124
127
|
request_body_registry,
|
|
125
128
|
inherited_path_params: inherited_path_params,
|
|
126
129
|
path_override: variant.path_override,
|
|
127
|
-
removed_params: variant.removed_params
|
|
130
|
+
removed_params: variant.removed_params,
|
|
131
|
+
operation_id_registry: @operation_id_registry
|
|
128
132
|
)
|
|
129
133
|
method = extract_method(route)
|
|
130
134
|
path_item.add_operation(method, operation)
|
|
@@ -9,17 +9,19 @@ module Gitlab
|
|
|
9
9
|
GET_METHOD = 'GET'
|
|
10
10
|
DELETE_METHOD = 'DELETE'
|
|
11
11
|
|
|
12
|
-
attr_reader :route, :options, :params, :request_body_registry
|
|
12
|
+
attr_reader :route, :options, :params, :request_body_registry, :operation_id
|
|
13
13
|
|
|
14
|
-
def self.convert(route:, options:, params:, request_body_registry:)
|
|
15
|
-
new(route: route, options: options, params: params, request_body_registry: request_body_registry
|
|
14
|
+
def self.convert(route:, options:, params:, request_body_registry:, operation_id:)
|
|
15
|
+
new(route: route, options: options, params: params, request_body_registry: request_body_registry,
|
|
16
|
+
operation_id: operation_id).convert
|
|
16
17
|
end
|
|
17
18
|
|
|
18
|
-
def initialize(route:, options:, params:, request_body_registry:)
|
|
19
|
+
def initialize(route:, options:, params:, request_body_registry:, operation_id:)
|
|
19
20
|
@route = route
|
|
20
21
|
@options = options
|
|
21
22
|
@params = params
|
|
22
23
|
@request_body_registry = request_body_registry
|
|
24
|
+
@operation_id = operation_id
|
|
23
25
|
end
|
|
24
26
|
|
|
25
27
|
def convert
|
|
@@ -58,7 +60,7 @@ module Gitlab
|
|
|
58
60
|
}
|
|
59
61
|
schema[:required] = required_params unless required_params.empty?
|
|
60
62
|
|
|
61
|
-
schema_ref = request_body_registry.register(schema)
|
|
63
|
+
schema_ref = request_body_registry.register(schema, name: "#{operation_id}Request")
|
|
62
64
|
|
|
63
65
|
{
|
|
64
66
|
required: required_params.any?,
|
|
@@ -15,11 +15,13 @@ module Gitlab
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def generate
|
|
18
|
+
# Resolved before initialize_tags so an invalid config.info fails before any conversion runs.
|
|
19
|
+
info = openapi_info
|
|
18
20
|
initialize_tags
|
|
19
21
|
|
|
20
22
|
{
|
|
21
23
|
openapi: '3.0.0',
|
|
22
|
-
info:
|
|
24
|
+
info: info,
|
|
23
25
|
tags: tag_registry.tags.sort_by { |t| t.fetch(:name, '') },
|
|
24
26
|
servers: Gitlab::GrapeOpenapi.configuration.servers.map(&:to_h),
|
|
25
27
|
paths: paths,
|
|
@@ -50,9 +52,37 @@ module Gitlab
|
|
|
50
52
|
|
|
51
53
|
private
|
|
52
54
|
|
|
55
|
+
def openapi_info
|
|
56
|
+
hash = configured_info.to_h
|
|
57
|
+
return hash unless blank?(hash[:title]) || blank?(hash[:version])
|
|
58
|
+
|
|
59
|
+
raise ConfigurationError, "config.info must be set with at least a title and version"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def configured_info
|
|
63
|
+
info = Gitlab::GrapeOpenapi.configuration.info
|
|
64
|
+
|
|
65
|
+
case info
|
|
66
|
+
when Models::Info then info
|
|
67
|
+
when Hash then Models::Info.new(**info.transform_keys(&:to_sym))
|
|
68
|
+
when nil then Models::Info.new
|
|
69
|
+
else
|
|
70
|
+
raise ConfigurationError,
|
|
71
|
+
"config.info must be a Gitlab::GrapeOpenapi::Models::Info or Hash, got #{info.class}"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def blank?(value)
|
|
76
|
+
value.to_s.strip.empty?
|
|
77
|
+
end
|
|
78
|
+
|
|
53
79
|
def schemas
|
|
54
80
|
entity_schemas = @schema_registry.schemas.transform_values(&:to_h)
|
|
55
81
|
request_body_schemas = @request_body_registry.schemas
|
|
82
|
+
|
|
83
|
+
collisions = entity_schemas.keys & request_body_schemas.keys
|
|
84
|
+
raise ArgumentError, "Schema component name collision: #{collisions.join(', ')}" unless collisions.empty?
|
|
85
|
+
|
|
56
86
|
entity_schemas.merge(request_body_schemas)
|
|
57
87
|
end
|
|
58
88
|
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module GrapeOpenapi
|
|
5
|
+
class OperationIdRegistry
|
|
6
|
+
def initialize
|
|
7
|
+
@operation_ids = {}
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def register(candidate)
|
|
11
|
+
operation_id = candidate
|
|
12
|
+
suffix = 2
|
|
13
|
+
|
|
14
|
+
while @operation_ids.key?(operation_id)
|
|
15
|
+
operation_id = "#{candidate}_#{suffix}"
|
|
16
|
+
suffix += 1
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
@operation_ids[operation_id] = true
|
|
20
|
+
operation_id
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'openssl'
|
|
4
|
-
|
|
5
3
|
module Gitlab
|
|
6
4
|
module GrapeOpenapi
|
|
7
5
|
class RequestBodyRegistry
|
|
@@ -11,47 +9,19 @@ module Gitlab
|
|
|
11
9
|
|
|
12
10
|
def initialize
|
|
13
11
|
@schemas = {}
|
|
14
|
-
@schema_hashes = {}
|
|
15
12
|
end
|
|
16
13
|
|
|
17
|
-
def register(schema)
|
|
14
|
+
def register(schema, name:)
|
|
18
15
|
return nil if schema.blank?
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if @schema_hashes.key?(schema_hash)
|
|
23
|
-
existing_name = @schema_hashes[schema_hash]
|
|
24
|
-
return { '$ref' => "#{SCHEMA_PATH_PREFIX}#{existing_name}" }
|
|
17
|
+
if @schemas.key?(name) && @schemas[name] != schema
|
|
18
|
+
raise ArgumentError, "Request body schema name '#{name}' is already registered"
|
|
25
19
|
end
|
|
26
20
|
|
|
27
|
-
name = "RequestBody_#{short_hash(schema_hash)}"
|
|
28
21
|
@schemas[name] = schema
|
|
29
|
-
@schema_hashes[schema_hash] = name
|
|
30
22
|
|
|
31
23
|
{ '$ref' => "#{SCHEMA_PATH_PREFIX}#{name}" }
|
|
32
24
|
end
|
|
33
|
-
|
|
34
|
-
private
|
|
35
|
-
|
|
36
|
-
def compute_hash(schema)
|
|
37
|
-
normalized = normalize_for_hash(schema)
|
|
38
|
-
OpenSSL::Digest::SHA256.hexdigest(normalized.to_s)
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def short_hash(full_hash)
|
|
42
|
-
full_hash[0, 12]
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def normalize_for_hash(obj)
|
|
46
|
-
case obj
|
|
47
|
-
when Hash
|
|
48
|
-
obj.sort.map { |k, v| [k.to_s, normalize_for_hash(v)] }
|
|
49
|
-
when Array
|
|
50
|
-
obj.map { |v| normalize_for_hash(v) }
|
|
51
|
-
else
|
|
52
|
-
obj
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
25
|
end
|
|
56
26
|
end
|
|
57
27
|
end
|
data/lib/gitlab-grape-openapi.rb
CHANGED
|
@@ -6,6 +6,7 @@ require_relative "gitlab/grape_openapi/configuration"
|
|
|
6
6
|
require_relative "gitlab/grape_openapi/generator"
|
|
7
7
|
require_relative "gitlab/grape_openapi/schema_registry"
|
|
8
8
|
require_relative "gitlab/grape_openapi/request_body_registry"
|
|
9
|
+
require_relative "gitlab/grape_openapi/operation_id_registry"
|
|
9
10
|
require_relative "gitlab/grape_openapi/tag_registry"
|
|
10
11
|
require_relative "gitlab/grape_openapi/normalized_path"
|
|
11
12
|
|
|
@@ -51,6 +52,9 @@ module Gitlab
|
|
|
51
52
|
module GrapeOpenapi
|
|
52
53
|
GenerationError = Class.new(StandardError)
|
|
53
54
|
|
|
55
|
+
# Raised when `config.info` is missing a title or version.
|
|
56
|
+
ConfigurationError = Class.new(GenerationError)
|
|
57
|
+
|
|
54
58
|
# Raised when a route declares more than one optional path segment
|
|
55
59
|
# containing a named parameter (e.g. `/foo(/:a)/bar(/:b)`).
|
|
56
60
|
MultipleOptionalSegmentsError = Class.new(GenerationError)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gitlab-grape-openapi
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- group::api
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-10-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: grape
|
|
@@ -172,6 +172,7 @@ files:
|
|
|
172
172
|
- lib/gitlab/grape_openapi/models/server_variable.rb
|
|
173
173
|
- lib/gitlab/grape_openapi/models/tag.rb
|
|
174
174
|
- lib/gitlab/grape_openapi/normalized_path.rb
|
|
175
|
+
- lib/gitlab/grape_openapi/operation_id_registry.rb
|
|
175
176
|
- lib/gitlab/grape_openapi/request_body_registry.rb
|
|
176
177
|
- lib/gitlab/grape_openapi/schema_registry.rb
|
|
177
178
|
- lib/gitlab/grape_openapi/serializers/time.rb
|