openapi_first 3.3.0 → 3.3.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/CHANGELOG.md +6 -1
- data/README.md +0 -3
- data/lib/openapi_first/builder.rb +5 -3
- data/lib/openapi_first/file_loader.rb +8 -8
- data/lib/openapi_first/ref_resolver.rb +29 -16
- data/lib/openapi_first/version.rb +1 -1
- data/lib/openapi_first.rb +0 -5
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1786c083ff520504c716e9bdd1e8b92754be71e70dd774644b6a0c655681369a
|
|
4
|
+
data.tar.gz: bc86929efbbe041515cfb12e6d453133cb4cf0a849c40ae5c526eda1b910a4cd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4b745143e975173192680152d5b42243c4eb58e8158b4f71aa67730780ad9ec49e788767f8bd5816f0b5dc6ffb711bbba362968a2c075db11dc5c7f11d29733d
|
|
7
|
+
data.tar.gz: 32b7bbab75bd6fbb1620808f389d4bfc051a20da124823ada6ea154635306b8b6f6ad378c4bc55a1733211b6438092b307d36d83cc3d23494462729c7b80c817
|
data/CHANGELOG.md
CHANGED
|
@@ -2,9 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 3.3.1
|
|
6
|
+
|
|
7
|
+
- Optimized caching towards reducing retained memory after calling `OpenapiFirst.load` without using a global cache. (Removed `OpenapiFirst.clear_cache!`.)
|
|
8
|
+
- Require ruby >= 3.3.0
|
|
9
|
+
|
|
5
10
|
## 3.3.0
|
|
6
11
|
|
|
7
|
-
- OpenapiFirst will now cache the contents of files that have been loaded. If you need to reload your OpenAPI definition for tests or server hot reloading, you can call `OpenapiFirst.clear_cache
|
|
12
|
+
- ~OpenapiFirst will now cache the contents of files that have been loaded. If you need to reload your OpenAPI definition for tests or server hot reloading, you can call `OpenapiFirst.clear_cache!`.~
|
|
8
13
|
- Optimized `OpenapiFirst::Router#match` for faster path matching and reduced memory allocation.
|
|
9
14
|
|
|
10
15
|
## 3.2.1
|
data/README.md
CHANGED
|
@@ -82,9 +82,6 @@ The request validation middleware returns a 4xx if the request is invalid or not
|
|
|
82
82
|
|
|
83
83
|
```ruby
|
|
84
84
|
use OpenapiFirst::Middlewares::RequestValidation
|
|
85
|
-
|
|
86
|
-
# Pass `raise_error: true` to raise an error if request is invalid:
|
|
87
|
-
use OpenapiFirst::Middlewares::RequestValidation, raise_error: true
|
|
88
85
|
```
|
|
89
86
|
|
|
90
87
|
#### Error responses
|
|
@@ -27,18 +27,20 @@ module OpenapiFirst
|
|
|
27
27
|
meta_schema = detect_meta_schema(contents, filepath)
|
|
28
28
|
@schemer_configuration = build_schemer_config(filepath:, meta_schema:)
|
|
29
29
|
@config = config
|
|
30
|
-
@
|
|
30
|
+
@file_loader = FileLoader.new
|
|
31
|
+
ref_resolver = RefResolver.new(file_loader:)
|
|
32
|
+
@contents = ref_resolver.for(contents, filepath:)
|
|
31
33
|
end
|
|
32
34
|
|
|
33
35
|
attr_reader :config
|
|
34
|
-
private attr_reader :schemer_configuration
|
|
36
|
+
private attr_reader :schemer_configuration, :file_loader
|
|
35
37
|
|
|
36
38
|
def build_schemer_config(filepath:, meta_schema:)
|
|
37
39
|
result = JSONSchemer.configuration.clone
|
|
38
40
|
dir = (filepath && File.absolute_path(File.dirname(filepath))) || Dir.pwd
|
|
39
41
|
result.base_uri = URI::File.build({ path: "#{dir}/" })
|
|
40
42
|
result.ref_resolver = JSONSchemer::CachedResolver.new do |uri|
|
|
41
|
-
|
|
43
|
+
file_loader.load(uri.path)
|
|
42
44
|
end
|
|
43
45
|
result.meta_schema = meta_schema
|
|
44
46
|
result.insert_property_defaults = true
|
|
@@ -5,11 +5,15 @@ require 'yaml'
|
|
|
5
5
|
|
|
6
6
|
module OpenapiFirst
|
|
7
7
|
# @!visibility private
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
class FileLoader
|
|
9
|
+
def self.load(file_path)
|
|
10
|
+
new.load(file_path)
|
|
11
|
+
end
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
def initialize
|
|
14
|
+
@cache = {}
|
|
15
|
+
@mutex = Mutex.new
|
|
16
|
+
end
|
|
13
17
|
|
|
14
18
|
def load(file_path)
|
|
15
19
|
@cache[file_path] || @mutex.synchronize do
|
|
@@ -29,9 +33,5 @@ module OpenapiFirst
|
|
|
29
33
|
end
|
|
30
34
|
end
|
|
31
35
|
end
|
|
32
|
-
|
|
33
|
-
def clear_cache!
|
|
34
|
-
@mutex.synchronize { @cache.clear }
|
|
35
|
-
end
|
|
36
36
|
end
|
|
37
37
|
end
|
|
@@ -5,30 +5,42 @@ require 'json_schemer'
|
|
|
5
5
|
module OpenapiFirst
|
|
6
6
|
# This is here to give traverse an OAD while keeping $refs intact
|
|
7
7
|
# @visibility private
|
|
8
|
-
|
|
9
|
-
def
|
|
10
|
-
|
|
8
|
+
class RefResolver
|
|
9
|
+
def initialize(file_loader:)
|
|
10
|
+
@file_loader = file_loader
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private attr_reader :file_loader
|
|
14
|
+
|
|
15
|
+
def load(filepath)
|
|
16
|
+
contents = file_loader.load(filepath)
|
|
11
17
|
self.for(contents, filepath:)
|
|
12
18
|
end
|
|
13
19
|
|
|
14
|
-
def
|
|
20
|
+
def for(value, filepath: nil, context: value)
|
|
15
21
|
case value
|
|
16
22
|
when ::Hash
|
|
17
|
-
resolver = Hash.new(value, context:, filepath:)
|
|
23
|
+
resolver = Hash.new(value, context:, filepath:, ref_resolver: self)
|
|
18
24
|
if value.key?('$ref')
|
|
19
25
|
probe = resolver.resolve_ref(value['$ref'])
|
|
20
26
|
return probe if probe.is_a?(Array)
|
|
21
27
|
end
|
|
22
28
|
resolver
|
|
23
29
|
when ::Array
|
|
24
|
-
Array.new(value, context:, filepath:)
|
|
30
|
+
Array.new(value, context:, filepath:, ref_resolver: self)
|
|
25
31
|
when ::NilClass
|
|
26
32
|
nil
|
|
27
33
|
else
|
|
28
|
-
Simple.new(value)
|
|
34
|
+
Simple.new(value, ref_resolver: self)
|
|
29
35
|
end
|
|
30
36
|
end
|
|
31
37
|
|
|
38
|
+
def file_at(filepath, file_pointer)
|
|
39
|
+
file_contents = file_loader.load(filepath)
|
|
40
|
+
value = Hana::Pointer.new(file_pointer).eval(file_contents)
|
|
41
|
+
self.for(value, filepath: filepath, context: file_contents)
|
|
42
|
+
end
|
|
43
|
+
|
|
32
44
|
# @visibility private
|
|
33
45
|
module Diggable
|
|
34
46
|
def dig(*keys)
|
|
@@ -42,10 +54,11 @@ module OpenapiFirst
|
|
|
42
54
|
|
|
43
55
|
# @visibility private
|
|
44
56
|
module Resolvable
|
|
45
|
-
def initialize(value, context: value, filepath: nil)
|
|
57
|
+
def initialize(value, ref_resolver:, context: value, filepath: nil)
|
|
46
58
|
@value = value
|
|
47
59
|
@context = context
|
|
48
60
|
@filepath = filepath
|
|
61
|
+
@ref_resolver = ref_resolver
|
|
49
62
|
@dir = if filepath
|
|
50
63
|
File.dirname(File.absolute_path(filepath))
|
|
51
64
|
else
|
|
@@ -62,6 +75,8 @@ module OpenapiFirst
|
|
|
62
75
|
|
|
63
76
|
attr_reader :filepath
|
|
64
77
|
|
|
78
|
+
private attr_reader :ref_resolver
|
|
79
|
+
|
|
65
80
|
def ==(_other)
|
|
66
81
|
raise "Don't call == on an unresolved value. Use .value == other instead."
|
|
67
82
|
end
|
|
@@ -71,16 +86,14 @@ module OpenapiFirst
|
|
|
71
86
|
value = Hana::Pointer.new(pointer[1..]).eval(context)
|
|
72
87
|
raise "Unknown reference #{pointer} in #{context}" unless value
|
|
73
88
|
|
|
74
|
-
return
|
|
89
|
+
return ref_resolver.for(value, filepath:, context:)
|
|
75
90
|
end
|
|
76
91
|
|
|
77
92
|
relative_path, file_pointer = pointer.split('#')
|
|
78
93
|
full_path = File.expand_path(relative_path, dir)
|
|
79
|
-
return
|
|
94
|
+
return ref_resolver.load(full_path) unless file_pointer
|
|
80
95
|
|
|
81
|
-
|
|
82
|
-
value = Hana::Pointer.new(file_pointer).eval(file_contents)
|
|
83
|
-
RefResolver.for(value, filepath: full_path, context: file_contents)
|
|
96
|
+
ref_resolver.file_at(full_path, file_pointer)
|
|
84
97
|
rescue OpenapiFirst::FileNotFoundError => e
|
|
85
98
|
message = "Problem with reference resolving #{pointer.inspect} in " \
|
|
86
99
|
"file #{File.absolute_path(filepath).inspect}: #{e.message}"
|
|
@@ -114,13 +127,13 @@ module OpenapiFirst
|
|
|
114
127
|
def [](key)
|
|
115
128
|
return resolve_ref(@value['$ref'])[key] if !@value.key?(key) && @value.key?('$ref')
|
|
116
129
|
|
|
117
|
-
|
|
130
|
+
ref_resolver.for(@value[key], filepath:, context:)
|
|
118
131
|
end
|
|
119
132
|
|
|
120
133
|
def fetch(key)
|
|
121
134
|
return resolve_ref(@value['$ref']).fetch(key) if !@value.key?(key) && @value.key?('$ref')
|
|
122
135
|
|
|
123
|
-
|
|
136
|
+
ref_resolver.for(@value.fetch(key), filepath:, context:)
|
|
124
137
|
end
|
|
125
138
|
|
|
126
139
|
def each
|
|
@@ -170,7 +183,7 @@ module OpenapiFirst
|
|
|
170
183
|
item = @value[index]
|
|
171
184
|
return resolve_ref(item['$ref']) if item.is_a?(::Hash) && item.key?('$ref')
|
|
172
185
|
|
|
173
|
-
|
|
186
|
+
ref_resolver.for(item, filepath:, context:)
|
|
174
187
|
end
|
|
175
188
|
|
|
176
189
|
def each
|
data/lib/openapi_first.rb
CHANGED
|
@@ -22,11 +22,6 @@ module OpenapiFirst
|
|
|
22
22
|
|
|
23
23
|
FAILURE = :openapi_first_validation_failure
|
|
24
24
|
|
|
25
|
-
# Clears cached files
|
|
26
|
-
def self.clear_cache!
|
|
27
|
-
FileLoader.clear_cache!
|
|
28
|
-
end
|
|
29
|
-
|
|
30
25
|
# @return [Configuration]
|
|
31
26
|
def self.configuration
|
|
32
27
|
@configuration ||= Configuration.new
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: openapi_first
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.3.
|
|
4
|
+
version: 3.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andreas Haller
|
|
@@ -179,14 +179,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
179
179
|
requirements:
|
|
180
180
|
- - ">="
|
|
181
181
|
- !ruby/object:Gem::Version
|
|
182
|
-
version: 3.
|
|
182
|
+
version: 3.3.0
|
|
183
183
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
184
184
|
requirements:
|
|
185
185
|
- - ">="
|
|
186
186
|
- !ruby/object:Gem::Version
|
|
187
187
|
version: '0'
|
|
188
188
|
requirements: []
|
|
189
|
-
rubygems_version: 4.0.
|
|
189
|
+
rubygems_version: 4.0.10
|
|
190
190
|
specification_version: 4
|
|
191
191
|
summary: OpenAPI based request validation, response validation, contract-testing and
|
|
192
192
|
coverage
|