jsonrpc-middleware 0.4.0 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a45b1d353d7fd1547e7e984edba9c9ed1e02669914c00294d08f259cb5bb76e6
4
- data.tar.gz: 25d2b7802a03378c90e181d5e5b580489299d41a3070817d762b43063a9d68b3
3
+ metadata.gz: bf6393e7fe408f08dc933ebb6fc73a2541829eab966df8acedd7103a2e4e2c01
4
+ data.tar.gz: f1f17e444ea3a84cfd69e46316e595eaa00fc0a01e9566e313111dc0e47142b8
5
5
  SHA512:
6
- metadata.gz: c3a417f6096c195940c782cb313f9b4e7a5e6ef2c1c6ed994a4d23e226e7a70ba7df4b635b03c56f392983b45b1d0239f0a121c2b2982101c5ad5c47680bd7f8
7
- data.tar.gz: 601bc95a7d965e6721af683765881d73ac34fc5ced0791c398b1ddc4acff054b586d0c74ab0107bf139bb177afcebc760460d96cb86896afec1394972b98b6d9
6
+ metadata.gz: 103c23a06d7d49ad68ed3d7249f24cf7a7c52cf82d72a9a0af68b1da4d2ec1869e8e80ef0207be9d4aaf5e85caf7433094f3f1e4dc52e812b4a5cf6cf074f735
7
+ data.tar.gz: eb0dcf3da91d3176de5507c1a9c604ffefdc59bfbd4476a0355d74fc85f301674b89f8b2a743b9eca4168dc3b410a43de3a056079674d64e7651fc7c2c69ada1
@@ -0,0 +1,52 @@
1
+ ---
2
+ allowed-tools: Bash(bundle :*), Bash(git :*), Read, Edit, MultiEdit, Glob
3
+ description: Update Gemfile dependencies to latest minor versions
4
+ argument-hint: [gemfile] [commit]
5
+ ---
6
+
7
+ Update the dependencies in the specified Gemfile (or ./Gemfile if no path provided) to their latest minor versions while
8
+ preserving major version constraints. Only update MAJOR.MINOR versions, never PATCH versions unless explicitly needed.
9
+
10
+ Steps:
11
+ 1. Read the Gemfile at the specified path (or ./Gemfile if $ARGUMENTS is empty)
12
+ 2. Read the corresponding Gemfile.lock to get current resolved versions
13
+ 3. Run `bundle outdated --only-explicit` to check for available minor updates of explicitly declared gems
14
+ 4. For each gem in Gemfile, check if Gemfile.lock has a newer minor version than the current Gemfile constraint allows
15
+ 5. Update gem version constraints to match the minor version from Gemfile.lock or latest available, whichever is newer (MAJOR.MINOR format)
16
+ 6. Use pessimistic version constraints (~> MAJOR.MINOR) to prevent automatic patch updates
17
+ 7. Preserve any existing version operators but ensure they follow minor-only update strategy
18
+ 8. Run `bundle update` to apply the changes
19
+ 7. Skip step 8, 9 and 10 if --commit flag is not provided
20
+ 8. Stage Gemfile (only if not gitignored)
21
+ 9. Verify if Gemfile.lock is tracked and not gitignored. If both conditions are met, stage it for commit.
22
+ 10. Create a git commit with message 'Update development dependencies' and a description listing all updated gems with their old and new versions like:
23
+
24
+ <commit-message>
25
+ Updated gems:
26
+ - rubocop: 1.75.2 → 1.78.0
27
+ - rubocop-yard: 0.10.0 → 1.0.0
28
+ </commit-message>
29
+
30
+ 11. If any dependencies were updated, respond only with the update message. And if the user has chose to commit,
31
+ include the update commit message. Otherwise, respond only with the no op message.
32
+
33
+ <update-message>
34
+ Updated gems:
35
+ - rbs: 3.8 → 3.9
36
+ - rubocop: 1.78 → 1.80
37
+ - rubocop-rspec: 3.6 → 3.7
38
+
39
+ <update-commit-message>The changes have been committed with the message "Update development dependencies".</update-commit-message>
40
+ </update-message>
41
+
42
+ <no-op-message>All dependencies are up to date.</no-op-message>
43
+
44
+ Key bundle outdated flags used:
45
+ - `--only-explicit`: Only show gems explicitly listed in Gemfile (not dependencies)
46
+ - No `--local` flag to ensure remote gem sources are checked for latest versions
47
+
48
+ Arguments:
49
+ - `gemfile`: Gemfile path (defaults to ./Gemfile if not provided)
50
+ - `--commit`: Create a git commit after updating dependencies with message 'Update development dependencies' and a description listing all updated gems with their old and new versions
51
+
52
+ Gemfile path: ${ARGUMENTS:-./Gemfile}
@@ -4,8 +4,12 @@
4
4
  "Bash(bundle exec rspec:*)",
5
5
  "Bash(bundle exec rubocop:*)",
6
6
  "Bash(bundle exec rake:*)",
7
- "Bash(mkdir:*)"
7
+ "Bash(mkdir:*)",
8
+ "Bash(bin/console:*)",
9
+ "Bash(bundle exec ruby:*)",
10
+ "Bash(git:*)",
11
+ "Bash(grep:*)"
8
12
  ]
9
13
  },
10
14
  "enableAllProjectMcpServers": false
11
- }
15
+ }
data/CHANGELOG.md CHANGED
@@ -5,10 +5,97 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.6.0] - 2025-09-17
9
+
10
+ ### Added
11
+ - MultiJson support for improved JSON performance and flexibility
12
+ - Configuration option to select JSON adapter (`JSONRPC.configuration.json_adapter`)
13
+ - Enhanced error handling with adapter and input preview details
14
+ - Better performance through optimized JSON parsing
15
+ - Enhanced examples
16
+ - Batch JSON-RPC request handling in Rails single-file routing example
17
+ - Smart home control API example using Rails routing DSL
18
+ - Updated documentation with batch request usage examples
19
+
20
+ ### Changed
21
+ - Replaced JSON gem with MultiJson throughout the codebase
22
+ - All JSON parsing now uses MultiJson for better adapter support
23
+ - Updated documentation to mention optimized JSON handling
24
+ - Refactored Request and Response classes to use dry-struct
25
+ - Simplified class definitions with automatic type checking
26
+ - Reduced code complexity while maintaining functionality
27
+ - Enhanced Rails integration
28
+ - Improved example applications with better error handling
29
+ - Updated Gemfile.lock files across all examples
30
+
31
+ ## [0.5.0] - 2025-07-22
32
+
33
+ ### Added
34
+ - Rails routing DSL for elegant JSON-RPC method mapping with support for namespaces and batch handling:
35
+ ```ruby
36
+ # In routes.rb
37
+ jsonrpc '/' do
38
+ # Handle batch requests
39
+ batch to: 'batch#handle'
40
+
41
+ method 'on', to: 'main#on'
42
+ method 'off', to: 'main#off'
43
+
44
+ namespace 'lights' do
45
+ method 'on', to: 'lights#on' # becomes lights.on
46
+ method 'off', to: 'lights#off' # becomes lights.off
47
+ end
48
+
49
+ namespace 'climate' do
50
+ method 'on', to: 'climate#on' # becomes climate.on
51
+ method 'off', to: 'climate#off' # becomes climate.off
52
+
53
+ namespace 'fan' do
54
+ method 'on', to: 'fan#on' # becomes climate.fan.on
55
+ method 'off', to: 'fan#off' # becomes climate.fan.off
56
+ end
57
+ end
58
+ end
59
+ ```
60
+ - `JSONRPC::BatchConstraint` for routing JSON-RPC batch requests to dedicated controllers:
61
+ ```ruby
62
+ # Handle batch requests with custom constraint
63
+ post '/api', to: 'api#handle_batch', constraints: JSONRPC::BatchConstraint.new
64
+
65
+ # Or use the DSL (recommended)
66
+ jsonrpc '/api' do
67
+ batch to: 'api#handle_batch'
68
+ end
69
+ ```
70
+
71
+ ### Changed
72
+ - Procedure registration now supports optional validation blocks (defaults to empty contract):
73
+ ```ruby
74
+ # Before: Always required validation block (even if empty)
75
+ procedure('ping') do
76
+ params do
77
+ # No params needed
78
+ end
79
+ end
80
+
81
+ # After: Optional validation block
82
+ procedure('ping') # Uses empty contract by default
83
+
84
+ # Still works with validation when needed
85
+ procedure('add') do
86
+ params do
87
+ required(:a).value(:integer)
88
+ required(:b).value(:integer)
89
+ end
90
+ end
91
+ ```
92
+ - Simplified example configurations by removing unnecessary empty validation blocks
93
+ - Enhanced Rails integration with automatic DSL registration via Railtie
94
+
8
95
  ## [0.4.0] - 2025-07-18
9
96
 
10
97
  ### Added
11
- - JSONRPC::BatchRequest#process_each method for simplified batch processing
98
+ - `JSONRPC::BatchRequest#process_each` method for simplified batch processing
12
99
 
13
100
  ## [0.3.0] - 2025-07-17
14
101
 
@@ -71,6 +158,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
71
158
  - Helper methods for request and response processing
72
159
  - Examples for basic and advanced usage scenarios
73
160
 
161
+ [0.6.0]: https://github.com/wilsonsilva/jsonrpc-middleware/compare/v0.5.0...v0.6.0
162
+ [0.5.0]: https://github.com/wilsonsilva/jsonrpc-middleware/compare/v0.4.0...v0.5.0
74
163
  [0.4.0]: https://github.com/wilsonsilva/jsonrpc-middleware/compare/v0.3.0...v0.4.0
75
164
  [0.3.0]: https://github.com/wilsonsilva/jsonrpc-middleware/compare/v0.2.0...v0.3.0
76
165
  [0.2.0]: https://github.com/wilsonsilva/jsonrpc-middleware/compare/v0.1.0...v0.2.0
data/README.md CHANGED
@@ -37,9 +37,11 @@ A Rack middleware implementing the JSON-RPC 2.0 protocol that integrates easily
37
37
  - **Spec-compliant**: Fully implements the [JSON-RPC 2.0 specification](https://www.jsonrpc.org/specification)
38
38
  - **Rack middleware integration**: Seamlessly integrates with Rack applications (Rails, Sinatra, Hanami, etc)
39
39
  - **Support for all request types**: Handles single requests, notifications, and batch requests
40
+ - **Rails routing DSL**: Elegant routing DSL for Rails applications with support for namespaces and batch handling
40
41
  - **Error handling**: Comprehensive error handling with standard JSON-RPC error responses
41
42
  - **Request validation**: Define request parameter specifications and validations
42
43
  - **Helpers**: Convenient helper methods to simplify request and response processing
44
+ - **Optimized JSON handling**: Uses MultiJSON to automatically select the fastest available JSON library
43
45
 
44
46
  ## 🏗️ Architecture
45
47
 
@@ -174,6 +176,7 @@ rake bundle:audit:update # Updates the bundler-audit vulnerability database
174
176
  rake clean # Remove any temporary products
175
177
  rake clobber # Remove any generated files
176
178
  rake coverage # Run spec with coverage
179
+ rake examples:bundle_install # Run bundle install on all example folders (useful after updating the gem version)
177
180
  rake install # Build and install jsonrpc-middleware.gem into system gems
178
181
  rake install:local # Build and install jsonrpc-middleware.gem into system gems without network access
179
182
  rake qa # Test, lint and perform security and documentation audits
data/Rakefile CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'English' # For $CHILD_STATUS
3
4
  require 'bundler/audit/task'
4
5
  require 'bundler/gem_tasks'
5
6
  require 'rspec/core/rake_task'
@@ -95,3 +96,59 @@ namespace :yard do
95
96
  puts 'Done!'
96
97
  end
97
98
  end
99
+
100
+ namespace :examples do
101
+ desc 'Run bundle install on all example folders'
102
+ task :bundle_install do
103
+ examples_dir = File.join(Dir.pwd, 'examples')
104
+
105
+ unless Dir.exist?(examples_dir)
106
+ puts 'Examples directory not found'
107
+ exit 1
108
+ end
109
+
110
+ example_folders = Dir.glob(File.join(examples_dir, '*')).select { |path| Dir.exist?(path) }
111
+
112
+ if example_folders.empty?
113
+ puts 'No example folders found'
114
+ return
115
+ end
116
+
117
+ puts "Found #{example_folders.length} example folders:"
118
+ example_folders.each { |folder| puts " - #{File.basename(folder)}" }
119
+ puts
120
+
121
+ failed_folders = []
122
+
123
+ example_folders.each do |folder|
124
+ gemfile_path = File.join(folder, 'Gemfile')
125
+
126
+ unless File.exist?(gemfile_path)
127
+ puts "Skipping #{File.basename(folder)} - no Gemfile found"
128
+ next
129
+ end
130
+
131
+ puts "Running bundle install in #{File.basename(folder)}..."
132
+
133
+ Dir.chdir(folder) do
134
+ system('bundle install')
135
+
136
+ if $CHILD_STATUS.success?
137
+ puts " ✓ Successfully installed gems in #{File.basename(folder)}"
138
+ else
139
+ failed_folders << File.basename(folder)
140
+ puts " ✗ Failed to bundle install in #{File.basename(folder)}"
141
+ end
142
+ end
143
+
144
+ puts
145
+ end
146
+
147
+ if failed_folders.empty?
148
+ puts 'All example folders processed successfully!'
149
+ else
150
+ puts "Failed to process #{failed_folders.length} folders: #{failed_folders.join(", ")}"
151
+ exit 1
152
+ end
153
+ end
154
+ end
data/examples/README.md CHANGED
@@ -10,6 +10,7 @@ This directory contains example implementations of JSON-RPC servers using the js
10
10
  - [**rails**](./rails/) - Calculator server using Rails
11
11
  - [**rails-single-file**](./rails-single-file/) - Echo server using Rails with bundler/inline
12
12
  - [**rails-single-file-routing**](./rails-single-file-routing/) - Echo server using Rails with method-specific routing
13
+ - [**rails-routing-dsl**](./rails-routing-dsl/) - Smart home control server showcasing Rails JSON-RPC routing DSL
13
14
  - [**sinatra-classic**](./sinatra-classic/) - Calculator server using classic Sinatra
14
15
  - [**sinatra-modular**](./sinatra-modular/) - Calculator server using modular Sinatra
15
16
 
@@ -27,6 +28,14 @@ The echo examples implement:
27
28
 
28
29
  - `echo` - Returns the input message
29
30
 
31
+ The rails-routing-dsl example implements a smart home control API:
32
+
33
+ - `on` / `off` - Control main home automation system
34
+ - `lights.on` / `lights.off` - Control lights
35
+ - `climate.on` / `climate.off` - Control climate system
36
+ - `climate.fan.on` / `climate.fan.off` - Control climate fan
37
+ - Batch request support for multiple operations
38
+
30
39
  ## Running Examples
31
40
 
32
41
  Each example directory contains its own README with specific instructions. Generally:
@@ -52,9 +52,5 @@ JSONRPC.configure do |config|
52
52
  end
53
53
 
54
54
  # Used only to test internal server errors
55
- procedure(:explode) do
56
- params do
57
- # No params
58
- end
59
- end
55
+ procedure(:explode)
60
56
  end
@@ -1,8 +1,10 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- jsonrpc-middleware (0.3.0)
4
+ jsonrpc-middleware (0.5.0)
5
+ dry-struct (~> 1.8)
5
6
  dry-validation (~> 1.11)
7
+ multi_json (~> 1.17)
6
8
  zeitwerk (~> 2.7)
7
9
 
8
10
  GEM
@@ -32,6 +34,11 @@ GEM
32
34
  dry-logic (~> 1.5)
33
35
  dry-types (~> 1.8)
34
36
  zeitwerk (~> 2.6)
37
+ dry-struct (1.8.0)
38
+ dry-core (~> 1.1)
39
+ dry-types (~> 1.8, >= 1.8.2)
40
+ ice_nine (~> 0.11)
41
+ zeitwerk (~> 2.6)
35
42
  dry-types (1.8.3)
36
43
  bigdecimal (~> 3.0)
37
44
  concurrent-ruby (~> 1.0)
@@ -45,7 +52,9 @@ GEM
45
52
  dry-initializer (~> 3.2)
46
53
  dry-schema (~> 1.14)
47
54
  zeitwerk (~> 2.6)
55
+ ice_nine (0.11.2)
48
56
  logger (1.7.0)
57
+ multi_json (1.17.0)
49
58
  nio4r (2.7.4)
50
59
  puma (6.6.0)
51
60
  nio4r (~> 2.0)
@@ -1,8 +1,10 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- jsonrpc-middleware (0.2.0)
4
+ jsonrpc-middleware (0.5.0)
5
+ dry-struct (~> 1.8)
5
6
  dry-validation (~> 1.11)
7
+ multi_json (~> 1.17)
6
8
  zeitwerk (~> 2.7)
7
9
 
8
10
  GEM
@@ -32,6 +34,11 @@ GEM
32
34
  dry-logic (~> 1.5)
33
35
  dry-types (~> 1.8)
34
36
  zeitwerk (~> 2.6)
37
+ dry-struct (1.8.0)
38
+ dry-core (~> 1.1)
39
+ dry-types (~> 1.8, >= 1.8.2)
40
+ ice_nine (~> 0.11)
41
+ zeitwerk (~> 2.6)
35
42
  dry-types (1.8.3)
36
43
  bigdecimal (~> 3.0)
37
44
  concurrent-ruby (~> 1.0)
@@ -45,7 +52,9 @@ GEM
45
52
  dry-initializer (~> 3.2)
46
53
  dry-schema (~> 1.14)
47
54
  zeitwerk (~> 2.6)
55
+ ice_nine (0.11.2)
48
56
  logger (1.7.0)
57
+ multi_json (1.17.0)
49
58
  nio4r (2.7.4)
50
59
  puma (6.6.0)
51
60
  nio4r (~> 2.0)
@@ -1,8 +1,10 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- jsonrpc-middleware (0.2.0)
4
+ jsonrpc-middleware (0.5.0)
5
+ dry-struct (~> 1.8)
5
6
  dry-validation (~> 1.11)
7
+ multi_json (~> 1.17)
6
8
  zeitwerk (~> 2.7)
7
9
 
8
10
  GEM
@@ -113,6 +115,11 @@ GEM
113
115
  dry-logic (~> 1.5)
114
116
  dry-types (~> 1.8)
115
117
  zeitwerk (~> 2.6)
118
+ dry-struct (1.8.0)
119
+ dry-core (~> 1.1)
120
+ dry-types (~> 1.8, >= 1.8.2)
121
+ ice_nine (~> 0.11)
122
+ zeitwerk (~> 2.6)
116
123
  dry-types (1.8.3)
117
124
  bigdecimal (~> 3.0)
118
125
  concurrent-ruby (~> 1.0)
@@ -132,6 +139,7 @@ GEM
132
139
  activesupport (>= 6.1)
133
140
  i18n (1.14.7)
134
141
  concurrent-ruby (~> 1.0)
142
+ ice_nine (0.11.2)
135
143
  io-console (0.8.1)
136
144
  irb (1.15.2)
137
145
  pp (>= 0.6.0)
@@ -149,6 +157,7 @@ GEM
149
157
  marcel (1.0.4)
150
158
  mini_mime (1.1.5)
151
159
  minitest (5.25.5)
160
+ multi_json (1.17.0)
152
161
  net-imap (0.5.9)
153
162
  date
154
163
  net-protocol
@@ -159,22 +168,8 @@ GEM
159
168
  net-smtp (0.5.1)
160
169
  net-protocol
161
170
  nio4r (2.7.4)
162
- nokogiri (1.18.8-aarch64-linux-gnu)
163
- racc (~> 1.4)
164
- nokogiri (1.18.8-aarch64-linux-musl)
165
- racc (~> 1.4)
166
- nokogiri (1.18.8-arm-linux-gnu)
167
- racc (~> 1.4)
168
- nokogiri (1.18.8-arm-linux-musl)
169
- racc (~> 1.4)
170
171
  nokogiri (1.18.8-arm64-darwin)
171
172
  racc (~> 1.4)
172
- nokogiri (1.18.8-x86_64-darwin)
173
- racc (~> 1.4)
174
- nokogiri (1.18.8-x86_64-linux-gnu)
175
- racc (~> 1.4)
176
- nokogiri (1.18.8-x86_64-linux-musl)
177
- racc (~> 1.4)
178
173
  pp (0.6.2)
179
174
  prettyprint
180
175
  prettyprint (0.2.0)
@@ -242,14 +237,7 @@ GEM
242
237
  zeitwerk (2.7.3)
243
238
 
244
239
  PLATFORMS
245
- aarch64-linux-gnu
246
- aarch64-linux-musl
247
- arm-linux-gnu
248
- arm-linux-musl
249
240
  arm64-darwin
250
- x86_64-darwin
251
- x86_64-linux-gnu
252
- x86_64-linux-musl
253
241
 
254
242
  DEPENDENCIES
255
243
  debug
@@ -54,9 +54,5 @@ require_relative '../../../procedures'
54
54
  # end
55
55
  #
56
56
  # # Used only to test internal server errors
57
- # procedure(:explode) do
58
- # params do
59
- # # No params
60
- # end
61
- # end
57
+ # procedure(:explode)
62
58
  # end
@@ -0,0 +1,199 @@
1
+ # Rails JSON-RPC Routing DSL
2
+
3
+ Demonstrates using the Rails routing DSL extension to route JSON-RPC methods to different controller actions for a
4
+ smart home control system.
5
+
6
+ ## Highlights
7
+
8
+ Uses the `jsonrpc` routing DSL to map JSON-RPC methods to Rails controller actions with clean, readable syntax:
9
+
10
+ ```ruby
11
+ class App < Rails::Application
12
+ # ...
13
+ routes.append do
14
+ jsonrpc '/' do
15
+ # Handle batch requests with a dedicated controller
16
+ batch to: 'batch#handle'
17
+
18
+ method 'on', to: 'main#on'
19
+ method 'off', to: 'main#off'
20
+
21
+ namespace 'lights' do
22
+ method 'on', to: 'lights#on' # becomes lights.on
23
+ method 'off', to: 'lights#off' # becomes lights.off
24
+ end
25
+
26
+ namespace 'climate' do
27
+ method 'on', to: 'climate#on' # becomes climate.on
28
+ method 'off', to: 'climate#off' # becomes climate.off
29
+
30
+ namespace 'fan' do
31
+ method 'on', to: 'fan#on' # becomes climate.fan.on
32
+ method 'off', to: 'fan#off' # becomes climate.fan.off
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ class MainController < ActionController::Base
40
+ def on
41
+ render jsonrpc: { device: 'main_system', status: 'on' }
42
+ end
43
+
44
+ def off
45
+ render jsonrpc: { device: 'main_system', status: 'off' }
46
+ end
47
+ end
48
+
49
+ class LightsController < ActionController::Base
50
+ def on
51
+ render jsonrpc: { device: 'lights', status: 'on' }
52
+ end
53
+
54
+ def off
55
+ render jsonrpc: { device: 'lights', status: 'off' }
56
+ end
57
+ end
58
+
59
+ class ClimateController < ActionController::Base
60
+ def on
61
+ render jsonrpc: { device: 'climate_system', status: 'on' }
62
+ end
63
+
64
+ def off
65
+ render jsonrpc: { device: 'climate_system', status: 'off' }
66
+ end
67
+ end
68
+
69
+ class FanController < ActionController::Base
70
+ def on
71
+ render jsonrpc: { device: 'fan', status: 'on' }
72
+ end
73
+
74
+ def off
75
+ render jsonrpc: { device: 'fan', status: 'off' }
76
+ end
77
+ end
78
+
79
+ class BatchController < ActionController::Base
80
+ def handle
81
+ # Process each request in the batch and collect results
82
+ results = jsonrpc_batch.process_each do |request_or_notification|
83
+ case request_or_notification.method
84
+ when 'on'
85
+ { device: 'main_system', status: 'on' }
86
+ when 'off'
87
+ { device: 'main_system', status: 'off' }
88
+ when 'lights.on'
89
+ { device: 'lights', status: 'on' }
90
+ when 'lights.off'
91
+ { device: 'lights', status: 'off' }
92
+ # ... handle other methods
93
+ end
94
+ end
95
+
96
+ render jsonrpc: results
97
+ end
98
+ end
99
+ ```
100
+
101
+ ## Running
102
+
103
+ ```sh
104
+ bundle exec rackup
105
+ ```
106
+
107
+ ## API
108
+
109
+ The server implements smart home controls with these procedures:
110
+
111
+ **Root Methods:**
112
+ - `on` - Turn home automation system on
113
+ - `off` - Turn home automation system off
114
+
115
+ **Lights Namespace:**
116
+ - `lights.on` - Turn lights on
117
+ - `lights.off` - Turn lights off
118
+
119
+ **Climate Namespace:**
120
+ - `climate.on` - Turn climate system on
121
+ - `climate.off` - Turn climate system off
122
+
123
+ **Climate Fan Namespace:**
124
+ - `climate.fan.on` - Turn fan on
125
+ - `climate.fan.off` - Turn fan off
126
+
127
+ **Batch Processing:**
128
+ - Batch requests are automatically routed to the `BatchController#handle` action
129
+ - The controller uses `jsonrpc_batch.process_each` to handle each request in the batch
130
+ - Responses are collected and returned as an array
131
+
132
+ ## Example Requests
133
+
134
+ Turn on the home automation system:
135
+ ```sh
136
+ curl -X POST http://localhost:9292 \
137
+ -H "Content-Type: application/json" \
138
+ -d '{"jsonrpc": "2.0", "method": "on", "params": {}, "id": 1}'
139
+ ```
140
+
141
+ Turn off the home automation system:
142
+ ```sh
143
+ curl -X POST http://localhost:9292 \
144
+ -H "Content-Type: application/json" \
145
+ -d '{"jsonrpc": "2.0", "method": "off", "params": {}, "id": 2}'
146
+ ```
147
+
148
+ Turn on lights:
149
+ ```sh
150
+ curl -X POST http://localhost:9292 \
151
+ -H "Content-Type: application/json" \
152
+ -d '{"jsonrpc": "2.0", "method": "lights.on", "params": {}, "id": 3}'
153
+ ```
154
+
155
+ Turn off the lights:
156
+ ```sh
157
+ curl -X POST http://localhost:9292 \
158
+ -H "Content-Type: application/json" \
159
+ -d '{"jsonrpc": "2.0", "method": "lights.off", "params": {}, "id": 4}'
160
+ ```
161
+
162
+ Turn on the climate system:
163
+ ```sh
164
+ curl -X POST http://localhost:9292 \
165
+ -H "Content-Type: application/json" \
166
+ -d '{"jsonrpc": "2.0", "method": "climate.on", "params": {}, "id": 5}'
167
+ ```
168
+
169
+ Turn off the climate system:
170
+ ```sh
171
+ curl -X POST http://localhost:9292 \
172
+ -H "Content-Type: application/json" \
173
+ -d '{"jsonrpc": "2.0", "method": "climate.off", "params": {}, "id": 6}'
174
+ ```
175
+
176
+ Turn on fan:
177
+ ```sh
178
+ curl -X POST http://localhost:9292 \
179
+ -H "Content-Type: application/json" \
180
+ -d '{"jsonrpc": "2.0", "method": "climate.fan.on", "params": {}, "id": 7}'
181
+ ```
182
+
183
+ Turn off fan:
184
+ ```sh
185
+ curl -X POST http://localhost:9292 \
186
+ -H "Content-Type: application/json" \
187
+ -d '{"jsonrpc": "2.0", "method": "climate.fan.off", "params": {}, "id": 8}'
188
+ ```
189
+
190
+ Batch request for evening routine:
191
+ ```sh
192
+ curl -X POST http://localhost:9292 \
193
+ -H "Content-Type: application/json" \
194
+ -d '[
195
+ {"jsonrpc": "2.0", "method": "off", "params": {}, "id": 9},
196
+ {"jsonrpc": "2.0", "method": "lights.off", "params": {}, "id": 10},
197
+ {"jsonrpc": "2.0", "method": "climate.off", "params": {}, "id": 11}
198
+ ]'
199
+ ```