openapi_first 1.0.0.beta3 → 1.0.0.beta4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 800354f7ac2847fb16987e6961589aaebb84c161f3b76ea652a00a4cf8762fbe
4
- data.tar.gz: f443b72fa8ce1103bfc5a7b30367ce96f84e0dc7ad137722424cab0ac0c13357
3
+ metadata.gz: c02c053192b6b39cb8f05acd35f7a257ee98b449c49f8ceeec4ac6e542f09e15
4
+ data.tar.gz: c36d3598b263ebd3d1a9bd23e6aa0b66256890f68e2f70fe245ca932d2f004f0
5
5
  SHA512:
6
- metadata.gz: e454ee38c95a21915869e5feae0f38f65e0aa9a0a5001b6b752043fa379836164af1bf7eac9bcff192822d66053dda00d6dfa787296cce82bccf346d218f4c6c
7
- data.tar.gz: 11a0a0ac1e1bbd350d1edfe1dcae4ccae15bcfe2f1863320f30f554c3ad16934b07891c578225d2d7d128c3cb7dafd4093407c1c153713567db4db3d9c99c938
6
+ metadata.gz: e70192d7c2cb58734b8ebb6ccf53b2f243a98e78adbea271a3b0df1468f400d60080ead1ea68c07dd33bd9985d67de02ec4e0200e3ca0d49272a893c97611ffb
7
+ data.tar.gz: c59e62cd24dd767330f7e9ce6ad96a9c13005a4498c39f3ccf10bc801b49b6bddccf3ac62f858ae3ecf56fa4c695b4ad010fea7292171f98b640dec968ea357d
@@ -1,24 +1,12 @@
1
- name: Ruby
2
-
3
- on:
4
- push:
5
- branches: [ master ]
6
- pull_request:
7
- branches: [ master ]
8
-
1
+ name: Test
2
+ on: [push, pull_request]
9
3
  jobs:
10
- build:
11
-
4
+ test:
12
5
  runs-on: ubuntu-latest
13
-
14
6
  steps:
15
- - uses: actions/checkout@v2
16
- - name: Set up Ruby 2.6
17
- uses: actions/setup-ruby@v1
7
+ - uses: actions/checkout@v3
8
+ - uses: ruby/setup-ruby@v1
18
9
  with:
19
- ruby-version: 2.6.x
20
- - name: Build and test with Rake
21
- run: |
22
- gem install bundler
23
- bundle install --jobs 4 --retry 3
24
- bundle exec rake
10
+ ruby-version: '3.1'
11
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
12
+ - run: bundle exec rake
data/.rubocop.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  AllCops:
2
- TargetRubyVersion: 3.0.5
2
+ TargetRubyVersion: 3.1.1
3
3
  NewCops: enable
4
4
  SuggestExtensions: false
5
5
  Style/Documentation:
data/CHANGELOG.md CHANGED
@@ -2,15 +2,28 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 1.0.0.beta4
6
+
7
+ - Update json_schemer to version 2.0
8
+ - Breaking: Requires Ruby 3.1 or later
9
+ - Added: Parameters are available at `env[OpenapiFirst::PATH_PARAMS]`, `env[OpenapiFirst::QUERY_PARAMS]`, `env[OpenapiFirst::HEADER_PARAMS]`, `env[OpenapiFirst::COOKIE_PARAMS]` in case you need to access them separately. Merged path and query parameters are still available at `env[OpenapiFirst::PARAMS]`
10
+ - Breaking / Added: ResponseValidation now validates response headers
11
+ - Breaking / Added: RequestValidation now validates cookie, path and header parameters
12
+ - Breaking: multipart File uploads are now read and then validated
13
+ - Breaking: Remove OpenapiFirst.env method
14
+ - Breaking: Request validation returns 400 instead of 415 if request body is required, but empty
15
+
5
16
  ## 1.0.0.beta3
6
17
 
7
18
  - Remove obsolete dependency: deep_merge
8
19
  - Remove obsolete dependency: hanami-utils
9
20
 
10
21
  ## 1.0.0.beta2
22
+
11
23
  - Fixed dependencies. Remove unused code.
12
24
 
13
25
  ## 1.0.0.beta1
26
+
14
27
  - Removed: `OpenapiFirst::Responder` and `OpenapiFirst::RackResponder`
15
28
  - Removed: `OpenapiFirst.app` and `OpenapiFirst.middleware`
16
29
  - Removed: `OpenapiFirst::Coverage`
data/Gemfile CHANGED
@@ -6,6 +6,9 @@ source 'https://rubygems.org'
6
6
  gemspec
7
7
 
8
8
  group :test, :development do
9
- gem 'pry'
9
+ gem 'bundler'
10
+ gem 'rack-test'
11
+ gem 'rake'
12
+ gem 'rspec'
10
13
  gem 'rubocop'
11
14
  end
data/Gemfile.lock CHANGED
@@ -1,22 +1,20 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- openapi_first (1.0.0.beta3)
4
+ openapi_first (1.0.0.beta4)
5
5
  hanami-router (~> 2.0.0)
6
6
  json_refs (~> 0.1, >= 0.1.7)
7
- json_schemer (~> 0.2.16)
7
+ json_schemer (~> 2.0.0)
8
8
  multi_json (~> 1.14)
9
- openapi_parameters (~> 0.2)
9
+ openapi_parameters (~> 0.2.2)
10
10
  rack (>= 2.2, < 4.0)
11
11
 
12
12
  GEM
13
13
  remote: https://rubygems.org/
14
14
  specs:
15
15
  ast (2.4.2)
16
- coderay (1.1.3)
16
+ base64 (0.1.1)
17
17
  diff-lcs (1.5.0)
18
- ecma-re-validator (0.4.0)
19
- regexp_parser (~> 2.2)
20
18
  hana (1.3.7)
21
19
  hanami-router (2.0.2)
22
20
  mustermann (~> 3.0)
@@ -24,77 +22,81 @@ GEM
24
22
  rack (~> 2.0)
25
23
  hansi (0.2.1)
26
24
  json (2.6.3)
27
- json_refs (0.1.7)
25
+ json_refs (0.1.8)
28
26
  hana
29
- json_schemer (0.2.24)
30
- ecma-re-validator (~> 0.3)
27
+ json_schemer (2.0.0)
31
28
  hana (~> 1.3)
32
29
  regexp_parser (~> 2.0)
33
- uri_template (~> 0.7)
34
- method_source (1.0.0)
30
+ simpleidn (~> 0.2)
31
+ language_server-protocol (3.17.0.3)
35
32
  multi_json (1.15.0)
36
33
  mustermann (3.0.0)
37
34
  ruby2_keywords (~> 0.0.1)
38
35
  mustermann-contrib (3.0.0)
39
36
  hansi (~> 0.2.0)
40
37
  mustermann (= 3.0.0)
41
- openapi_parameters (0.2.1)
38
+ openapi_parameters (0.2.2)
42
39
  rack (>= 2.2)
43
40
  zeitwerk (~> 2.6)
44
- parallel (1.22.1)
45
- parser (3.2.1.1)
41
+ parallel (1.23.0)
42
+ parser (3.2.2.3)
46
43
  ast (~> 2.4.1)
47
- pry (0.14.2)
48
- coderay (~> 1.1)
49
- method_source (~> 1.0)
50
- rack (2.2.6.4)
51
- rack-test (1.1.0)
52
- rack (>= 1.0, < 3)
44
+ racc
45
+ racc (1.7.1)
46
+ rack (2.2.8)
47
+ rack-test (2.1.0)
48
+ rack (>= 1.3)
53
49
  rainbow (3.1.1)
54
50
  rake (13.0.6)
55
- regexp_parser (2.7.0)
56
- rexml (3.2.5)
51
+ regexp_parser (2.8.1)
52
+ rexml (3.2.6)
57
53
  rspec (3.12.0)
58
54
  rspec-core (~> 3.12.0)
59
55
  rspec-expectations (~> 3.12.0)
60
56
  rspec-mocks (~> 3.12.0)
61
- rspec-core (3.12.1)
57
+ rspec-core (3.12.2)
62
58
  rspec-support (~> 3.12.0)
63
- rspec-expectations (3.12.2)
59
+ rspec-expectations (3.12.3)
64
60
  diff-lcs (>= 1.2.0, < 2.0)
65
61
  rspec-support (~> 3.12.0)
66
- rspec-mocks (3.12.5)
62
+ rspec-mocks (3.12.6)
67
63
  diff-lcs (>= 1.2.0, < 2.0)
68
64
  rspec-support (~> 3.12.0)
69
- rspec-support (3.12.0)
70
- rubocop (1.48.1)
65
+ rspec-support (3.12.1)
66
+ rubocop (1.56.3)
67
+ base64 (~> 0.1.1)
71
68
  json (~> 2.3)
69
+ language_server-protocol (>= 3.17.0)
72
70
  parallel (~> 1.10)
73
- parser (>= 3.2.0.0)
71
+ parser (>= 3.2.2.3)
74
72
  rainbow (>= 2.2.2, < 4.0)
75
73
  regexp_parser (>= 1.8, < 3.0)
76
74
  rexml (>= 3.2.5, < 4.0)
77
- rubocop-ast (>= 1.26.0, < 2.0)
75
+ rubocop-ast (>= 1.28.1, < 2.0)
78
76
  ruby-progressbar (~> 1.7)
79
77
  unicode-display_width (>= 2.4.0, < 3.0)
80
- rubocop-ast (1.28.0)
78
+ rubocop-ast (1.29.0)
81
79
  parser (>= 3.2.1.0)
82
80
  ruby-progressbar (1.13.0)
83
81
  ruby2_keywords (0.0.5)
82
+ simpleidn (0.2.1)
83
+ unf (~> 0.1.4)
84
+ unf (0.1.4)
85
+ unf_ext
86
+ unf_ext (0.0.8.2)
84
87
  unicode-display_width (2.4.2)
85
- uri_template (0.7.0)
86
- zeitwerk (2.6.7)
88
+ zeitwerk (2.6.11)
87
89
 
88
90
  PLATFORMS
89
91
  arm64-darwin-21
92
+ x86_64-linux
90
93
 
91
94
  DEPENDENCIES
92
- bundler (~> 2)
95
+ bundler
93
96
  openapi_first!
94
- pry
95
- rack-test (~> 1)
96
- rake (~> 13)
97
- rspec (~> 3)
97
+ rack-test
98
+ rake
99
+ rspec
98
100
  rubocop
99
101
 
100
102
  BUNDLED WITH
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Join the chat at https://gitter.im/openapi_first/community](https://badges.gitter.im/openapi_first/community.svg)](https://gitter.im/openapi_first/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4
4
 
5
- OpenapiFirst helps to implement HTTP APIs based on an [OpenAPI](https://www.openapis.org/) API description.
5
+ OpenapiFirst helps to implement HTTP APIs based on an [OpenAPI](https://www.openapis.org/) API description. It supports OpenAPI 3.0 and 3.1.
6
6
 
7
7
  It provides these Rack middlewares:
8
8
 
@@ -10,6 +10,8 @@ It provides these Rack middlewares:
10
10
  - [`OpenapiFirst::ResponseValidation`](#response-validation) Validates the response and raises an exception if the response body is invalid.
11
11
  - [`OpenapiFirst::Router`](#openapifirstrouter) – This internal middleware is added automatically when using request/response validation. It adds the OpenAPI operation for the current request to the Rack env.
12
12
 
13
+ Using Request and Response validation together ensures that your implementation follows exactly the API description. This enables you to use the API description as a single source of truth for your API, reason about details and use various tooling.
14
+
13
15
  ## Request Validation
14
16
 
15
17
  The `OpenapiFirst::RequestValidation` middleware returns a 400 status code with a body that describes the error if the request is not valid.
@@ -19,6 +21,7 @@ use OpenapiFirst::RequestValidation, spec: 'openapi.yaml'
19
21
  ```
20
22
 
21
23
  It adds these fields to the Rack env:
24
+
22
25
  - `env[OpenapiFirst::PARAMS]` – The parsed parameters (query, path) for the current request (string keyed)
23
26
  - `env[OpenapiFirst::REQUEST_BODY]` – The parsed request body (string keyed)
24
27
  - `env[OpenapiFirst::OPERATION]` (Added via Router) – The Operation object for the current request. This is an instance of `OpenapiFirst::Operation`.
@@ -27,8 +30,9 @@ It adds these fields to the Rack env:
27
30
 
28
31
  | Name | Possible values | Description | Default |
29
32
  | :------------- | --------------- | -------------------------------------------------------------------------------------------------- | ---------------------------------- |
30
- | `spec:` | | The path to the spec file or spec loaded via `OpenapiFirst.load`
33
+ | `spec:` | | The path to the spec file or spec loaded via `OpenapiFirst.load` |
31
34
  | `raise_error:` | `false`, `true` | If set to true the middleware raises `OpenapiFirst::RequestInvalidError` instead of returning 4xx. | `false` (don't raise an exception) |
35
+ | `error_response:`| `:default`, Your implementation of `ErrorResponse` | :default
32
36
 
33
37
  The error responses conform with [JSON:API](https://jsonapi.org).
34
38
 
@@ -50,6 +54,7 @@ content-type: "application/vnd.api+json"
50
54
  }
51
55
  ```
52
56
 
57
+
53
58
  ### Parameters
54
59
 
55
60
  The `RequestValidation` middleware adds `env[OpenapiFirst::PARAMS]` (or `env['openapi.params']` ) with the converted query and path parameters. This only includes the parameters that are defined in the API description. It supports every [`style` and `explode` value as described](https://spec.openapis.org/oas/latest.html#style-examples) in the OpenAPI 3.0 and 3.1 specs. So you can do things these:
@@ -72,9 +77,10 @@ This middleware adds the parsed request body to `env[OpenapiFirst::REQUEST_BODY]
72
77
 
73
78
  The middleware will return a status `415` if the requests content type does not match or `400` if the request body is invalid.
74
79
 
75
- ### Header, Cookie, Path parameter validation
80
+ ### Header, Cookie, Query and Path parameter validation
76
81
 
77
- tbd.
82
+ The `RequestValidation` middleware validates the request headers, cookies and path parameters as defined in you API description. It returns a `400` status code if the request is invalid. It adds the parsed merged _path_ and _query_ parameters to `env['openapi.params']`.
83
+ Separate parsed parameters are made available by location at `env['openapi.path_params']`, `env['openapi.query']`, `env['openapi.headers']`, `env['openapi.cookies']` as well if you need to access them separately.
78
84
 
79
85
  ### readOnly / writeOnly properties
80
86
 
@@ -92,9 +98,9 @@ use OpenapiFirst::ResponseValidation, spec: 'openapi.yaml' if ENV['RACK_ENV'] ==
92
98
 
93
99
  ### Options
94
100
 
95
- | Name | Possible values | Description | Default |
96
- | :------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- |
97
- | `spec:` | | The path to the spec file or spec loaded via `OpenapiFirst.load`
101
+ | Name | Possible values | Description | Default |
102
+ | :------ | --------------- | ---------------------------------------------------------------- | ------- |
103
+ | `spec:` | | The path to the spec file or spec loaded via `OpenapiFirst.load` |
98
104
 
99
105
  ## OpenapiFirst::Router
100
106
 
@@ -104,13 +110,13 @@ This middleware is used automatically, but you can add it to the top of your mid
104
110
  use OpenapiFirst::Router, spec: './openapi/openapi.yaml'
105
111
  ```
106
112
 
107
- This middleware adds `env[OpenapiFirst::OPERATION]` which holds an Operation object that responds to `#operation_id`, `#path` (and `#[string]` to access raw fields).
113
+ This middleware adds `env['openapi.operation']` which holds an instance of `OpenapiFirst::Operation` that responds to `#operation_id`, `#path` (and `#[]` to access raw fields).
108
114
 
109
115
  ### Options and defaults
110
116
 
111
117
  | Name | Possible values | Description | Default |
112
118
  | :------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- |
113
- | `spec:` | | The path to the spec file or spec loaded via `OpenapiFirst.load` | |
119
+ | `spec:` | | The path to the spec file or spec loaded via `OpenapiFirst.load` | |
114
120
  | `raise_error:` | `false`, `true` | If set to true the middleware raises `OpenapiFirst::NotFoundError` when a path or method was not found in the API description. This is useful during testing to spot an incomplete API description. | `false` (don't raise an exception) |
115
121
  | `not_found:` | `:continue`, `:halt` | If set to `:continue` the middleware will not return 404 (405, 415), but just pass handling the request to the next middleware or application in the Rack stack. If combined with `raise_error: true` `raise_error` gets preference and an exception is raised. | `:halt` (return 4xx response) |
116
122
 
@@ -160,9 +166,9 @@ run OpenapiFirst.app(spec, namespace: Pets)
160
166
 
161
167
  Run `bin/setup` to install dependencies.
162
168
 
163
- Run `bundle exec rspec` to run the tests.
169
+ See `bundle exec rake` to run the linter and the tests.
164
170
 
165
- See `bundle exec rake -T` for rubygems related tasks.
171
+ Run `bundle exec rspec` to run the tests only.
166
172
 
167
173
  ## Benchmarks
168
174
 
@@ -4,15 +4,15 @@ PATH
4
4
  openapi_first (1.0.0.beta3)
5
5
  hanami-router (~> 2.0.0)
6
6
  json_refs (~> 0.1, >= 0.1.7)
7
- json_schemer (~> 0.2.16)
7
+ json_schemer (~> 2.0.0)
8
8
  multi_json (~> 1.14)
9
- openapi_parameters (~> 0.2)
9
+ openapi_parameters (~> 0.2.2)
10
10
  rack (>= 2.2, < 4.0)
11
11
 
12
12
  GEM
13
13
  remote: https://rubygems.org/
14
14
  specs:
15
- activesupport (7.0.4.3)
15
+ activesupport (7.0.8)
16
16
  concurrent-ruby (~> 1.0, >= 1.0.2)
17
17
  i18n (>= 1.6, < 2)
18
18
  minitest (>= 5.1)
@@ -40,14 +40,12 @@ GEM
40
40
  dry-inflector (~> 1.0)
41
41
  dry-logic (~> 1.4)
42
42
  zeitwerk (~> 2.6)
43
- ecma-re-validator (0.4.0)
44
- regexp_parser (~> 2.2)
45
- grape (1.7.0)
43
+ grape (1.7.1)
46
44
  activesupport
47
45
  builder
48
46
  dry-types (>= 1.1)
49
47
  mustermann-grape (~> 1.0.0)
50
- rack (>= 1.3.0)
48
+ rack (>= 1.3.0, < 3)
51
49
  rack-accept
52
50
  hana (1.3.7)
53
51
  hanami-api (0.3.0)
@@ -57,18 +55,17 @@ GEM
57
55
  mustermann-contrib (~> 3.0)
58
56
  rack (~> 2.0)
59
57
  hansi (0.2.1)
60
- i18n (1.12.0)
58
+ i18n (1.14.1)
61
59
  concurrent-ruby (~> 1.0)
62
- json_refs (0.1.7)
60
+ json_refs (0.1.8)
63
61
  hana
64
62
  json_schema (0.21.0)
65
- json_schemer (0.2.24)
66
- ecma-re-validator (~> 0.3)
63
+ json_schemer (2.0.0)
67
64
  hana (~> 1.3)
68
65
  regexp_parser (~> 2.0)
69
- uri_template (~> 0.7)
66
+ simpleidn (~> 0.2)
70
67
  memory_profiler (1.0.1)
71
- minitest (5.18.0)
68
+ minitest (5.20.0)
72
69
  multi_json (1.15.0)
73
70
  mustermann (3.0.0)
74
71
  ruby2_keywords (~> 0.0.1)
@@ -78,22 +75,24 @@ GEM
78
75
  mustermann-grape (1.0.2)
79
76
  mustermann (>= 1.0.0)
80
77
  nio4r (2.5.9)
81
- openapi_parameters (0.2.1)
78
+ openapi_parameters (0.2.2)
82
79
  rack (>= 2.2)
83
80
  zeitwerk (~> 2.6)
84
81
  openapi_parser (1.0.0)
85
- puma (6.2.2)
82
+ puma (6.3.1)
86
83
  nio4r (~> 2.0)
87
- rack (2.2.6.4)
84
+ rack (2.2.8)
88
85
  rack-accept (0.4.5)
89
86
  rack (>= 0.4)
90
87
  rack-protection (3.0.6)
91
88
  rack
92
- regexp_parser (2.8.0)
93
- roda (3.67.0)
89
+ regexp_parser (2.8.1)
90
+ roda (3.68.0)
94
91
  rack
95
92
  ruby2_keywords (0.0.5)
96
93
  seg (1.2.0)
94
+ simpleidn (0.2.1)
95
+ unf (~> 0.1.4)
97
96
  sinatra (3.0.6)
98
97
  mustermann (~> 3.0)
99
98
  rack (~> 2.2, >= 2.2.4)
@@ -105,8 +104,10 @@ GEM
105
104
  tilt (2.1.0)
106
105
  tzinfo (2.0.6)
107
106
  concurrent-ruby (~> 1.0)
108
- uri_template (0.7.0)
109
- zeitwerk (2.6.7)
107
+ unf (0.1.4)
108
+ unf_ext
109
+ unf_ext (0.0.8.2)
110
+ zeitwerk (2.6.11)
110
111
 
111
112
  PLATFORMS
112
113
  arm64-darwin-21
@@ -24,9 +24,9 @@ app = Rack::Builder.new do
24
24
 
25
25
  not_found = ->(_env) { [404, {}, []] }
26
26
 
27
- run lambda do |env|
27
+ run(lambda do |env|
28
28
  handlers.fetch(env[OpenapiFirst::OPERATION]&.operation_id, not_found).call(env)
29
- end
29
+ end)
30
30
  end
31
31
 
32
32
  run app
@@ -23,7 +23,7 @@ module OpenapiFirst
23
23
  errors = [err]
24
24
 
25
25
  Rack::Response.new(
26
- MultiJson.dump(errors: errors),
26
+ MultiJson.dump(errors:),
27
27
  400,
28
28
  Rack::CONTENT_TYPE => 'application/vnd.api+json'
29
29
  ).finish
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenapiFirst
4
+ class Config
5
+ def initialize(error_response: :default)
6
+ @error_response = error_response
7
+ end
8
+
9
+ attr_reader :error_response
10
+
11
+ def self.default_options
12
+ @default_options ||= new
13
+ end
14
+
15
+ def self.default_options=(options)
16
+ @default_options = new(**options)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenapiFirst
4
+ class DefaultErrorResponse < ErrorResponse
5
+ OpenapiFirst::Plugins.register_error_response(:default, self)
6
+
7
+ def body
8
+ MultiJson.dump({ errors: serialized_errors })
9
+ end
10
+
11
+ def serialized_errors
12
+ return default_errors unless validation_output
13
+
14
+ key = pointer_key
15
+ [
16
+ {
17
+ source: { key => pointer(validation_output['instanceLocation']) },
18
+ title: validation_output['error']
19
+ }
20
+ ]
21
+ end
22
+
23
+ def default_errors
24
+ [{
25
+ status: status.to_s,
26
+ title:
27
+ }]
28
+ end
29
+
30
+ def pointer_key
31
+ case location
32
+ when :request_body
33
+ :pointer
34
+ when :query, :path
35
+ :parameter
36
+ else
37
+ location
38
+ end
39
+ end
40
+
41
+ def pointer(data_pointer)
42
+ return data_pointer if location == :request_body
43
+
44
+ data_pointer.delete_prefix('/')
45
+ end
46
+ end
47
+ end
@@ -3,6 +3,7 @@
3
3
  require_relative 'operation'
4
4
 
5
5
  module OpenapiFirst
6
+ # Represents an OpenAPI API Description document
6
7
  class Definition
7
8
  attr_reader :filepath, :operations
8
9
 
@@ -11,9 +12,15 @@ module OpenapiFirst
11
12
  methods = %w[get head post put patch delete trace options]
12
13
  @operations = resolved['paths'].flat_map do |path, path_item|
13
14
  path_item.slice(*methods).map do |request_method, _operation_object|
14
- Operation.new(path, request_method, path_item)
15
+ Operation.new(path, request_method, path_item, openapi_version: detect_version(resolved))
15
16
  end
16
17
  end
17
18
  end
19
+
20
+ private
21
+
22
+ def detect_version(resolved)
23
+ (resolved['openapi'] || resolved['swagger'])[0..2]
24
+ end
18
25
  end
19
26
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenapiFirst
4
+ # This is the base class for error responses
5
+ class ErrorResponse
6
+ ## @param status [Integer] The HTTP status code.
7
+ ## @param title [String] The title of the error. Usually the name of the HTTP status code.
8
+ ## @param location [Symbol] The location of the error (:request_body, :query, :header, :cookie, :path).
9
+ ## @param validation_result [ValidationResult]
10
+ def initialize(status:, location:, title:, validation_result:)
11
+ @status = status
12
+ @title = title
13
+ @location = location
14
+ @validation_output = validation_result&.output
15
+ @schema = validation_result&.schema
16
+ @data = validation_result&.data
17
+ end
18
+
19
+ attr_reader :status, :location, :title, :schema, :data, :validation_output
20
+
21
+ def render
22
+ Rack::Response.new(body, status, Rack::CONTENT_TYPE => content_type).finish
23
+ end
24
+
25
+ def content_type = 'application/json'
26
+
27
+ def body
28
+ raise NotImplementedError
29
+ end
30
+ end
31
+ end
@@ -5,15 +5,6 @@ module OpenapiFirst
5
5
 
6
6
  class NotFoundError < Error; end
7
7
 
8
- class HandlerNotFoundError < Error; end
9
-
10
- class NotImplementedError < Error
11
- def initialize(message)
12
- warn 'NotImplementedError is deprecated. Handle HandlerNotFoundError instead'
13
- super
14
- end
15
- end
16
-
17
8
  class ResponseInvalid < Error; end
18
9
 
19
10
  class ResponseCodeNotFoundError < ResponseInvalid; end
@@ -22,37 +13,9 @@ module OpenapiFirst
22
13
 
23
14
  class ResponseBodyInvalidError < ResponseInvalid; end
24
15
 
16
+ class ResponseHeaderInvalidError < ResponseInvalid; end
17
+
25
18
  class BodyParsingError < Error; end
26
19
 
27
- class RequestInvalidError < Error
28
- def initialize(serialized_errors)
29
- message = error_message(serialized_errors)
30
- super message
31
- end
32
-
33
- private
34
-
35
- def error_message(errors)
36
- errors.map do |error|
37
- [human_source(error), human_error(error)].compact.join(' ')
38
- end.join(', ')
39
- end
40
-
41
- def human_source(error)
42
- return unless error[:source]
43
-
44
- source_key = error[:source].keys.first
45
- source = {
46
- pointer: 'Request body invalid:',
47
- parameter: 'Query parameter invalid:'
48
- }.fetch(source_key, source_key)
49
- name = error[:source].values.first
50
- source += " #{name}" unless name.nil? || name.empty?
51
- source
52
- end
53
-
54
- def human_error(error)
55
- error[:title]
56
- end
57
- end
20
+ class RequestInvalidError < Error; end
58
21
  end