Skip to content

Commit 41a64bd

Browse files
committed
feat: add request and response schema validator conditionaly
1 parent b42c679 commit 41a64bd

File tree

7 files changed

+88
-10
lines changed

7 files changed

+88
-10
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@
3030

3131
# Ignore master key for decrypting credentials and more.
3232
/config/master.key
33+
.byebug_history

Gemfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,13 @@ gem "thruster", require: false
3535
# Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin Ajax possible
3636
# gem "rack-cors"
3737
gem "committee"
38+
gem "openapi_first"
3839
gem "scalar_ruby", "~> 1.1"
3940

4041
group :development, :test do
4142
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
4243
gem "debug", platforms: %i[ mri windows ], require: "debug/prelude"
43-
44+
gem "byebug"
4445
# Static analysis for security vulnerabilities [https://brakemanscanner.org/]
4546
gem "brakeman", require: false
4647

Gemfile.lock

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ GEM
8383
brakeman (7.0.0)
8484
racc
8585
builder (3.3.0)
86+
byebug (11.1.3)
8687
committee (5.5.1)
8788
json_schema (~> 0.14, >= 0.14.3)
8889
openapi_parser (~> 2.0)
@@ -105,6 +106,7 @@ GEM
105106
raabro (~> 1.4)
106107
globalid (1.2.1)
107108
activesupport (>= 6.1)
109+
hana (1.3.7)
108110
i18n (1.14.7)
109111
concurrent-ruby (~> 1.0)
110112
io-console (0.8.0)
@@ -114,6 +116,11 @@ GEM
114116
reline (>= 0.4.2)
115117
json (2.10.2)
116118
json_schema (0.21.0)
119+
json_schemer (2.4.0)
120+
bigdecimal
121+
hana (~> 1.3)
122+
regexp_parser (~> 2.0)
123+
simpleidn (~> 0.2)
117124
kamal (2.5.3)
118125
activesupport (>= 7.0)
119126
base64 (~> 0.2)
@@ -161,6 +168,13 @@ GEM
161168
racc (~> 1.4)
162169
nokogiri (1.18.3-x86_64-linux-gnu)
163170
racc (~> 1.4)
171+
openapi_first (2.4.0)
172+
hana (~> 1.3)
173+
json_schemer (>= 2.1, < 3.0)
174+
openapi_parameters (>= 0.3.3, < 2.0)
175+
rack (>= 2.2, < 4.0)
176+
openapi_parameters (0.4.0)
177+
rack (>= 2.2)
164178
openapi_parser (2.2.4)
165179
ostruct (0.6.1)
166180
parallel (1.26.3)
@@ -251,6 +265,7 @@ GEM
251265
ruby-progressbar (1.13.0)
252266
scalar_ruby (1.1.0)
253267
securerandom (0.4.1)
268+
simpleidn (0.2.3)
254269
solid_cable (3.0.7)
255270
actioncable (>= 7.2)
256271
activejob (>= 7.2)
@@ -304,9 +319,11 @@ PLATFORMS
304319
DEPENDENCIES
305320
bootsnap
306321
brakeman
322+
byebug
307323
committee
308324
debug
309325
kamal
326+
openapi_first
310327
puma (>= 5.0)
311328
rails (~> 8.0.2)
312329
rubocop-rails-omakase

config/application.rb

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
# Require the gems listed in Gemfile, including any gems
66
# you've limited to :test, :development, or :production.
77
Bundler.require(*Rails.groups)
8-
8+
require_relative "../lib/open_api_schema/request_validator_middleware"
9+
require_relative "../lib/open_api_schema/response_validator_middleware"
910
module PocDocsFirst
1011
class Application < Rails::Application
1112
# Initialize configuration defaults for originally generated Rails version.
@@ -29,12 +30,7 @@ class Application < Rails::Application
2930
# Skip views, helpers and assets when generating a new resource.
3031
config.api_only = true
3132

32-
config.middleware.use Committee::Middleware::RequestValidation,
33-
schema_path: "docs/openapi.json",
34-
coerce_date_times: true,
35-
params_key: "action_dispatch.request.request_parameters",
36-
query_hash_key: "action_dispatch.request.query_parameters",
37-
strict_reference_validation: true
38-
config.middleware.use Committee::Middleware::ResponseValidation, schema_path: "docs/openapi.json", strict_reference_validation: true
33+
config.middleware.use ::OpenApiSchema::RequestValidatorMiddleware
34+
config.middleware.use ::OpenApiSchema::ResponseValidatorMiddleware
3935
end
4036
end

docs/openapi.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
"schema": {
6868
"type": "object",
6969
"properties": {
70-
"id": { "type": "number" },
70+
"id": { "type": "string" },
7171
"message": { "type": "string" },
7272
"created_at": { "type": "string", "format": "date-time" },
7373
"updated_at": { "type": "string", "format": "date-time" }
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
module OpenApiSchema
3+
class RequestValidatorMiddleware
4+
def initialize(app)
5+
@app = app
6+
@request_validator = Committee::Middleware::RequestValidation.new(app, schema_path: "docs/openapi.json", strict_reference_validation: true, coerce_date_times: true, params_key: "action_dispatch.request.request_parameters", query_hash_key: "action_dispatch.request.query_parameters")
7+
end
8+
9+
# Handles the middleware call to validate the schema if the "Validate-Schema" header is present.
10+
# If the header is set to "1", it validates the request and response schema.
11+
# Otherwise, it continues the request-response cycle as usual.
12+
#
13+
# @param env [Hash] The Rack environment hash.
14+
# @return [Array] The status, headers, and body of the response.
15+
def call(env)
16+
status, headers, response = @app.call(env)
17+
18+
19+
if condition_for_request_validation?(env)
20+
status, headers, response = @request_validator.call(env)
21+
end
22+
23+
[ status, headers, response ]
24+
end
25+
26+
private
27+
28+
def condition_for_request_validation?(env)
29+
env.key?("HTTP_VALIDATE_SCHEMA")
30+
end
31+
end
32+
end
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
module OpenApiSchema
3+
class ResponseValidatorMiddleware
4+
def initialize(app)
5+
@app = app
6+
@response_validator = Committee::Middleware::ResponseValidation.new(app, schema_path: "docs/openapi.json", strict_reference_validation: true)
7+
end
8+
9+
# Handles the middleware call to validate the schema if the "Validate-Schema" header is present.
10+
# If the header is set to "1", it validates the request and response schema.
11+
# Otherwise, it continues the request-response cycle as usual.
12+
#
13+
# @param env [Hash] The Rack environment hash.
14+
# @return [Array] The status, headers, and body of the response.
15+
def call(env)
16+
status, headers, response = @app.call(env)
17+
18+
if condition_for_response_validation?(env)
19+
status, headers, response = @response_validator.call(env)
20+
end
21+
22+
[ status, headers, response ]
23+
end
24+
25+
private
26+
27+
def condition_for_response_validation?(env)
28+
env.key?("HTTP_VALIDATE_SCHEMA")
29+
end
30+
end
31+
end

0 commit comments

Comments
 (0)