Skip to content

Commit f838959

Browse files
Enhance Message Validation
1 parent fb4597a commit f838959

26 files changed

+1787
-31
lines changed

CONTRIBUTORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
- Add ParameterClient for external parameter access
4545
- Add structured error handling with class error hierarchy
4646
- Add ParameterWatcher for real-time parameter monitoring
47+
- Enhance Message Validation
4748

4849
- **[Martins Mozeiko](https://github.com/martins-mozeiko)**
4950
- QoS new/delete fix

example/actions/README.md

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,29 @@ The `action_client/` directory contains examples of nodes that send goals to act
6060
- Cleanup and shutdown handling
6161
- **Run Command**: `node action_client/action-client-cancel-example.js`
6262

63+
#### 3. Action Client Validation (`action-client-validation-example.js`)
64+
65+
**Purpose**: Demonstrates goal validation features for action clients.
66+
67+
- **Action Type**: `action_tutorials_interfaces/action/Fibonacci`
68+
- **Action Name**: `fibonacci`
69+
- **Functionality**:
70+
- Schema introspection for action goal types
71+
- Client-level validation with `validateGoals: true` option
72+
- Per-goal validation override with `{ validate: true/false }`
73+
- Strict mode validation for detecting unknown fields
74+
- Reusable goal validators with `createMessageValidator()`
75+
- Error handling with `MessageValidationError`
76+
- **Features**:
77+
- **Goal Validation**: Catch invalid goals before sending to action server
78+
- **Schema Introspection**: Use `getMessageSchema()` to inspect goal structure
79+
- **Dynamic Toggle**: Enable/disable validation with `setValidation()`
80+
- **Detailed Errors**: Field-level validation issues with expected vs received types
81+
- **Strict Mode**: Detect extra fields that don't belong in the goal
82+
- **Reusable Validators**: Create validators for repeated goal validation
83+
- **Run Command**: `node action_client/action-client-validation-example.js`
84+
- **Note**: Standalone example - demonstrates validation errors without requiring a running action server
85+
6386
### Action Server Examples
6487

6588
The `action_server/` directory contains examples of nodes that provide action services:
@@ -216,6 +239,8 @@ int32[] sequence
216239
- **Feedback Handling**: Processing incremental updates during execution
217240
- **Result Processing**: Handling final results and status
218241
- **Goal Cancellation**: Canceling active goals with `cancelGoal()`
242+
- **Goal Validation**: Pre-send validation with `validateGoals` option and `MessageValidationError`
243+
- **Schema Introspection**: Programmatic access to action goal schemas
219244

220245
#### Action Server Concepts
221246

@@ -260,19 +285,16 @@ All examples use ES6 classes to encapsulate action functionality:
260285
### Common Issues
261286

262287
1. **Action Server Not Available**:
263-
264288
- Ensure action server is running before starting client
265289
- Check that both use the same action name (`fibonacci`)
266290
- Verify action type matches (`test_msgs/action/Fibonacci`)
267291

268292
2. **Goal Not Accepted**:
269-
270293
- Check server's `goalCallback` return value
271294
- Verify goal message structure is correct
272295
- Ensure server is properly initialized
273296

274297
3. **Missing Feedback**:
275-
276298
- Confirm feedback callback is properly bound
277299
- Check server's `publishFeedback()` calls
278300
- Verify feedback message structure
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright (c) 2025 Mahmoud Alghalayini. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
'use strict';
16+
17+
const rclnodejs = require('../../../index.js');
18+
19+
async function main() {
20+
await rclnodejs.init();
21+
const node = rclnodejs.createNode('action_client_validation_example_node');
22+
23+
const Fibonacci = rclnodejs.require(
24+
'action_tutorials_interfaces/action/Fibonacci'
25+
);
26+
27+
const actionClient = new rclnodejs.ActionClient(
28+
node,
29+
'action_tutorials_interfaces/action/Fibonacci',
30+
'fibonacci',
31+
{ validateGoals: true }
32+
);
33+
34+
const validGoal = { order: 10 };
35+
console.log(
36+
'Valid goal:',
37+
rclnodejs.validateMessage(validGoal, Fibonacci.Goal).valid
38+
);
39+
40+
try {
41+
await actionClient.sendGoal({ order: 'invalid' });
42+
} catch (error) {
43+
if (error instanceof rclnodejs.MessageValidationError) {
44+
console.log('Caught validation error:', error.issues[0].problem);
45+
}
46+
}
47+
48+
actionClient.destroy();
49+
node.destroy();
50+
rclnodejs.shutdown();
51+
}
52+
53+
main();

example/graph/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ Graph introspection allows you to:
3131
This example creates a complete ROS 2 system with multiple nodes and then introspects the graph to display:
3232

3333
1. **Node Creation**: Creates several nodes with different communication patterns:
34-
3534
- `publisher_node` (namespace: `ns1`) - publishes to a topic
3635
- `subscriber_node` (namespace: `ns1`) - subscribes to a topic
3736
- `service_node` (namespace: `ns1`) - provides a service

example/lifecycle/README.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -355,19 +355,16 @@ Multiple lifecycle nodes can be coordinated using external lifecycle managers:
355355
### Common Issues
356356

357357
1. **Publisher Not Publishing**:
358-
359358
- Ensure lifecycle publisher is activated in `onActivate()`
360359
- Check that node is in active state
361360
- Verify publisher is created in `onConfigure()`
362361

363362
2. **Timer Not Working**:
364-
365363
- Create timer in `onActivate()`, not `onConfigure()`
366364
- Cancel timer in `onDeactivate()`
367365
- Check timer interval format (BigInt nanoseconds)
368366

369367
3. **State Transition Failures**:
370-
371368
- Ensure callbacks return appropriate return codes
372369
- Check for exceptions in callback implementations
373370
- Verify resource cleanup in deactivate/shutdown

example/rate/README.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -332,19 +332,16 @@ while (running) {
332332
### Common Issues
333333

334334
1. **Rate Drift**:
335-
336335
- Processing time exceeds rate period
337336
- Solution: Optimize processing or reduce rate frequency
338337
- Monitor actual vs. target frequency
339338

340339
2. **Missed Messages**:
341-
342340
- Rate limiting causes message drops
343341
- Expected behavior in the example (only every 200th message processed)
344342
- Use `ros2 topic echo` to see all messages
345343

346344
3. **High CPU Usage**:
347-
348345
- Rate loop running too fast for processing capacity
349346
- Solution: Reduce rate frequency or optimize processing
350347
- Monitor system resource usage

example/services/README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,28 @@ ROS 2 services provide a request-response communication pattern where clients se
7070
- **TypeScript Ready**: Full type safety with comprehensive TypeScript definitions
7171
- **Run Command**: `node example/services/client/async-client-example.js`
7272

73+
#### Service Client Validation (`client/client-validation-example.js`)
74+
75+
**Purpose**: Demonstrates request validation features for service clients.
76+
77+
- **Service Type**: `example_interfaces/srv/AddTwoInts`
78+
- **Service Name**: `add_two_ints`
79+
- **Functionality**:
80+
- Schema introspection for service request types
81+
- Client-level validation with `validateRequests: true` option
82+
- Per-request validation override with `{ validate: true/false }`
83+
- Strict mode validation for detecting unknown fields
84+
- Async request validation with `sendRequestAsync()`
85+
- Error handling with `MessageValidationError`
86+
- **Features**:
87+
- **Request Validation**: Catch invalid requests before sending to service
88+
- **Schema Introspection**: Use `getMessageSchema()` to inspect request structure
89+
- **Dynamic Toggle**: Enable/disable validation with `setValidation()`
90+
- **Detailed Errors**: Field-level validation issues with expected vs received types
91+
- **Strict Mode**: Detect extra fields that don't belong in the request
92+
- **Run Command**: `node example/services/client/client-validation-example.js`
93+
- **Note**: Standalone example - demonstrates validation errors without requiring a running service
94+
7395
**Key API Differences**:
7496

7597
```javascript
@@ -333,6 +355,8 @@ This script automatically starts the service, tests the client, and cleans up.
333355
- **Error Handling**: Proper error handling with try/catch blocks and specific error types (async only)
334356
- **Timeout Management**: Built-in timeout support to prevent hanging requests (async only)
335357
- **Request Cancellation**: AbortController support for user-cancellable operations (async only)
358+
- **Request Validation**: Pre-send validation with `validateRequests` option and `MessageValidationError`
359+
- **Schema Introspection**: Programmatic access to service request/response schemas
336360
- **Resource Management**: Proper node shutdown and cleanup
337361
- **Data Analysis**: Processing and interpreting received data
338362
- **Visualization**: Converting data to human-readable formats
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (c) 2025 Mahmoud Alghalayini. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
'use strict';
16+
17+
const rclnodejs = require('../../../index.js');
18+
19+
async function main() {
20+
await rclnodejs.init();
21+
const node = rclnodejs.createNode('client_validation_example_node');
22+
23+
const client = node.createClient(
24+
'example_interfaces/srv/AddTwoInts',
25+
'add_two_ints',
26+
{ validateRequests: true }
27+
);
28+
29+
const validRequest = { a: BigInt(5), b: BigInt(10) };
30+
console.log(
31+
'Valid request:',
32+
rclnodejs.validateMessage(validRequest, client.typeClass.Request).valid
33+
);
34+
35+
try {
36+
client.sendRequest({ a: 'invalid', b: BigInt(10) }, () => {});
37+
} catch (error) {
38+
if (error instanceof rclnodejs.MessageValidationError) {
39+
console.log('Caught validation error:', error.issues[0].problem);
40+
}
41+
}
42+
43+
node.destroy();
44+
rclnodejs.shutdown();
45+
}
46+
47+
main();

example/topics/README.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,27 @@ The `publisher/` directory contains examples of nodes that publish messages to t
6969
- **Run Command**: `node publisher/publisher-raw-message.js`
7070
- **Pair**: Works with `subscription-raw-message.js`
7171

72+
### 7. Publisher Validation (`publisher-validation-example.js`)
73+
74+
**Purpose**: Demonstrates message validation features for publishers.
75+
76+
- **Message Type**: `std_msgs/msg/String`, `geometry_msgs/msg/Twist`
77+
- **Topics**: Various validation test topics
78+
- **Functionality**:
79+
- Schema introspection with `getMessageSchema()`, `getFieldNames()`, `getFieldType()`
80+
- Publisher-level validation with `validateMessages: true` option
81+
- Per-publish validation override with `{ validate: true/false }`
82+
- Strict mode validation for unknown fields
83+
- Nested message validation (Twist with Vector3)
84+
- Reusable validators with `createMessageValidator()`
85+
- Error handling with `MessageValidationError`
86+
- **Features**:
87+
- Catch invalid messages before publishing
88+
- Dynamic validation toggle with `setValidation()`
89+
- Detailed error reports with field-level issues
90+
- **Run Command**: `node publisher/publisher-validation-example.js`
91+
- **Note**: Standalone example - no subscriber required
92+
7293
## Subscriber Examples
7394

7495
The `subscriber/` directory contains examples of nodes that subscribe to topics:
@@ -214,7 +235,8 @@ Several examples work together to demonstrate complete communication:
214235
- **Service Events**: Monitoring service interactions
215236
- **Multi-dimensional Arrays**: Complex data structures with layout information
216237
- **Message Serialization**: TypedArray handling and JSON-safe conversion for web applications
217-
- **Validation**: Name and topic validation utilities
238+
- **Name Validation**: Topic names, node names, and namespace validation utilities
239+
- **Message Validation**: Schema introspection and pre-publish message validation with detailed error reporting
218240

219241
## Notes
220242

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright (c) 2025 Mahmoud Alghalayini. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
'use strict';
16+
17+
const rclnodejs = require('../../../index.js');
18+
19+
rclnodejs.init().then(() => {
20+
const node = rclnodejs.createNode('publisher_validation_example_node');
21+
22+
const publisher = node.createPublisher('std_msgs/msg/String', 'topic', {
23+
validateMessages: true,
24+
});
25+
26+
publisher.publish({ data: 'Hello ROS' });
27+
console.log('Published valid message');
28+
29+
try {
30+
publisher.publish({ data: 12345 });
31+
} catch (error) {
32+
if (error instanceof rclnodejs.MessageValidationError) {
33+
console.log('Caught validation error:', error.issues[0].problem);
34+
}
35+
}
36+
37+
node.destroy();
38+
rclnodejs.shutdown();
39+
});

0 commit comments

Comments
 (0)