Class: JSONRPC_Rails::Middleware::Validator
- Inherits:
-
Object
- Object
- JSONRPC_Rails::Middleware::Validator
- Defined in:
- lib/jsonrpc_rails/middleware/validator.rb
Overview
Rack middleware that validates incoming JSON-RPC 2.0 payloads
and injects fully-typed Ruby objects (Request / Notification /
Response) into env[:jsonrpc] for easy downstream use.
Validation always runs on the raw Hash/Array first; objects are only instantiated after the structure has been deemed valid, so malformed IDs or empty batches no longer raise before we can return a proper -32600 “Invalid Request”.
Constant Summary collapse
- CONTENT_TYPE =
"application/json"- ENV_PAYLOAD_KEY =
:jsonrpc- BATCH_POLICIES =
%i[allow reject].freeze
- RESERVED_MEMBERS =
%w[jsonrpc method params id result error].freeze
Instance Method Summary collapse
-
#call(env) ⇒ Object
Rack entry point.
-
#initialize(app, paths = nil, payload_validator: nil, batch_policy: :allow, require_json_content_type: false) ⇒ Validator
constructor
A new instance of Validator.
Constructor Details
#initialize(app, paths = nil, payload_validator: nil, batch_policy: :allow, require_json_content_type: false) ⇒ Validator
Returns a new instance of Validator.
30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/jsonrpc_rails/middleware/validator.rb', line 30 def initialize(app, paths = nil, payload_validator: nil, batch_policy: :allow, require_json_content_type: false) unless BATCH_POLICIES.include?(batch_policy) raise ArgumentError, "batch_policy must be one of: #{BATCH_POLICIES.join(", ")}" end @app = app @paths = Array(paths || Rails.configuration.jsonrpc_rails.validated_paths) @payload_validator = payload_validator @batch_policy = batch_policy @require_json_content_type = require_json_content_type end |
Instance Method Details
#call(env) ⇒ Object
Rack entry point
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/jsonrpc_rails/middleware/validator.rb', line 44 def call(env) return @app.call(env) unless validate_path?(env["PATH_INFO"]) return @app.call(env) unless env["REQUEST_METHOD"] == "POST" unless json_content_type?(env["CONTENT_TYPE"]) return @app.call(env) unless @require_json_content_type return jsonrpc_error_response( :server_error, status: 415, message: "Unsupported Media Type: Content-Type must be application/json" ) end body = env["rack.input"].read # Replace consumed input with fresh StringIO for downstream middleware # This is Rack 3.0+ compatible and works with all input stream types env["rack.input"] = StringIO.new(body) begin raw_payload = ActiveSupport::JSON.decode(body) rescue ActiveSupport::JSON.parse_error return jsonrpc_error_response(:parse_error) end unless raw_payload.is_a?(Hash) || raw_payload.is_a?(Array) return jsonrpc_error_response(:invalid_request) end return invalid_request_response(raw_payload) unless valid_batch_policy?(raw_payload) return invalid_request_response(raw_payload) unless valid_payload_structure?(raw_payload) return invalid_request_response(raw_payload) unless valid_protocol_payload?(raw_payload) begin env[ENV_PAYLOAD_KEY] = convert_to_objects(raw_payload) rescue JSON_RPC::JsonRpcError, ArgumentError, TypeError return invalid_request_response(raw_payload) end @app.call(env) end |