jsonrpc-middleware 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.aiignore +6 -1
- data/.claude/agents/entire-search.md +25 -0
- data/.claude/agents/rbs-specialist.md +89 -0
- data/.claude/settings.json +84 -0
- data/.devcontainer/devcontainer.json +17 -0
- data/.dockerignore +16 -0
- data/.entire/.gitignore +5 -0
- data/.entire/settings.json +4 -0
- data/.rubocop.yml +26 -1
- data/.tool-versions +1 -1
- data/.yard-lint.yml +283 -0
- data/AGENTS.md +142 -0
- data/CHANGELOG.md +19 -0
- data/CLAUDE.md +2 -113
- data/Dockerfile +144 -0
- data/README.md +9 -17
- data/Rakefile +62 -11
- data/examples/procedures.rb +3 -1
- data/examples/rack/Gemfile.lock +4 -4
- data/examples/rack-echo/Gemfile.lock +4 -4
- data/examples/rails/Gemfile.lock +12 -5
- data/examples/rails/config/initializers/jsonrpc.rb +1 -1
- data/examples/rails-routing-dsl/config.ru +5 -5
- data/examples/rails-single-file/config.ru +1 -1
- data/examples/rails-single-file-routing/config.ru +1 -1
- data/examples/sinatra-classic/Gemfile.lock +11 -4
- data/examples/sinatra-modular/Gemfile.lock +11 -4
- data/lib/jsonrpc/batch_request.rb +8 -11
- data/lib/jsonrpc/batch_response.rb +6 -8
- data/lib/jsonrpc/configuration.rb +30 -4
- data/lib/jsonrpc/error.rb +7 -8
- data/lib/jsonrpc/errors/internal_error.rb +2 -0
- data/lib/jsonrpc/errors/invalid_params_error.rb +2 -0
- data/lib/jsonrpc/errors/invalid_request_error.rb +2 -0
- data/lib/jsonrpc/errors/method_not_found_error.rb +2 -0
- data/lib/jsonrpc/errors/parse_error.rb +2 -0
- data/lib/jsonrpc/helpers.rb +6 -0
- data/lib/jsonrpc/middleware.rb +12 -11
- data/lib/jsonrpc/notification.rb +7 -8
- data/lib/jsonrpc/parser.rb +13 -12
- data/lib/jsonrpc/railtie/batch_constraint.rb +1 -0
- data/lib/jsonrpc/railtie/mapper_extension.rb +2 -2
- data/lib/jsonrpc/railtie/method_constraint.rb +9 -0
- data/lib/jsonrpc/railtie/routes_dsl.rb +10 -15
- data/lib/jsonrpc/railtie.rb +2 -0
- data/lib/jsonrpc/response.rb +2 -2
- data/lib/jsonrpc/types.rb +1 -1
- data/lib/jsonrpc/validator.rb +14 -4
- data/lib/jsonrpc/version.rb +1 -1
- data/lib/jsonrpc.rb +3 -0
- data/rbs_collection.lock.yaml +476 -0
- data/rbs_collection.yaml +21 -0
- data/sig/jsonrpc/batch_request.rbs +17 -0
- data/sig/jsonrpc/batch_response.rbs +17 -0
- data/sig/jsonrpc/configuration.rbs +18 -0
- data/sig/jsonrpc/error.rbs +17 -0
- data/sig/jsonrpc/errors/internal_error.rbs +5 -0
- data/sig/jsonrpc/errors/invalid_params_error.rbs +5 -0
- data/sig/jsonrpc/errors/invalid_request_error.rbs +5 -0
- data/sig/jsonrpc/errors/method_not_found_error.rbs +5 -0
- data/sig/jsonrpc/errors/parse_error.rbs +5 -0
- data/sig/jsonrpc/middleware.rbs +20 -3
- data/sig/jsonrpc/notification.rbs +15 -0
- data/sig/jsonrpc/parser.rbs +7 -1
- data/sig/jsonrpc/request.rbs +18 -0
- data/sig/jsonrpc/response.rbs +19 -0
- data/sig/jsonrpc/validator.rbs +8 -0
- data/sig/jsonrpc.rbs +3 -156
- data/sig/multi_json.rbs +17 -0
- data/sig/type_definitions.rbs +11 -0
- data/sig/zeitwerk.rbs +10 -0
- metadata +34 -12
- data/.claude/commands/document.md +0 -105
- data/.claude/commands/gemfile/update.md +0 -52
- data/.claude/commands/test.md +0 -561
- data/.claude/docs/yard.md +0 -602
- data/.claude/settings.local.json +0 -15
- data/.yardstick.yml +0 -22
data/lib/jsonrpc/parser.rb
CHANGED
|
@@ -6,6 +6,8 @@ module JSONRPC
|
|
|
6
6
|
# The Parser handles converting raw JSON strings into appropriate JSONRPC objects
|
|
7
7
|
# based on the JSON-RPC 2.0 protocol specification.
|
|
8
8
|
#
|
|
9
|
+
# @api public
|
|
10
|
+
#
|
|
9
11
|
# @example Parse a request
|
|
10
12
|
# parser = JSONRPC::Parser.new
|
|
11
13
|
# request = parser.parse('{"jsonrpc":"2.0","method":"subtract","params":[42,23],"id":1}')
|
|
@@ -26,14 +28,13 @@ module JSONRPC
|
|
|
26
28
|
# @example Parse a batch request
|
|
27
29
|
# parser.parse('[{"jsonrpc":"2.0","method":"sum","params":[1,2],"id":"1"}]')
|
|
28
30
|
#
|
|
31
|
+
# @raise [ParseError] if the JSON is invalid
|
|
32
|
+
# @raise [InvalidRequestError] if the request structure is invalid
|
|
33
|
+
#
|
|
29
34
|
# @param json [String] the JSON-RPC 2.0 message
|
|
30
35
|
#
|
|
31
36
|
# @return [Request, Notification, BatchRequest] the parsed object
|
|
32
37
|
#
|
|
33
|
-
# @raise [ParseError] if the JSON is invalid
|
|
34
|
-
#
|
|
35
|
-
# @raise [InvalidRequestError] if the request structure is invalid
|
|
36
|
-
#
|
|
37
38
|
def parse(json)
|
|
38
39
|
data = MultiJson.load(json)
|
|
39
40
|
|
|
@@ -83,12 +84,12 @@ module JSONRPC
|
|
|
83
84
|
#
|
|
84
85
|
# @api private
|
|
85
86
|
#
|
|
87
|
+
# @raise [InvalidRequestError] if the batch is empty
|
|
88
|
+
#
|
|
86
89
|
# @param data [Array] the array of request data
|
|
87
90
|
#
|
|
88
91
|
# @return [BatchRequest] the batch request
|
|
89
92
|
#
|
|
90
|
-
# @raise [InvalidRequestError] if the batch is empty
|
|
91
|
-
#
|
|
92
93
|
def parse_batch(data)
|
|
93
94
|
raise InvalidRequestError.new(data: { details: 'Batch request cannot be empty' }) if data.empty?
|
|
94
95
|
|
|
@@ -114,12 +115,12 @@ module JSONRPC
|
|
|
114
115
|
#
|
|
115
116
|
# @api private
|
|
116
117
|
#
|
|
118
|
+
# @raise [InvalidRequestError] if the request structure is invalid
|
|
119
|
+
#
|
|
117
120
|
# @param data [Hash] the parsed JSON data for a single item
|
|
118
121
|
#
|
|
119
122
|
# @return [Request, Notification] the parsed request or notification
|
|
120
123
|
#
|
|
121
|
-
# @raise [InvalidRequestError] if the request structure is invalid
|
|
122
|
-
#
|
|
123
124
|
def parse_single_for_batch(data)
|
|
124
125
|
validate_jsonrpc_version(data)
|
|
125
126
|
validate_request_structure(data)
|
|
@@ -141,10 +142,10 @@ module JSONRPC
|
|
|
141
142
|
#
|
|
142
143
|
# @api private
|
|
143
144
|
#
|
|
144
|
-
# @param data [Hash] the request data
|
|
145
|
-
#
|
|
146
145
|
# @raise [InvalidRequestError] if the version is missing or invalid
|
|
147
146
|
#
|
|
147
|
+
# @param data [Hash] the request data
|
|
148
|
+
#
|
|
148
149
|
# @return [void]
|
|
149
150
|
#
|
|
150
151
|
def validate_jsonrpc_version(data)
|
|
@@ -170,10 +171,10 @@ module JSONRPC
|
|
|
170
171
|
#
|
|
171
172
|
# @api private
|
|
172
173
|
#
|
|
173
|
-
# @param data [Hash] the request data
|
|
174
|
-
#
|
|
175
174
|
# @raise [InvalidRequestError] if the request structure is invalid
|
|
176
175
|
#
|
|
176
|
+
# @param data [Hash] the request data
|
|
177
|
+
#
|
|
177
178
|
# @return [void]
|
|
178
179
|
#
|
|
179
180
|
def validate_request_structure(data)
|
|
@@ -8,8 +8,6 @@ module JSONRPC
|
|
|
8
8
|
module MapperExtension
|
|
9
9
|
# Define JSON-RPC routes with a DSL
|
|
10
10
|
#
|
|
11
|
-
# @param path [String] the path to handle JSON-RPC requests on
|
|
12
|
-
#
|
|
13
11
|
# @example Define JSON-RPC routes
|
|
14
12
|
# jsonrpc '/api/v1' do
|
|
15
13
|
# # Handle batch requests
|
|
@@ -24,6 +22,8 @@ module JSONRPC
|
|
|
24
22
|
# end
|
|
25
23
|
# end
|
|
26
24
|
#
|
|
25
|
+
# @param path [String] the path to handle JSON-RPC requests on
|
|
26
|
+
#
|
|
27
27
|
# @return [void]
|
|
28
28
|
#
|
|
29
29
|
def jsonrpc(path = '/', &)
|
|
@@ -22,6 +22,7 @@ module JSONRPC
|
|
|
22
22
|
# Check if the request matches the configured method name
|
|
23
23
|
#
|
|
24
24
|
# @param request [ActionDispatch::Request] The Rails request object
|
|
25
|
+
#
|
|
25
26
|
# @return [Boolean] true if the JSON-RPC method matches, false otherwise
|
|
26
27
|
#
|
|
27
28
|
def matches?(request)
|
|
@@ -31,5 +32,13 @@ module JSONRPC
|
|
|
31
32
|
|
|
32
33
|
jsonrpc_request.method == @jsonrpc_method_name
|
|
33
34
|
end
|
|
35
|
+
|
|
36
|
+
# Returns a string representation of the constraint
|
|
37
|
+
#
|
|
38
|
+
# @return [String] A string showing the configured JSON-RPC method name
|
|
39
|
+
#
|
|
40
|
+
def to_s
|
|
41
|
+
"#<JSONRPC::MethodConstraint method=\"#{@jsonrpc_method_name}\">"
|
|
42
|
+
end
|
|
34
43
|
end
|
|
35
44
|
end
|
|
@@ -57,9 +57,6 @@ module JSONRPC
|
|
|
57
57
|
|
|
58
58
|
# Define a JSON-RPC method route
|
|
59
59
|
#
|
|
60
|
-
# @param jsonrpc_method [String] the JSON-RPC method name
|
|
61
|
-
# @param to [String] the Rails controller action (e.g., 'users#create')
|
|
62
|
-
#
|
|
63
60
|
# @example Map a JSON-RPC method to controller action
|
|
64
61
|
# method 'user.create', to: 'users#create'
|
|
65
62
|
#
|
|
@@ -68,33 +65,30 @@ module JSONRPC
|
|
|
68
65
|
# method 'create', to: 'posts#create' # becomes posts.create
|
|
69
66
|
# end
|
|
70
67
|
#
|
|
68
|
+
# @param jsonrpc_method [String] the JSON-RPC method name
|
|
69
|
+
# @param to [String] the Rails controller action (e.g., 'users#create')
|
|
70
|
+
#
|
|
71
71
|
# @return [void]
|
|
72
72
|
#
|
|
73
73
|
def method(jsonrpc_method, to:)
|
|
74
74
|
full_method_name = build_full_method_name(jsonrpc_method)
|
|
75
75
|
constraint = JSONRPC::MethodConstraint.new(full_method_name)
|
|
76
76
|
|
|
77
|
-
@mapper.post
|
|
78
|
-
to: to,
|
|
79
|
-
constraints: constraint
|
|
80
|
-
}
|
|
77
|
+
@mapper.post(@path_prefix, to: to, constraints: constraint)
|
|
81
78
|
end
|
|
82
79
|
|
|
83
80
|
# Define a route for handling JSON-RPC batch requests
|
|
84
81
|
#
|
|
85
|
-
# @param to [String] the Rails controller action (e.g., 'batches#handle')
|
|
86
|
-
#
|
|
87
82
|
# @example Map batch requests to a controller action
|
|
88
83
|
# batch to: 'batches#handle'
|
|
89
84
|
#
|
|
85
|
+
# @param to [String] the Rails controller action (e.g., 'batches#handle')
|
|
86
|
+
#
|
|
90
87
|
# @return [void]
|
|
91
88
|
def batch(to:)
|
|
92
89
|
constraint = JSONRPC::BatchConstraint.new
|
|
93
90
|
|
|
94
|
-
@mapper.post
|
|
95
|
-
to: to,
|
|
96
|
-
constraints: constraint
|
|
97
|
-
}
|
|
91
|
+
@mapper.post(@path_prefix, to: to, constraints: constraint)
|
|
98
92
|
end
|
|
99
93
|
|
|
100
94
|
# Create a namespace for grouping related JSON-RPC methods
|
|
@@ -102,8 +96,6 @@ module JSONRPC
|
|
|
102
96
|
# Namespaces can be nested to create hierarchical method names.
|
|
103
97
|
# Each level of nesting adds a dot-separated prefix to the method names.
|
|
104
98
|
#
|
|
105
|
-
# @param name [String] the namespace name
|
|
106
|
-
#
|
|
107
99
|
# @example Single-level namespace
|
|
108
100
|
# namespace 'posts' do
|
|
109
101
|
# method 'create', to: 'posts#create' # becomes posts.create
|
|
@@ -121,6 +113,8 @@ module JSONRPC
|
|
|
121
113
|
# end
|
|
122
114
|
# end
|
|
123
115
|
#
|
|
116
|
+
# @param name [String] the namespace name
|
|
117
|
+
#
|
|
124
118
|
# @return [void]
|
|
125
119
|
#
|
|
126
120
|
def namespace(name, &)
|
|
@@ -134,6 +128,7 @@ module JSONRPC
|
|
|
134
128
|
# Build the full method name including namespaces
|
|
135
129
|
#
|
|
136
130
|
# @param method_name [String] the base method name
|
|
131
|
+
#
|
|
137
132
|
# @return [String] the full method name with namespace prefixes
|
|
138
133
|
#
|
|
139
134
|
def build_full_method_name(method_name)
|
data/lib/jsonrpc/railtie.rb
CHANGED
data/lib/jsonrpc/response.rb
CHANGED
|
@@ -82,9 +82,7 @@ module JSONRPC
|
|
|
82
82
|
# @param id [String, Integer, nil] the request identifier
|
|
83
83
|
#
|
|
84
84
|
# @raise [ArgumentError] if both result and error are present or both are nil
|
|
85
|
-
#
|
|
86
85
|
# @raise [ArgumentError] if error is present but not a JSONRPC::Error
|
|
87
|
-
#
|
|
88
86
|
# @raise [ArgumentError] if id is not a String, Integer, or nil
|
|
89
87
|
#
|
|
90
88
|
|
|
@@ -150,5 +148,7 @@ module JSONRPC
|
|
|
150
148
|
def to_json(*)
|
|
151
149
|
MultiJson.dump(to_h, *)
|
|
152
150
|
end
|
|
151
|
+
|
|
152
|
+
alias to_response to_h
|
|
153
153
|
end
|
|
154
154
|
end
|
data/lib/jsonrpc/types.rb
CHANGED
data/lib/jsonrpc/validator.rb
CHANGED
|
@@ -13,6 +13,16 @@ module JSONRPC
|
|
|
13
13
|
# error = validator.validate(request)
|
|
14
14
|
#
|
|
15
15
|
class Validator
|
|
16
|
+
# Initializes the Validator
|
|
17
|
+
#
|
|
18
|
+
# @api public
|
|
19
|
+
#
|
|
20
|
+
# @param logger [Logger] the logger instance for diagnostic output
|
|
21
|
+
#
|
|
22
|
+
def initialize(logger: JSONRPC.configuration.logger)
|
|
23
|
+
@logger = logger
|
|
24
|
+
end
|
|
25
|
+
|
|
16
26
|
# Validates a single request, notification or a batch
|
|
17
27
|
#
|
|
18
28
|
# @api public
|
|
@@ -92,7 +102,7 @@ module JSONRPC
|
|
|
92
102
|
request_id: extract_request_id(request_or_notification),
|
|
93
103
|
data: {
|
|
94
104
|
method: request_or_notification.method,
|
|
95
|
-
params: validation_result.errors.to_h
|
|
105
|
+
params: validation_result.errors.to_h # rubocop:disable Rails/DeprecatedActiveModelErrorsMethods
|
|
96
106
|
}
|
|
97
107
|
)
|
|
98
108
|
end
|
|
@@ -100,8 +110,8 @@ module JSONRPC
|
|
|
100
110
|
nil
|
|
101
111
|
rescue StandardError => e
|
|
102
112
|
if JSONRPC.configuration.log_request_validation_errors
|
|
103
|
-
|
|
104
|
-
|
|
113
|
+
@logger.error("Validation error: #{e.message}")
|
|
114
|
+
@logger.error(e.backtrace.join("\n"))
|
|
105
115
|
end
|
|
106
116
|
|
|
107
117
|
InternalError.new(request_id: extract_request_id(request_or_notification))
|
|
@@ -111,7 +121,7 @@ module JSONRPC
|
|
|
111
121
|
#
|
|
112
122
|
# @api private
|
|
113
123
|
#
|
|
114
|
-
# @param request [Request, Notification]
|
|
124
|
+
# @param request [Request, Notification] A request or notification to be validated
|
|
115
125
|
# @param procedure [Configuration::Procedure] the procedure configuration
|
|
116
126
|
#
|
|
117
127
|
# @return [Hash, InvalidParamsError] prepared params or error
|
data/lib/jsonrpc/version.rb
CHANGED
data/lib/jsonrpc.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'logger'
|
|
3
4
|
require 'zeitwerk'
|
|
4
5
|
require 'dry-struct'
|
|
5
6
|
require 'dry-validation'
|
|
@@ -72,10 +73,12 @@ loader.enable_reloading
|
|
|
72
73
|
loader.collapse("#{__dir__}/jsonrpc/errors")
|
|
73
74
|
loader.collapse("#{__dir__}/jsonrpc/railtie")
|
|
74
75
|
|
|
76
|
+
# :nocov:
|
|
75
77
|
unless defined?(Rails)
|
|
76
78
|
loader.ignore("#{__dir__}/jsonrpc/railtie.rb")
|
|
77
79
|
loader.ignore("#{__dir__}/jsonrpc/railtie/method_constraint.rb")
|
|
78
80
|
end
|
|
81
|
+
# :nocov:
|
|
79
82
|
|
|
80
83
|
loader.inflector.inflect('jsonrpc' => 'JSONRPC')
|
|
81
84
|
loader.setup
|