Class: JSONRPC_Rails::Middleware::Validator

Inherits:
Object
  • Object
show all
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` 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

Instance Method Summary collapse

Constructor Details

#initialize(app, paths = nil) ⇒ Validator

Returns a new instance of Validator.

Parameters:

  • app (#call)
  • paths (Array<String, Regexp, Proc>) (defaults to: nil)

    paths to validate



23
24
25
26
# File 'lib/jsonrpc_rails/middleware/validator.rb', line 23

def initialize(app, paths = nil)
  @app   = app
  @paths = Array(paths || Rails.configuration.jsonrpc_rails.validated_paths)
end

Instance Method Details

#call(env) ⇒ Object

Rack entry point



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/jsonrpc_rails/middleware/validator.rb', line 29

def call(env)
  return @app.call(env) unless validate_path?(env["PATH_INFO"])
  return @app.call(env) unless env["REQUEST_METHOD"] == "POST" &&
                               env["CONTENT_TYPE"]&.start_with?(CONTENT_TYPE)

  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)

  raw_payload = parse_json(body)

  unless raw_payload.is_a?(Hash) || raw_payload.is_a?(Array)
    id = extract_id_from_raw_payload(raw_payload)
    return jsonrpc_error_response(:invalid_request, id: id)
  end

  validity, = if raw_payload.is_a?(Array)
                validate_batch(raw_payload)
  else
                validate_single(raw_payload)
  end
  return validity unless validity == :valid

  env[ENV_PAYLOAD_KEY] = convert_to_objects(raw_payload)

  @app.call(env)
end