skooma 0.2.0 → 0.2.2
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 +36 -1
- data/README.md +7 -0
- data/lib/skooma/matchers/conform_response_schema.rb +1 -1
- data/lib/skooma/matchers/wrapper.rb +6 -5
- data/lib/skooma/objects/openapi/keywords/paths.rb +2 -1
- data/lib/skooma/objects/openapi.rb +12 -0
- data/lib/skooma/objects/operation/keywords/parameters.rb +1 -1
- data/lib/skooma/objects/parameter/keywords/value_parser.rb +6 -4
- data/lib/skooma/objects/path_item/keywords/base_operation.rb +4 -0
- data/lib/skooma/output_format.rb +3 -2
- data/lib/skooma/version.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d780ea317b116a8bdafac72f240b68366cf6f2892ea671f29ed51dd48a198093
|
4
|
+
data.tar.gz: '078593785c8fc17c73c171616131880dbeaf1b85923e593a3612eb9b2309ff0d'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f16cb70ad584c45615c4c376ebbab69e48caca0daa32c687d55c9c96453b3a608096afeedc45a7286e0e4ace4c2dc500c2d36ed013d0b951d915b60bbba42a63
|
7
|
+
data.tar.gz: c301176ff04134e0e6d18c57e4e0ced55f1dca82d8ff807eefa820cc02f8227101275ccf43b4e3b60c6716b19d7da94f714da37435f417995e97faf44f2b20d3
|
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,39 @@ and this project adheres to [Semantic Versioning].
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## [0.2.2] - 2024-01-04
|
11
|
+
|
12
|
+
### Added
|
13
|
+
|
14
|
+
- Add support for APIs mounted under a path prefix. ([@skryukov])
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
# spec/rails_helper.rb
|
18
|
+
|
19
|
+
RSpec.configure do |config|
|
20
|
+
# ...
|
21
|
+
path_to_openapi = Rails.root.join("docs", "openapi.yml")
|
22
|
+
# pass path_prefix option if your API is mounted under a prefix:
|
23
|
+
config.include Skooma::RSpec[path_to_openapi, path_prefix: "/internal/api"], type: :request
|
24
|
+
end
|
25
|
+
```
|
26
|
+
|
27
|
+
### Changed
|
28
|
+
|
29
|
+
- Bump `json_skooma` version to `~> 0.2.0`. ([@skryukov])
|
30
|
+
|
31
|
+
### Fixed
|
32
|
+
|
33
|
+
- Better checks to automatic request/response detection to prevent methods overrides via RSpec helpers (i.e. `subject(:response)`). ([@skryukov])
|
34
|
+
- Fail response validation when expected response code or `responses` keyword aren't listed. ([@skryukov])
|
35
|
+
|
36
|
+
## [0.2.1] - 2023-10-23
|
37
|
+
|
38
|
+
### Fixed
|
39
|
+
|
40
|
+
- Raise error when parameter attributes misses required keys. ([@skryukov])
|
41
|
+
- Fix output format. ([@skryukov])
|
42
|
+
|
10
43
|
## [0.2.0] - 2023-10-23
|
11
44
|
|
12
45
|
### Added
|
@@ -26,7 +59,9 @@ and this project adheres to [Semantic Versioning].
|
|
26
59
|
|
27
60
|
[@skryukov]: https://github.com/skryukov
|
28
61
|
|
29
|
-
[Unreleased]: https://github.com/skryukov/skooma/compare/v0.2.
|
62
|
+
[Unreleased]: https://github.com/skryukov/skooma/compare/v0.2.2...HEAD
|
63
|
+
[0.2.2]: https://github.com/skryukov/skooma/compare/v0.2.1...v0.2.2
|
64
|
+
[0.2.1]: https://github.com/skryukov/skooma/compare/v0.2.0...v0.2.1
|
30
65
|
[0.2.0]: https://github.com/skryukov/skooma/compare/v0.1.0...v0.2.0
|
31
66
|
[0.1.0]: https://github.com/skryukov/skooma/commits/v0.1.0
|
32
67
|
|
data/README.md
CHANGED
@@ -14,6 +14,10 @@ Skooma is a Ruby library for validating API implementations against OpenAPI docu
|
|
14
14
|
- Supports request/response validations against OpenAPI document
|
15
15
|
- Includes RSpec and Minitest helpers
|
16
16
|
|
17
|
+
### Learn more
|
18
|
+
|
19
|
+
- [Let there be docs! A documentation-first approach to Rails API development](https://evilmartians.com/events/let-there-be-docs-a-documentation-first-approach-to-rails-api-development) – Talk and slides from Friendly.rb 2023
|
20
|
+
|
17
21
|
<a href="https://evilmartians.com/?utm_source=skooma&utm_campaign=project_page">
|
18
22
|
<img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54">
|
19
23
|
</a>
|
@@ -44,6 +48,9 @@ RSpec.configure do |config|
|
|
44
48
|
# ...
|
45
49
|
path_to_openapi = Rails.root.join("docs", "openapi.yml")
|
46
50
|
config.include Skooma::RSpec[path_to_openapi], type: :request
|
51
|
+
|
52
|
+
# OR pass path_prefix option if your API is mounted under a prefix:
|
53
|
+
config.include Skooma::RSpec[path_to_openapi, path_prefix: "/internal/api"], type: :request
|
47
54
|
end
|
48
55
|
```
|
49
56
|
|
@@ -23,24 +23,24 @@ module Skooma
|
|
23
23
|
|
24
24
|
def request_object
|
25
25
|
# `rails` integration
|
26
|
-
return request if defined?(::ActionDispatch)
|
26
|
+
return @request if defined?(::ActionDispatch) && @request.is_a?(::ActionDispatch::Request)
|
27
27
|
# `rack-test` integration
|
28
|
-
return last_request if defined?(::Rack::Test)
|
28
|
+
return last_request if defined?(::Rack::Test) && defined?(:last_request)
|
29
29
|
|
30
30
|
raise "Request object not found"
|
31
31
|
end
|
32
32
|
|
33
33
|
def response_object
|
34
34
|
# `rails` integration
|
35
|
-
return response if defined?(::ActionDispatch)
|
35
|
+
return @response if defined?(::ActionDispatch) && @response.is_a?(::ActionDispatch::Response)
|
36
36
|
# `rack-test` integration
|
37
|
-
return last_response if defined?(::Rack::Test)
|
37
|
+
return last_response if defined?(::Rack::Test) && defined?(:last_response)
|
38
38
|
|
39
39
|
raise "Response object not found"
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
def initialize(helper_methods_module, openapi_path, base_uri: "https://skoomarb.dev/")
|
43
|
+
def initialize(helper_methods_module, openapi_path, base_uri: "https://skoomarb.dev/", path_prefix: "")
|
44
44
|
super()
|
45
45
|
|
46
46
|
registry = create_test_registry
|
@@ -50,6 +50,7 @@ module Skooma
|
|
50
50
|
JSONSkooma::Sources::Local.new(pathname.dirname.to_s)
|
51
51
|
)
|
52
52
|
schema = registry.schema(URI.parse("#{base_uri}#{pathname.basename}"), schema_class: Skooma::Objects::OpenAPI)
|
53
|
+
schema.path_prefix = path_prefix
|
53
54
|
|
54
55
|
include DefaultHelperMethods
|
55
56
|
include helper_methods_module
|
@@ -32,7 +32,7 @@ module Skooma
|
|
32
32
|
subresult.annotate({"path_attributes" => attributes})
|
33
33
|
path_schema.evaluate(instance, subresult)
|
34
34
|
|
35
|
-
if subresult.passed?
|
35
|
+
if subresult.passed? && subresult.children.any?
|
36
36
|
result.success
|
37
37
|
else
|
38
38
|
result.failure("Path #{instance["path"]} is invalid")
|
@@ -43,6 +43,7 @@ module Skooma
|
|
43
43
|
private
|
44
44
|
|
45
45
|
def find_route(instance_path)
|
46
|
+
instance_path = instance_path.delete_prefix(json.root.path_prefix)
|
46
47
|
return [instance_path, {}, json[instance_path]] if json.key?(instance_path)
|
47
48
|
|
48
49
|
@regexp_map.reduce(nil) do |result, (path, path_regex, subschema)|
|
@@ -31,6 +31,18 @@ module Skooma
|
|
31
31
|
super(Instance.new(instance), result)
|
32
32
|
end
|
33
33
|
|
34
|
+
def path_prefix=(value)
|
35
|
+
raise ArgumentError, "Path prefix must be a string" unless value.is_a?(String)
|
36
|
+
|
37
|
+
@path_prefix = value
|
38
|
+
@path_prefix = "/#{@path_prefix}" unless @path_prefix.start_with?("/")
|
39
|
+
@path_prefix = @path_prefix.delete_suffix("/") if @path_prefix.end_with?("/")
|
40
|
+
end
|
41
|
+
|
42
|
+
def path_prefix
|
43
|
+
@path_prefix || ""
|
44
|
+
end
|
45
|
+
|
34
46
|
def json_schema_dialect_uri
|
35
47
|
@json_schema_dialect_uri || parent_schema&.json_schema_dialect_uri
|
36
48
|
end
|
@@ -12,7 +12,7 @@ module Skooma
|
|
12
12
|
def initialize(parent_schema, value)
|
13
13
|
super
|
14
14
|
keys = json.filter_map { |v| v["in"] && [v["in"].value, v["name"].value] }
|
15
|
-
parent_params =
|
15
|
+
parent_params = parent_schema.parent["parameters"] || []
|
16
16
|
parent_params.reject! do |v|
|
17
17
|
v["in"] && keys.include?([v["in"].value, v["name"].value])
|
18
18
|
end
|
@@ -9,9 +9,11 @@ module Skooma
|
|
9
9
|
module ValueParser
|
10
10
|
class << self
|
11
11
|
def call(instance, result)
|
12
|
-
type = result.sibling(instance, "in")
|
13
|
-
key
|
14
|
-
|
12
|
+
type = result.sibling(instance, "in")&.annotation
|
13
|
+
raise Error, "Missing `in` key #{result.path}" unless type
|
14
|
+
|
15
|
+
key = result.sibling(instance, "name")&.annotation
|
16
|
+
raise Error, "Missing `name` key #{instance.path}: #{key}" unless key
|
15
17
|
|
16
18
|
case type
|
17
19
|
when "query"
|
@@ -30,7 +32,7 @@ module Skooma
|
|
30
32
|
when "cookie"
|
31
33
|
# instance["headers"]["Cookie"]
|
32
34
|
else
|
33
|
-
raise Error, "Unknown location: #{
|
35
|
+
raise Error, "Unknown location: #{type}"
|
34
36
|
end
|
35
37
|
end
|
36
38
|
|
@@ -8,6 +8,10 @@ module Skooma
|
|
8
8
|
def evaluate(instance, result)
|
9
9
|
return result.discard unless instance["method"] == key
|
10
10
|
|
11
|
+
if json["responses"].nil? && instance["response"]
|
12
|
+
return result.failure("Responses are not listed for #{key.upcase} #{instance["path"]}")
|
13
|
+
end
|
14
|
+
|
11
15
|
json.evaluate(instance, result)
|
12
16
|
return result.success if result.passed?
|
13
17
|
|
data/lib/skooma/output_format.rb
CHANGED
@@ -18,8 +18,9 @@ module Skooma
|
|
18
18
|
"keywordLocation" => node.path.to_s
|
19
19
|
}
|
20
20
|
|
21
|
-
child_data =
|
22
|
-
|
21
|
+
child_data = []
|
22
|
+
node.each_children do |child|
|
23
|
+
child_data << node_data(child) unless child.valid?
|
23
24
|
end
|
24
25
|
|
25
26
|
if first || child_data.length > 1
|
data/lib/skooma/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: skooma
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Svyatoslav Kryukov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: zeitwerk
|
@@ -30,15 +30,15 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 0.2.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
41
|
-
description:
|
40
|
+
version: 0.2.0
|
41
|
+
description: Apply a documentation-first approach to API development.
|
42
42
|
email:
|
43
43
|
- me@skryukov.dev
|
44
44
|
executables: []
|
@@ -166,5 +166,5 @@ requirements: []
|
|
166
166
|
rubygems_version: 3.3.7
|
167
167
|
signing_key:
|
168
168
|
specification_version: 4
|
169
|
-
summary:
|
169
|
+
summary: Validate API implementations against OpenAPI documents.
|
170
170
|
test_files: []
|