jsonrpc-middleware 0.1.0 → 0.2.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/.aiexclude +4 -0
- data/.claude/commands/document.md +105 -0
- data/.claude/docs/yard.md +602 -0
- data/.claude/settings.local.json +2 -1
- data/.env.example +5 -0
- data/CHANGELOG.md +22 -2
- data/CLAUDE.md +114 -0
- data/README.md +42 -102
- data/Rakefile +59 -1
- data/examples/README.md +37 -0
- data/examples/procedures.rb +6 -1
- data/examples/rack/README.md +26 -1
- data/examples/rack/app.rb +1 -1
- data/examples/rack-echo/README.md +23 -1
- data/examples/rack-single-file/README.md +37 -0
- data/examples/rack-single-file/config.ru +54 -0
- data/examples/rails/.gitignore +21 -0
- data/examples/rails/.ruby-version +1 -0
- data/examples/rails/Gemfile +15 -0
- data/examples/rails/Gemfile.lock +261 -0
- data/examples/rails/README.md +32 -0
- data/examples/rails/Rakefile +8 -0
- data/examples/rails/app/controllers/application_controller.rb +4 -0
- data/examples/rails/app/controllers/jsonrpc_controller.rb +44 -0
- data/examples/rails/bin/dev +4 -0
- data/examples/rails/bin/rails +6 -0
- data/examples/rails/bin/rake +6 -0
- data/examples/rails/bin/setup +28 -0
- data/examples/rails/config/application.rb +47 -0
- data/examples/rails/config/boot.rb +5 -0
- data/examples/rails/config/credentials.yml.enc +1 -0
- data/examples/rails/config/environment.rb +7 -0
- data/examples/rails/config/environments/development.rb +42 -0
- data/examples/rails/config/environments/production.rb +60 -0
- data/examples/rails/config/environments/test.rb +44 -0
- data/examples/rails/config/initializers/cors.rb +18 -0
- data/examples/rails/config/initializers/filter_parameter_logging.rb +10 -0
- data/examples/rails/config/initializers/inflections.rb +18 -0
- data/examples/rails/config/initializers/jsonrpc.rb +62 -0
- data/examples/rails/config/locales/en.yml +31 -0
- data/examples/rails/config/puma.rb +40 -0
- data/examples/rails/config/routes.rb +14 -0
- data/examples/rails/config.ru +8 -0
- data/examples/rails/public/robots.txt +1 -0
- data/examples/rails-single-file/config.ru +71 -0
- data/examples/sinatra-classic/Gemfile +9 -0
- data/examples/sinatra-classic/Gemfile.lock +95 -0
- data/examples/sinatra-classic/README.md +32 -0
- data/examples/sinatra-classic/app.rb +54 -0
- data/examples/sinatra-classic/config.ru +6 -0
- data/examples/sinatra-modular/Gemfile +9 -0
- data/examples/sinatra-modular/Gemfile.lock +95 -0
- data/examples/sinatra-modular/README.md +32 -0
- data/examples/sinatra-modular/app.rb +57 -0
- data/examples/sinatra-modular/config.ru +6 -0
- data/lib/jsonrpc/batch_request.rb +67 -2
- data/lib/jsonrpc/batch_response.rb +56 -0
- data/lib/jsonrpc/configuration.rb +156 -14
- data/lib/jsonrpc/error.rb +83 -2
- data/lib/jsonrpc/errors/internal_error.rb +14 -2
- data/lib/jsonrpc/errors/invalid_params_error.rb +13 -1
- data/lib/jsonrpc/errors/invalid_request_error.rb +8 -0
- data/lib/jsonrpc/errors/method_not_found_error.rb +8 -0
- data/lib/jsonrpc/errors/parse_error.rb +8 -0
- data/lib/jsonrpc/helpers.rb +212 -21
- data/lib/jsonrpc/middleware.rb +211 -5
- data/lib/jsonrpc/notification.rb +58 -0
- data/lib/jsonrpc/parser.rb +30 -0
- data/lib/jsonrpc/railtie.rb +57 -0
- data/lib/jsonrpc/request.rb +68 -1
- data/lib/jsonrpc/response.rb +76 -0
- data/lib/jsonrpc/validator.rb +67 -6
- data/lib/jsonrpc/version.rb +11 -1
- data/lib/jsonrpc.rb +53 -1
- metadata +49 -1
@@ -6,16 +6,28 @@ module JSONRPC
|
|
6
6
|
# Raised when there was an internal JSON-RPC error.
|
7
7
|
#
|
8
8
|
# @example Create an internal error
|
9
|
-
# error = JSONRPC::Errors::InternalError.new(data: { details:
|
9
|
+
# error = JSONRPC::Errors::InternalError.new(data: { details: 'Unexpected server error' })
|
10
10
|
#
|
11
11
|
class InternalError < Error
|
12
12
|
# Creates a new Internal Error with code -32603
|
13
13
|
#
|
14
|
+
# @api public
|
15
|
+
#
|
16
|
+
# @example Create an internal error
|
17
|
+
# error = JSONRPC::InternalError.new
|
18
|
+
#
|
19
|
+
# @example Create an internal error with exception details
|
20
|
+
# error = JSONRPC::InternalError.new(data: { exception: "NoMethodError" }, request_id: 1)
|
21
|
+
#
|
14
22
|
# @param message [String] short description of the error
|
15
23
|
# @param data [Hash, Array, String, Number, Boolean, nil] additional error information
|
16
24
|
# @param request_id [String, Integer, nil] the request identifier
|
17
25
|
#
|
18
|
-
def initialize(
|
26
|
+
def initialize(
|
27
|
+
message = 'Internal JSON-RPC error.',
|
28
|
+
data: nil,
|
29
|
+
request_id: nil
|
30
|
+
)
|
19
31
|
super(
|
20
32
|
message,
|
21
33
|
code: -32_603,
|
@@ -11,11 +11,23 @@ module JSONRPC
|
|
11
11
|
class InvalidParamsError < Error
|
12
12
|
# Creates a new Invalid Params Error with code -32602
|
13
13
|
#
|
14
|
+
# @api public
|
15
|
+
#
|
16
|
+
# @example Create an invalid params error
|
17
|
+
# error = JSONRPC::InvalidParamsError.new
|
18
|
+
#
|
19
|
+
# @example Create an invalid params error with validation details
|
20
|
+
# error = JSONRPC::InvalidParamsError.new(data: { errors: ["param a is required"] })
|
21
|
+
#
|
14
22
|
# @param message [String] short description of the error
|
15
23
|
# @param data [Hash, Array, String, Number, Boolean, nil] additional error information
|
16
24
|
# @param request_id [String, Integer, nil] the request identifier
|
17
25
|
#
|
18
|
-
def initialize(
|
26
|
+
def initialize(
|
27
|
+
message = 'Invalid method parameter(s).',
|
28
|
+
data: nil,
|
29
|
+
request_id: nil
|
30
|
+
)
|
19
31
|
super(
|
20
32
|
message,
|
21
33
|
code: -32_602,
|
@@ -11,6 +11,14 @@ module JSONRPC
|
|
11
11
|
class InvalidRequestError < Error
|
12
12
|
# Creates a new Invalid Request Error with code -32600
|
13
13
|
#
|
14
|
+
# @api public
|
15
|
+
#
|
16
|
+
# @example Create an invalid request error
|
17
|
+
# error = JSONRPC::InvalidRequestError.new
|
18
|
+
#
|
19
|
+
# @example Create an invalid request error with custom data
|
20
|
+
# error = JSONRPC::InvalidRequestError.new(data: { field: "missing jsonrpc" })
|
21
|
+
#
|
14
22
|
# @param message [String] short description of the error
|
15
23
|
# @param data [Hash, Array, String, Number, Boolean, nil] additional error information
|
16
24
|
# @param request_id [String, Integer, nil] the request identifier
|
@@ -11,6 +11,14 @@ module JSONRPC
|
|
11
11
|
class MethodNotFoundError < Error
|
12
12
|
# Creates a new Method Not Found Error with code -32601
|
13
13
|
#
|
14
|
+
# @api public
|
15
|
+
#
|
16
|
+
# @example Create a method not found error
|
17
|
+
# error = JSONRPC::MethodNotFoundError.new
|
18
|
+
#
|
19
|
+
# @example Create a method not found error with method name
|
20
|
+
# error = JSONRPC::MethodNotFoundError.new(data: { method: "unknown_method" })
|
21
|
+
#
|
14
22
|
# @param message [String] short description of the error
|
15
23
|
# @param data [Hash, Array, String, Number, Boolean, nil] additional error information
|
16
24
|
# @param request_id [String, Integer, nil] the request identifier
|
@@ -12,6 +12,14 @@ module JSONRPC
|
|
12
12
|
class ParseError < Error
|
13
13
|
# Creates a new Parse Error with code -32700
|
14
14
|
#
|
15
|
+
# @api public
|
16
|
+
#
|
17
|
+
# @example Create a parse error with default message
|
18
|
+
# error = JSONRPC::ParseError.new
|
19
|
+
#
|
20
|
+
# @example Create a parse error with custom data
|
21
|
+
# error = JSONRPC::ParseError.new(data: { detail: "Unexpected end of input" })
|
22
|
+
#
|
15
23
|
# @param message [String] short description of the error
|
16
24
|
# @param data [Hash, Array, String, Number, Boolean, nil] additional error information
|
17
25
|
#
|
data/lib/jsonrpc/helpers.rb
CHANGED
@@ -3,32 +3,140 @@
|
|
3
3
|
module JSONRPC
|
4
4
|
# Framework-agnostic helpers for JSON-RPC
|
5
5
|
module Helpers
|
6
|
+
# Extends the including class with ClassMethods when module is included
|
7
|
+
#
|
8
|
+
# @api public
|
9
|
+
#
|
10
|
+
# @example Include helpers in a class
|
11
|
+
# class MyController
|
12
|
+
# include JSONRPC::Helpers
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# @param base [Class] The class including this module
|
16
|
+
#
|
17
|
+
# @return [void]
|
18
|
+
#
|
6
19
|
def self.included(base)
|
7
20
|
base.extend(ClassMethods)
|
8
21
|
end
|
9
22
|
|
10
23
|
# Class methods for registering JSON-RPC procedure handlers
|
11
24
|
module ClassMethods
|
25
|
+
# Registers a JSON-RPC procedure with the given method name
|
26
|
+
#
|
27
|
+
# @api public
|
28
|
+
#
|
29
|
+
# @example Register a procedure
|
30
|
+
# jsonrpc_method('add') do
|
31
|
+
# params do
|
32
|
+
# required(:a).value(:integer)
|
33
|
+
# required(:b).value(:integer)
|
34
|
+
# end
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# @param method_name [String, Symbol] the name of the method
|
38
|
+
#
|
39
|
+
# @yield Block containing the procedure definition
|
40
|
+
#
|
41
|
+
# @return [Configuration::Procedure] the registered procedure
|
42
|
+
#
|
12
43
|
def jsonrpc_method(method_name, &)
|
13
44
|
Configuration.instance.procedure(method_name, &)
|
14
45
|
end
|
15
46
|
end
|
16
47
|
|
17
|
-
|
18
|
-
|
19
|
-
|
48
|
+
# Checks if the current request is a batch request
|
49
|
+
#
|
50
|
+
# @api public
|
51
|
+
#
|
52
|
+
# @example Check if request is batch
|
53
|
+
# jsonrpc_batch? # => true/false
|
54
|
+
#
|
55
|
+
# @return [Boolean] true if current request is a batch
|
56
|
+
#
|
57
|
+
def jsonrpc_batch? = env.key?('jsonrpc.batch')
|
20
58
|
|
21
|
-
#
|
22
|
-
|
23
|
-
|
24
|
-
|
59
|
+
# Checks if the current request is a notification
|
60
|
+
#
|
61
|
+
# @api public
|
62
|
+
#
|
63
|
+
# @example Check if request is notification
|
64
|
+
# jsonrpc_notification? # => true/false
|
65
|
+
#
|
66
|
+
# @return [Boolean] true if current request is a notification
|
67
|
+
#
|
68
|
+
def jsonrpc_notification? = env.key?('jsonrpc.notification')
|
25
69
|
|
26
|
-
#
|
70
|
+
# Checks if the current request is a regular request
|
71
|
+
#
|
72
|
+
# @api public
|
73
|
+
#
|
74
|
+
# @example Check if request is regular request
|
75
|
+
# jsonrpc_request? # => true/false
|
76
|
+
#
|
77
|
+
# @return [Boolean] true if current request is a regular request
|
78
|
+
#
|
79
|
+
def jsonrpc_request? = env.key?('jsonrpc.request')
|
80
|
+
|
81
|
+
# Gets the current JSON-RPC batch request object
|
82
|
+
#
|
83
|
+
# @api public
|
84
|
+
#
|
85
|
+
# @example Get current batch
|
86
|
+
# batch = jsonrpc_batch
|
87
|
+
#
|
88
|
+
# @return [BatchRequest, nil] the current batch request or nil
|
89
|
+
#
|
90
|
+
def jsonrpc_batch = env['jsonrpc.batch']
|
91
|
+
|
92
|
+
# Gets the current JSON-RPC request object
|
93
|
+
#
|
94
|
+
# @api public
|
95
|
+
#
|
96
|
+
# @example Get current request
|
97
|
+
# request = jsonrpc_request
|
98
|
+
#
|
99
|
+
# @return [Request, nil] the current request or nil
|
100
|
+
#
|
101
|
+
def jsonrpc_request = env['jsonrpc.request']
|
102
|
+
|
103
|
+
# Gets the current JSON-RPC notification object
|
104
|
+
#
|
105
|
+
# @api public
|
106
|
+
#
|
107
|
+
# @example Get current notification
|
108
|
+
# notification = jsonrpc_notification
|
109
|
+
#
|
110
|
+
# @return [Notification, nil] the current notification or nil
|
111
|
+
#
|
112
|
+
def jsonrpc_notification = env['jsonrpc.notification']
|
113
|
+
|
114
|
+
# Creates a JSON-RPC response
|
115
|
+
#
|
116
|
+
# @api public
|
117
|
+
#
|
118
|
+
# @example Create a successful response
|
119
|
+
# jsonrpc_response(42) # => [200, headers, body]
|
120
|
+
#
|
121
|
+
# @param result [Object] the result to return
|
122
|
+
#
|
123
|
+
# @return [Array] Rack response tuple
|
124
|
+
#
|
27
125
|
def jsonrpc_response(result)
|
28
126
|
[200, { 'content-type' => 'application/json' }, [Response.new(id: jsonrpc_request.id, result: result).to_json]]
|
29
127
|
end
|
30
128
|
|
31
|
-
#
|
129
|
+
# Creates a JSON-RPC batch response
|
130
|
+
#
|
131
|
+
# @api public
|
132
|
+
#
|
133
|
+
# @example Create a batch response
|
134
|
+
# jsonrpc_batch_response([response1, response2]) # => [200, headers, body]
|
135
|
+
#
|
136
|
+
# @param responses [Array] array of responses
|
137
|
+
#
|
138
|
+
# @return [Array] Rack response tuple
|
139
|
+
#
|
32
140
|
def jsonrpc_batch_response(responses)
|
33
141
|
# If batch contained only notifications, responses will be empty or contain only nils
|
34
142
|
return [204, {}, []] if responses.compact.empty?
|
@@ -36,48 +144,131 @@ module JSONRPC
|
|
36
144
|
[200, { 'content-type' => 'application/json' }, [responses.to_json]]
|
37
145
|
end
|
38
146
|
|
147
|
+
# Creates a response for a notification (no content)
|
148
|
+
#
|
149
|
+
# @api public
|
150
|
+
#
|
151
|
+
# @example Create notification response
|
152
|
+
# jsonrpc_notification_response # => [204, {}, []]
|
153
|
+
#
|
154
|
+
# @return [Array] Rack response tuple with 204 status
|
155
|
+
#
|
39
156
|
def jsonrpc_notification_response
|
40
157
|
[204, {}, []]
|
41
158
|
end
|
42
159
|
|
43
|
-
#
|
160
|
+
# Creates a JSON-RPC error response
|
161
|
+
#
|
162
|
+
# @api public
|
163
|
+
#
|
164
|
+
# @example Create error response
|
165
|
+
# error = JSONRPC::Error.new(code: -32600, message: "Invalid Request")
|
166
|
+
# jsonrpc_error(error) # => JSON string
|
167
|
+
#
|
168
|
+
# @param error [Error] the error object
|
169
|
+
#
|
170
|
+
# @return [String] JSON-formatted error response
|
171
|
+
#
|
44
172
|
def jsonrpc_error(error)
|
45
173
|
Response.new(id: jsonrpc_request.id, error: error).to_json
|
46
174
|
end
|
47
175
|
|
48
|
-
#
|
176
|
+
# Gets the current JSON-RPC request params object
|
177
|
+
#
|
178
|
+
# @api public
|
179
|
+
#
|
180
|
+
# @example Get request parameters
|
181
|
+
# params = jsonrpc_params # => [1, 2, 3] or {"a": 1, "b": 2}
|
182
|
+
#
|
183
|
+
# @return [Array, Hash, nil] the request parameters
|
184
|
+
#
|
49
185
|
def jsonrpc_params
|
50
186
|
jsonrpc_request.params
|
51
187
|
end
|
52
188
|
|
53
|
-
#
|
54
|
-
#
|
189
|
+
# Creates a Parse error (-32700) for invalid JSON
|
190
|
+
#
|
191
|
+
# @api public
|
192
|
+
#
|
193
|
+
# @example Create parse error
|
194
|
+
# jsonrpc_parse_error # => JSON error response
|
195
|
+
#
|
196
|
+
# @param data [Object, nil] additional error data
|
197
|
+
#
|
198
|
+
# @return [String] JSON-formatted error response
|
199
|
+
#
|
55
200
|
def jsonrpc_parse_error(data: nil)
|
56
201
|
jsonrpc_error(ParseError.new(data: data))
|
57
202
|
end
|
58
203
|
|
59
|
-
#
|
60
|
-
#
|
204
|
+
# Creates an Invalid Request error (-32600) for invalid Request objects
|
205
|
+
#
|
206
|
+
# @api public
|
207
|
+
#
|
208
|
+
# @example Create invalid request error
|
209
|
+
# jsonrpc_invalid_request_error # => JSON error response
|
210
|
+
#
|
211
|
+
# @param data [Object, nil] additional error data
|
212
|
+
#
|
213
|
+
# @return [String] JSON-formatted error response
|
214
|
+
#
|
61
215
|
def jsonrpc_invalid_request_error(data: nil)
|
62
216
|
jsonrpc_error(InvalidRequestError.new(data: data))
|
63
217
|
end
|
64
218
|
|
65
|
-
#
|
66
|
-
#
|
219
|
+
# Creates a Method not found error (-32601) for missing methods
|
220
|
+
#
|
221
|
+
# @api public
|
222
|
+
#
|
223
|
+
# @example Create method not found error
|
224
|
+
# jsonrpc_method_not_found_error # => JSON error response
|
225
|
+
#
|
226
|
+
# @param data [Object, nil] additional error data
|
227
|
+
#
|
228
|
+
# @return [String] JSON-formatted error response
|
229
|
+
#
|
67
230
|
def jsonrpc_method_not_found_error(data: nil)
|
68
231
|
jsonrpc_error(MethodNotFoundError.new(data: data))
|
69
232
|
end
|
70
233
|
|
71
|
-
#
|
72
|
-
#
|
234
|
+
# Creates an Invalid params error (-32602) for invalid parameters
|
235
|
+
#
|
236
|
+
# @api public
|
237
|
+
#
|
238
|
+
# @example Create invalid params error
|
239
|
+
# jsonrpc_invalid_params_error # => JSON error response
|
240
|
+
#
|
241
|
+
# @param data [Object, nil] additional error data
|
242
|
+
#
|
243
|
+
# @return [String] JSON-formatted error response
|
244
|
+
#
|
73
245
|
def jsonrpc_invalid_params_error(data: nil)
|
74
246
|
jsonrpc_error(InvalidParamsError.new(data: data))
|
75
247
|
end
|
76
248
|
|
77
|
-
#
|
78
|
-
#
|
249
|
+
# Creates an Internal error (-32603) for server errors
|
250
|
+
#
|
251
|
+
# @api public
|
252
|
+
#
|
253
|
+
# @example Create internal error
|
254
|
+
# jsonrpc_internal_error # => JSON error response
|
255
|
+
#
|
256
|
+
# @param data [Object, nil] additional error data
|
257
|
+
#
|
258
|
+
# @return [String] JSON-formatted error response
|
259
|
+
#
|
79
260
|
def jsonrpc_internal_error(data: nil)
|
80
261
|
jsonrpc_error(InternalError.new(data: data))
|
81
262
|
end
|
263
|
+
|
264
|
+
# Gets the Rack environment hash from @env or the Rails Request
|
265
|
+
#
|
266
|
+
# @api private
|
267
|
+
#
|
268
|
+
# @return [Hash] the Rack environment hash
|
269
|
+
#
|
270
|
+
def env
|
271
|
+
@env ||= request.env
|
272
|
+
end
|
82
273
|
end
|
83
274
|
end
|