openapi_first 4.3.0 → 4.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
- data/CHANGELOG.md +6 -0
- data/README.md +13 -0
- data/lib/openapi_first/child_configuration.rb +6 -2
- data/lib/openapi_first/definition.rb +11 -2
- data/lib/openapi_first/middlewares/request_validation.rb +7 -8
- data/lib/openapi_first/router/path_trie.rb +10 -1
- data/lib/openapi_first/version.rb +1 -1
- data/lib/openapi_first.rb +9 -4
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ef15e925e193150f3425c32bd94986f3c069f12af86a88ad043886de13c1ca8a
|
|
4
|
+
data.tar.gz: d4f11e849a469be720cbd5973ffb04e039664101ed44484d4b4f4b2c5ef542f8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8aa700d2587944d67f5e2372fe7793c1cd71a76e6c772bf56938564e4f4c4221cb29e54e0ec37bec66c1da370415aabbebb7f722f4cd4fbeba478919308df6cb
|
|
7
|
+
data.tar.gz: 6ef3870f3b011ac35065775da7265d6bc6dff0b121ec0ee42a7e5b47a9fd69d17dbc25ea85723615206d9704afcaee4f65ff3f04e6c85f430ea4781316260ff8
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 4.4.0
|
|
6
|
+
|
|
7
|
+
- Changed: Percent-encoded path parameters are now decoded. For example `/files/my%20file` yields `my file` for `/files/{name}`. A `+` stays a `+`. Values with a malformed encoding or that do not decode to valid UTF-8 are kept as they are. If your application decodes path parameters itself, remove that, or values get decoded twice. Known limitation: An encoded delimiter inside an array or object path parameter is decoded before the value is split, so `/files/a%2Cb,c` yields `["a", "b", "c"]`.
|
|
8
|
+
- Added: You can pass a block to `OpenapiFirst::Middlewares::RequestValidation` to configure hooks and other options specifically for that middleware. With a registered name or a Definition it creates a copy of that OAD, so the registered OAD stays unchanged.
|
|
9
|
+
- Fix: `OpenapiFirst.load` now accepts and applies a configuration block.
|
|
10
|
+
|
|
5
11
|
## 4.3.0
|
|
6
12
|
|
|
7
13
|
- Fix: Passing a block to `config.register` not works when called inside `OpenapiFirst.configure` block. Before the block was ignored.
|
data/README.md
CHANGED
|
@@ -84,6 +84,19 @@ The request validation middleware returns a 4xx if the request is invalid or not
|
|
|
84
84
|
use OpenapiFirst::Middlewares::RequestValidation
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
+
You can pass a block to configure [hooks](#hooks) and other options for this middleware only:
|
|
88
|
+
|
|
89
|
+
```ruby
|
|
90
|
+
use OpenapiFirst::Middlewares::RequestValidation, :v1 do |config|
|
|
91
|
+
config.request_validation_error_response = :jsonapi
|
|
92
|
+
config.after_request_validation do |validated_request|
|
|
93
|
+
warn validated_request.error.message if validated_request.invalid?
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
If you pass a registered name or a Definition together with a block, the middleware uses a copy of that OAD that keeps its configuration and adds yours. The registered OAD stays unchanged.
|
|
99
|
+
|
|
87
100
|
#### Error responses
|
|
88
101
|
|
|
89
102
|
openapi_first produces a useful machine readable error response that can be customized.
|
|
@@ -6,16 +6,20 @@ module OpenapiFirst
|
|
|
6
6
|
def initialize(parent:)
|
|
7
7
|
super()
|
|
8
8
|
@parent = parent
|
|
9
|
-
@request_validation_error_response =
|
|
9
|
+
@request_validation_error_response = nil
|
|
10
10
|
@path = parent.path
|
|
11
11
|
@regexp_resolver = parent.regexp_resolver
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
private attr_reader :parent
|
|
15
15
|
|
|
16
|
+
def request_validation_error_response
|
|
17
|
+
@request_validation_error_response || parent.request_validation_error_response
|
|
18
|
+
end
|
|
19
|
+
|
|
16
20
|
HOOKS.each do |hook|
|
|
17
21
|
define_method(hook) do |&block|
|
|
18
|
-
return hooks[hook].chain(parent.
|
|
22
|
+
return hooks[hook].chain(parent.public_send(hook)) if block.nil?
|
|
19
23
|
|
|
20
24
|
hooks[hook] << block
|
|
21
25
|
block
|
|
@@ -24,10 +24,11 @@ module OpenapiFirst
|
|
|
24
24
|
# @param contents [Hash] The OpenAPI document.
|
|
25
25
|
# @param filepath [String] The file path of the OpenAPI document.
|
|
26
26
|
# @param path_prefix [String,nil] An optional path prefix, that is not documented, that all requests begin with.
|
|
27
|
-
|
|
27
|
+
# @param config [Configuration] The configuration to use. Gets yielded and frozen.
|
|
28
|
+
def initialize(contents, filepath = nil, path_prefix = nil, config: OpenapiFirst.configuration.child)
|
|
28
29
|
@filepath = filepath
|
|
29
30
|
@path_prefix = path_prefix
|
|
30
|
-
@config =
|
|
31
|
+
@config = config
|
|
31
32
|
yield @config if block_given?
|
|
32
33
|
@config.freeze
|
|
33
34
|
@router = Builder.build_router(contents, filepath:, config:)
|
|
@@ -35,6 +36,14 @@ module OpenapiFirst
|
|
|
35
36
|
@paths = @router.routes.map(&:path).to_a.uniq # TODO: Refactor
|
|
36
37
|
end
|
|
37
38
|
|
|
39
|
+
# Returns a new Definition of the same document whose configuration is a child of this one's.
|
|
40
|
+
# @visibility private
|
|
41
|
+
# @yield [Configuration]
|
|
42
|
+
# @return [Definition]
|
|
43
|
+
def configure(&)
|
|
44
|
+
Definition.new(@resolved, filepath, path_prefix, config: @config.child, &)
|
|
45
|
+
end
|
|
46
|
+
|
|
38
47
|
# Gives access to the raw resolved Hash. Like `mydefinition['components'].dig('schemas', 'Stations')`
|
|
39
48
|
# @!method [](key)
|
|
40
49
|
# @return [Hash]
|
|
@@ -29,20 +29,19 @@ module OpenapiFirst
|
|
|
29
29
|
# :error_response The Class to use for error responses.
|
|
30
30
|
# This can be a Symbol-name of an registered error response (:default, :jsonapi)
|
|
31
31
|
# or it can be set to false to disable returning a response.
|
|
32
|
-
# default:
|
|
33
|
-
|
|
32
|
+
# default: the configured request_validation_error_response
|
|
33
|
+
# @yield [Configuration] Optional block to configure hooks and other options for this middleware.
|
|
34
|
+
# If spec is a registered name or a Definition, this uses a new Definition that inherits its configuration,
|
|
35
|
+
# so the registered Definition is not changed.
|
|
36
|
+
def initialize(app, spec = nil, options = {}, &)
|
|
34
37
|
@app = app
|
|
35
38
|
if spec.is_a?(Hash)
|
|
36
39
|
options = spec
|
|
37
40
|
spec = options[:spec]
|
|
38
41
|
end
|
|
39
42
|
@raise = options.fetch(:raise_error, false)
|
|
43
|
+
@definition = OpenapiFirst.load(spec || :default, &)
|
|
40
44
|
@error_response_class = error_response_option(options[:error_response])
|
|
41
|
-
|
|
42
|
-
spec ||= :default
|
|
43
|
-
spec = OpenapiFirst[spec] if spec.is_a?(Symbol)
|
|
44
|
-
|
|
45
|
-
@definition = spec.is_a?(Definition) ? spec : OpenapiFirst.load(spec)
|
|
46
45
|
end
|
|
47
46
|
|
|
48
47
|
# @attr_reader [Proc] app The upstream Rack application
|
|
@@ -70,7 +69,7 @@ module OpenapiFirst
|
|
|
70
69
|
return if value == false
|
|
71
70
|
return OpenapiFirst.find_error_response(value) if value.is_a?(Symbol)
|
|
72
71
|
|
|
73
|
-
value ||
|
|
72
|
+
value || @definition.config.request_validation_error_response
|
|
74
73
|
end
|
|
75
74
|
end
|
|
76
75
|
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'rack/utils'
|
|
3
4
|
require_relative '../path_template'
|
|
4
5
|
require_relative 'segment_pattern'
|
|
5
6
|
|
|
@@ -23,7 +24,10 @@ module OpenapiFirst
|
|
|
23
24
|
def match(path)
|
|
24
25
|
values = []
|
|
25
26
|
value, names = find(path.split('/', -1), 0, values)
|
|
26
|
-
|
|
27
|
+
return unless value
|
|
28
|
+
|
|
29
|
+
values.map! { decode(_1) } if path.include?('%')
|
|
30
|
+
[value, names.zip(values).to_h]
|
|
27
31
|
end
|
|
28
32
|
|
|
29
33
|
def find(segments, index, values)
|
|
@@ -47,6 +51,11 @@ module OpenapiFirst
|
|
|
47
51
|
|
|
48
52
|
private
|
|
49
53
|
|
|
54
|
+
def decode(value)
|
|
55
|
+
decoded = Rack::Utils.unescape_path(value).force_encoding(Encoding::UTF_8)
|
|
56
|
+
decoded.valid_encoding? ? decoded : value
|
|
57
|
+
end
|
|
58
|
+
|
|
50
59
|
def find_partial(segments, index, values)
|
|
51
60
|
@partial.each_value do |pattern, node|
|
|
52
61
|
captures = pattern.match(segments[index])
|
data/lib/openapi_first.rb
CHANGED
|
@@ -62,15 +62,20 @@ module OpenapiFirst
|
|
|
62
62
|
configuration.plugin(name, **)
|
|
63
63
|
end
|
|
64
64
|
|
|
65
|
-
# Load and dereference an OpenAPI spec file or return the Definition if it's already loaded
|
|
66
|
-
#
|
|
65
|
+
# Load and dereference an OpenAPI spec file or return the Definition if it's already loaded.
|
|
66
|
+
# If a block is given together with a Definition or Symbol,
|
|
67
|
+
# this returns a new Definition with the configuration block applied.
|
|
68
|
+
# @param filepath_or_definition [String, Symbol, Definition] The path to the file, a registered name or a Definition
|
|
67
69
|
# @param only [Proc, nil] An optional proc to filter paths. It is called with the path string and should return
|
|
68
70
|
# true/false
|
|
69
71
|
# @param path_prefix [String, nil] An optional path prefix, that is not documented, that all requests begin with.
|
|
72
|
+
# @yieldparam config [Configuration] Configuration of the returned Definition.
|
|
70
73
|
# @return [Definition]
|
|
71
74
|
def self.load(filepath_or_definition, only: nil, path_prefix: nil, &)
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
if filepath_or_definition.is_a?(Definition) || filepath_or_definition.is_a?(Symbol)
|
|
76
|
+
definition = self[filepath_or_definition]
|
|
77
|
+
return block_given? ? definition.configure(&) : definition
|
|
78
|
+
end
|
|
74
79
|
|
|
75
80
|
filepath = filepath_or_definition
|
|
76
81
|
raise FileNotFoundError, "File not found: #{filepath}" unless File.exist?(filepath)
|