Class: OpenapiFirst::RequestValidation
- Inherits:
-
Object
- Object
- OpenapiFirst::RequestValidation
- Defined in:
- lib/openapi_first/request_validation.rb
Instance Method Summary collapse
- #allowed_params(json_schema, params) ⇒ Object
-
#call(env) ⇒ Object
rubocop:disable Metrics/AbcSize, Metrics/MethodLength.
- #default_error(status, title = ) ⇒ Object
- #error_response(status, errors = [default_error(status)]) ⇒ Object
- #halt(response) ⇒ Object
-
#initialize(app, allow_unknown_query_parameters: false) ⇒ RequestValidation
constructor
A new instance of RequestValidation.
- #parse_and_validate_request_body!(env, content_type, body, operation) ⇒ Object
- #request_body_schema(content_type, endpoint) ⇒ Object
- #serialize_query_parameter_errors(validation_errors) ⇒ Object
- #serialize_request_body_errors(validation_errors) ⇒ Object
- #validate_json_schema(schema, object) ⇒ Object
- #validate_query_parameters!(env, operation, params) ⇒ Object
- #validate_request_body_presence!(body, operation) ⇒ Object
- #validate_request_content_type!(content_type, operation) ⇒ Object
Constructor Details
#initialize(app, allow_unknown_query_parameters: false) ⇒ RequestValidation
Returns a new instance of RequestValidation.
11 12 13 14 |
# File 'lib/openapi_first/request_validation.rb', line 11 def initialize(app, allow_unknown_query_parameters: false) @app = app @allow_unknown_query_parameters = allow_unknown_query_parameters end |
Instance Method Details
#allowed_params(json_schema, params) ⇒ Object
115 116 117 118 119 120 121 122 123 |
# File 'lib/openapi_first/request_validation.rb', line 115 def allowed_params(json_schema, params) json_schema['properties'] .keys .each_with_object({}) do |parameter_name, filtered| next unless params.key?(parameter_name) filtered[parameter_name] = params[parameter_name] end end |
#call(env) ⇒ Object
rubocop:disable Metrics/AbcSize, Metrics/MethodLength
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/openapi_first/request_validation.rb', line 16 def call(env) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength operation = env[OpenapiFirst::OPERATION] return @app.call(env) unless operation req = Rack::Request.new(env) catch(:halt) do validate_query_parameters!(env, operation, req.params) content_type = req.content_type return @app.call(env) unless operation.request_body validate_request_content_type!(content_type, operation) body = req.body.read req.body.rewind parse_and_validate_request_body!(env, content_type, body, operation) @app.call(env) end end |
#default_error(status, title = ) ⇒ Object
69 70 71 72 73 74 |
# File 'lib/openapi_first/request_validation.rb', line 69 def default_error(status, title = Rack::Utils::HTTP_STATUS_CODES[status]) { status: status.to_s, title: title } end |
#error_response(status, errors = [default_error(status)]) ⇒ Object
76 77 78 79 80 81 82 |
# File 'lib/openapi_first/request_validation.rb', line 76 def error_response(status, errors = [default_error(status)]) Rack::Response.new( MultiJson.dump(errors: errors), status, Rack::CONTENT_TYPE => 'application/vnd.api+json' ).finish end |
#halt(response) ⇒ Object
34 35 36 |
# File 'lib/openapi_first/request_validation.rb', line 34 def halt(response) throw :halt, response end |
#parse_and_validate_request_body!(env, content_type, body, operation) ⇒ Object
38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/openapi_first/request_validation.rb', line 38 def parse_and_validate_request_body!(env, content_type, body, operation) validate_request_body_presence!(body, operation) return if body.empty? schema = request_body_schema(content_type, operation) return unless schema parsed_request_body = MultiJson.load(body) errors = validate_json_schema(schema, parsed_request_body) if errors.any? halt(error_response(400, serialize_request_body_errors(errors))) end env[OpenapiFirst::REQUEST_BODY] = parsed_request_body end |
#request_body_schema(content_type, endpoint) ⇒ Object
84 85 86 87 88 |
# File 'lib/openapi_first/request_validation.rb', line 84 def request_body_schema(content_type, endpoint) return unless endpoint endpoint.request_body.content[content_type]&.fetch('schema') end |
#serialize_query_parameter_errors(validation_errors) ⇒ Object
125 126 127 128 129 130 131 132 133 |
# File 'lib/openapi_first/request_validation.rb', line 125 def serialize_query_parameter_errors(validation_errors) validation_errors.map do |error| { source: { parameter: File.basename(error['data_pointer']) } }.update(ValidationFormat.error_details(error)) end end |
#serialize_request_body_errors(validation_errors) ⇒ Object
90 91 92 93 94 95 96 97 98 |
# File 'lib/openapi_first/request_validation.rb', line 90 def serialize_request_body_errors(validation_errors) validation_errors.map do |error| { source: { pointer: error['data_pointer'] } }.update(ValidationFormat.error_details(error)) end end |
#validate_json_schema(schema, object) ⇒ Object
65 66 67 |
# File 'lib/openapi_first/request_validation.rb', line 65 def validate_json_schema(schema, object) JSONSchemer.schema(schema).validate(object) end |
#validate_query_parameters!(env, operation, params) ⇒ Object
100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/openapi_first/request_validation.rb', line 100 def validate_query_parameters!(env, operation, params) json_schema = QueryParameters.new( operation: operation, allow_unknown_parameters: @allow_unknown_query_parameters ).to_json_schema return unless json_schema errors = JSONSchemer.schema(json_schema).validate(params) if errors.any? halt error_response(400, serialize_query_parameter_errors(errors)) end env[QUERY_PARAMS] = allowed_params(json_schema, params) end |
#validate_request_body_presence!(body, operation) ⇒ Object
59 60 61 62 63 |
# File 'lib/openapi_first/request_validation.rb', line 59 def validate_request_body_presence!(body, operation) return unless operation.request_body.required && body.empty? halt(error_response(415, 'Request body is required')) end |
#validate_request_content_type!(content_type, operation) ⇒ Object
53 54 55 56 57 |
# File 'lib/openapi_first/request_validation.rb', line 53 def validate_request_content_type!(content_type, operation) return if operation.request_body.content[content_type] halt(error_response(415)) end |