node-red 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/CHANGELOG.md +11 -0
- data/README.md +10 -0
- data/examples/flow_management.rb +0 -38
- data/lib/node/red/client.rb +54 -18
- data/lib/node/red/errors.rb +22 -4
- data/lib/node/red/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9cc4a2ebc55b4f440b05fdb7209304381bafee347ef54257306bdf74b196963d
|
|
4
|
+
data.tar.gz: 151b1bb1140a55798308f499077ea575826010b8c2587a19efe277bbc6371ae0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 80f109e87d03189d1513944d074b02b7292988229a16c1b285f87e1abfbfb402a9f648a09d2458e5d07bd6cbd6e3168e31cda8c5897d007363f2cb10a643860e
|
|
7
|
+
data.tar.gz: 61951643190f2f562b81836600e84e81c843353a1798413eb1f8007a3d46b4be1bd3dbcf815728261bb51a699cf483a8bbcb9236b0c163ff1db4edae737d30f7
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
## [0.2.0] - 2025-10-28
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
- Structured error classes with contextual information (`status`, `code`, `details`)
|
|
5
|
+
- Extensive WebMock-backed RSpec coverage for every Admin API endpoint and error path
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- Improved error handling to map Node-RED response codes (400/401/404/409/5xx) to dedicated exceptions
|
|
9
|
+
- Enhanced JSON parsing safeguards on responses and errors for clearer diagnostics
|
|
10
|
+
- Updated README with advanced error-handling guidance
|
|
11
|
+
|
|
1
12
|
## [0.1.0] - 2025-10-28
|
|
2
13
|
|
|
3
14
|
- Initial release
|
data/README.md
CHANGED
|
@@ -140,6 +140,16 @@ rescue Node::Red::ApiError => e
|
|
|
140
140
|
end
|
|
141
141
|
```
|
|
142
142
|
|
|
143
|
+
Each error object carries contextual information to help with debugging:
|
|
144
|
+
|
|
145
|
+
```ruby
|
|
146
|
+
rescue Node::Red::ApiError => e
|
|
147
|
+
puts e.status # => 400, 401, 404, 409, 500, ...
|
|
148
|
+
puts e.code # => "invalid_request", "module_already_loaded", ... (may be nil)
|
|
149
|
+
puts e.details # => full parsed response body, if available
|
|
150
|
+
end
|
|
151
|
+
```
|
|
152
|
+
|
|
143
153
|
## Development
|
|
144
154
|
|
|
145
155
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/examples/flow_management.rb
CHANGED
|
@@ -56,44 +56,6 @@ begin
|
|
|
56
56
|
puts "=== Deploying Complete Flow Configuration ==="
|
|
57
57
|
|
|
58
58
|
# Create a simple flow with an inject and debug node
|
|
59
|
-
complete_flows = [
|
|
60
|
-
{
|
|
61
|
-
id: "flow1",
|
|
62
|
-
type: "tab",
|
|
63
|
-
label: "Test Flow"
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
id: "inject1",
|
|
67
|
-
type: "inject",
|
|
68
|
-
z: "flow1",
|
|
69
|
-
name: "Test Inject",
|
|
70
|
-
props: [{ p: "payload" }],
|
|
71
|
-
repeat: "",
|
|
72
|
-
crontab: "",
|
|
73
|
-
once: false,
|
|
74
|
-
onceDelay: 0.1,
|
|
75
|
-
topic: "",
|
|
76
|
-
payload: "Hello from Ruby!",
|
|
77
|
-
payloadType: "str",
|
|
78
|
-
x: 150,
|
|
79
|
-
y: 100
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
id: "debug1",
|
|
83
|
-
type: "debug",
|
|
84
|
-
z: "flow1",
|
|
85
|
-
name: "Test Debug",
|
|
86
|
-
active: true,
|
|
87
|
-
tosidebar: true,
|
|
88
|
-
console: false,
|
|
89
|
-
tostatus: false,
|
|
90
|
-
complete: "payload",
|
|
91
|
-
targetType: "msg",
|
|
92
|
-
x: 350,
|
|
93
|
-
y: 100,
|
|
94
|
-
wires: []
|
|
95
|
-
}
|
|
96
|
-
]
|
|
97
59
|
|
|
98
60
|
# NOTE: Be careful with deploy_flows as it replaces ALL flows
|
|
99
61
|
# Uncomment the following lines to deploy
|
data/lib/node/red/client.rb
CHANGED
|
@@ -286,34 +286,70 @@ module Node
|
|
|
286
286
|
def handle_response(response)
|
|
287
287
|
case response
|
|
288
288
|
when Net::HTTPSuccess
|
|
289
|
-
|
|
289
|
+
parse_response_body(response)
|
|
290
|
+
when Net::HTTPBadRequest
|
|
291
|
+
raise_api_error(BadRequestError, response)
|
|
290
292
|
when Net::HTTPUnauthorized
|
|
291
|
-
|
|
293
|
+
raise_api_error(AuthenticationError, response)
|
|
292
294
|
when Net::HTTPNotFound
|
|
293
|
-
|
|
295
|
+
raise_api_error(NotFoundError, response)
|
|
296
|
+
when Net::HTTPConflict
|
|
297
|
+
raise_api_error(ConflictError, response)
|
|
294
298
|
when Net::HTTPClientError
|
|
295
|
-
|
|
296
|
-
raise ApiError, "API error: #{response.code} #{error_message}"
|
|
299
|
+
raise_api_error(ApiError, response)
|
|
297
300
|
when Net::HTTPServerError
|
|
298
|
-
|
|
301
|
+
raise_api_error(ServerError, response)
|
|
299
302
|
else
|
|
300
|
-
|
|
303
|
+
raise_api_error(UnexpectedResponseError, response)
|
|
301
304
|
end
|
|
302
305
|
end
|
|
303
306
|
|
|
304
|
-
# Parse
|
|
307
|
+
# Parse a successful HTTP response body, ensuring JSON content
|
|
305
308
|
#
|
|
306
309
|
# @param response [Net::HTTPResponse] The HTTP response
|
|
307
|
-
# @return [
|
|
308
|
-
def
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
response.message
|
|
316
|
-
|
|
310
|
+
# @return [Hash, Array] Parsed JSON response or empty hash for blank body
|
|
311
|
+
def parse_response_body(response)
|
|
312
|
+
body = response.body
|
|
313
|
+
return {} if body.nil? || body.strip.empty?
|
|
314
|
+
|
|
315
|
+
JSON.parse(body)
|
|
316
|
+
rescue JSON::ParserError => e
|
|
317
|
+
raise UnexpectedResponseError.new(
|
|
318
|
+
"Invalid JSON response: #{e.message}",
|
|
319
|
+
status: response.code.to_i,
|
|
320
|
+
details: { body: body }
|
|
321
|
+
)
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
# Raise a structured API error based on the HTTP response
|
|
325
|
+
#
|
|
326
|
+
# @param error_class [Class<ApiError>] The error class to raise
|
|
327
|
+
# @param response [Net::HTTPResponse] The HTTP response
|
|
328
|
+
# @raise [ApiError]
|
|
329
|
+
def raise_api_error(error_class, response)
|
|
330
|
+
message, error_code, details = extract_error_details(response)
|
|
331
|
+
raise error_class.new(
|
|
332
|
+
message,
|
|
333
|
+
status: response.code.to_i,
|
|
334
|
+
code: error_code,
|
|
335
|
+
details: details
|
|
336
|
+
)
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
# Extract error details from a failed HTTP response
|
|
340
|
+
#
|
|
341
|
+
# @param response [Net::HTTPResponse] The HTTP response
|
|
342
|
+
# @return [Array(String, String, Hash, nil)] message, error code and raw details
|
|
343
|
+
def extract_error_details(response)
|
|
344
|
+
body = response.body
|
|
345
|
+
return [response.message, nil, nil] if body.nil? || body.strip.empty?
|
|
346
|
+
|
|
347
|
+
data = JSON.parse(body)
|
|
348
|
+
message = data["message"] || data["error"] || response.message
|
|
349
|
+
error_code = data["code"]
|
|
350
|
+
[message, error_code, data]
|
|
351
|
+
rescue JSON::ParserError
|
|
352
|
+
[response.message, nil, { raw_body: body }]
|
|
317
353
|
end
|
|
318
354
|
end
|
|
319
355
|
end
|
data/lib/node/red/errors.rb
CHANGED
|
@@ -2,16 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
module Node
|
|
4
4
|
module Red
|
|
5
|
-
# Base error class for Node-RED API errors
|
|
6
|
-
class ApiError < StandardError
|
|
5
|
+
# Base error class for Node-RED API errors that keeps rich context
|
|
6
|
+
class ApiError < StandardError
|
|
7
|
+
attr_reader :status, :code, :details
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
def initialize(message, status:, code: nil, details: nil)
|
|
10
|
+
super(message)
|
|
11
|
+
@status = status
|
|
12
|
+
@code = code
|
|
13
|
+
@details = details
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Raised when the request is malformed (HTTP 400)
|
|
18
|
+
class BadRequestError < ApiError; end
|
|
19
|
+
|
|
20
|
+
# Raised when authentication fails (HTTP 401)
|
|
9
21
|
class AuthenticationError < ApiError; end
|
|
10
22
|
|
|
11
|
-
# Raised when a resource is not found
|
|
23
|
+
# Raised when a resource is not found (HTTP 404)
|
|
12
24
|
class NotFoundError < ApiError; end
|
|
13
25
|
|
|
26
|
+
# Raised when there is a version mismatch (HTTP 409)
|
|
27
|
+
class ConflictError < ApiError; end
|
|
28
|
+
|
|
14
29
|
# Raised when the server returns a 5xx error
|
|
15
30
|
class ServerError < ApiError; end
|
|
31
|
+
|
|
32
|
+
# Raised when the response type is unexpected
|
|
33
|
+
class UnexpectedResponseError < ApiError; end
|
|
16
34
|
end
|
|
17
35
|
end
|
data/lib/node/red/version.rb
CHANGED