Class: JSONRPC::Middleware

Inherits:
Object
  • Object
show all
Defined in:
lib/jsonrpc/middleware.rb,
sig/jsonrpc/middleware.rbs

Overview

Rack middleware for handling JSON-RPC 2.0 requests

This middleware intercepts HTTP POST requests at a specified path and processes them as JSON-RPC 2.0 messages. It handles parsing, validation, and error responses according to the JSON-RPC 2.0 specification.

Examples:

Basic usage

use JSONRPC::Middleware

Custom path

use JSONRPC::Middleware, path: '/api/v1/rpc'

Constant Summary collapse

DEFAULT_PATH =

Default path for JSON-RPC requests

Returns:

  • (String)

    The default path '/'

'/'

Instance Method Summary collapse

Constructor Details

#initialize(app, options = {}) ⇒ Middleware

Initializes the JSON-RPC middleware

Examples:

Basic initialization

middleware = JSONRPC::Middleware.new(app)

With custom path

middleware = JSONRPC::Middleware.new(app, path: '/api/jsonrpc')

Parameters:

  • app (#call)

    The Rack application to wrap

  • options (Hash) (defaults to: {})

    Configuration options

Options Hash (options):

  • :path (String) — default: '/'

    The path to handle JSON-RPC requests on

  • :rescue_internal_errors (Boolean) — default: nil

    Override config rescue_internal_errors

  • :log_internal_errors (Boolean) — default: true

    Override config log_internal_errors

  • :logger (Logger) — default: nil

    Override config logger



46
47
48
49
50
51
52
53
54
55
# File 'lib/jsonrpc/middleware.rb', line 46

def initialize(app, options = {})
  @app = app
  @path = options.fetch(:path, DEFAULT_PATH)
  @config = JSONRPC.configuration
  @logger = options.fetch(:logger, @config.logger)
  @parser = Parser.new
  @validator = Validator.new(logger: @logger)
  @log_internal_errors = options.fetch(:log_internal_errors, @config.log_internal_errors)
  @rescue_internal_errors = options.fetch(:rescue_internal_errors, @config.rescue_internal_errors)
end

Instance Method Details

#call(env) ⇒ Array

Rack application call method

Examples:

Processing a request

status, headers, body = middleware.call(env)

Parameters:

  • env (Hash)

    The Rack environment

Returns:

  • (Array)

    Rack response tuple [status, headers, body]



68
69
70
71
72
73
74
75
76
# File 'lib/jsonrpc/middleware.rb', line 68

def call(env)
  @req = Rack::Request.new(env)

  if jsonrpc_request?
    handle_jsonrpc_request
  else
    @app.call(env)
  end
end

#handle_jsonrpc_requestArray

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Handles a JSON-RPC request through the complete processing pipeline

Returns:

  • (Array)

    Rack response tuple

Raises:

  • (StandardError)

    Catches all errors and converts to Internal Error response



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/jsonrpc/middleware.rb', line 98

def handle_jsonrpc_request
  parsed_request = parse_request
  return parsed_request if parsed_request.is_a?(Array) # Early return for parse errors

  if @config.validate_procedure_signatures
    validation_result = validate_request(parsed_request)
    return validation_result if validation_result.is_a?(Array) # Early return for validation errors
  end

  # Set parsed request in environment and call app
  store_request_in_env(parsed_request)
  @app.call(@req.env)
rescue StandardError => e
  log_internal_error(e) if @log_internal_errors

  data = {}
  data = { class: e.class.name, message: e.message, backtrace: e.backtrace } if @config.render_internal_errors
  error = InternalError.new(request_id: parsed_request.is_a?(Request) ? parsed_request.id : nil, data:)
  @req.env['jsonrpc.error'] = error

  raise e unless @rescue_internal_errors

  json_response(200, error.to_response)
end

#jsonrpc_request?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Determines if the current request should be handled as JSON-RPC

Returns:

  • (Boolean)

    true if the request matches the configured path and is a POST request



86
87
88
# File 'lib/jsonrpc/middleware.rb', line 86

def jsonrpc_request?
  @req.path == @path && @req.post?
end

#log_internal_error(error) ⇒ void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Logs internal errors with full backtrace using the configured logger

Examples:

Log an internal error

log_internal_error(StandardError.new("Something went wrong"))

Parameters:

  • error (Exception)

    The error to log



393
394
395
396
# File 'lib/jsonrpc/middleware.rb', line 393

def log_internal_error(error)
  @logger.error("Internal error: #{error.message}")
  @logger.error(error.backtrace.join("\n"))
end