-
Notifications
You must be signed in to change notification settings - Fork 81
Enhance Message Validation #1341
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -60,6 +60,29 @@ The `action_client/` directory contains examples of nodes that send goals to act | |||
| - Cleanup and shutdown handling | ||||
| - **Run Command**: `node action_client/action-client-cancel-example.js` | ||||
|
|
||||
| #### 3. Action Client Validation (`action-client-validation-example.js`) | ||||
|
|
||||
| **Purpose**: Demonstrates goal validation features for action clients. | ||||
|
|
||||
| - **Action Type**: `action_tutorials_interfaces/action/Fibonacci` | ||||
| - **Action Name**: `fibonacci` | ||||
| - **Functionality**: | ||||
| - Schema introspection for action goal types | ||||
| - Client-level validation with `validateGoals: true` option | ||||
| - Per-goal validation override with `{ validate: true/false }` | ||||
| - Strict mode validation for detecting unknown fields | ||||
| - Reusable goal validators with `createMessageValidator()` | ||||
| - Error handling with `MessageValidationError` | ||||
| - **Features**: | ||||
| - **Goal Validation**: Catch invalid goals before sending to action server | ||||
| - **Schema Introspection**: Use `getMessageSchema()` to inspect goal structure | ||||
| - **Dynamic Toggle**: Enable/disable validation with `setValidation()` | ||||
| - **Detailed Errors**: Field-level validation issues with expected vs received types | ||||
| - **Strict Mode**: Detect extra fields that don't belong in the goal | ||||
| - **Reusable Validators**: Create validators for repeated goal validation | ||||
| - **Run Command**: `node action_client/action-client-validation-example.js` | ||||
| - **Note**: Standalone example - demonstrates validation errors without requiring a running action server | ||||
|
|
||||
| ### Action Server Examples | ||||
|
|
||||
| The `action_server/` directory contains examples of nodes that provide action services: | ||||
|
|
@@ -216,6 +239,8 @@ int32[] sequence | |||
| - **Feedback Handling**: Processing incremental updates during execution | ||||
| - **Result Processing**: Handling final results and status | ||||
| - **Goal Cancellation**: Canceling active goals with `cancelGoal()` | ||||
| - **Goal Validation**: Pre-send validation with `validateGoals` option and `MessageValidationError` | ||||
| - **Schema Introspection**: Programmatic access to action goal schemas | ||||
|
|
||||
| #### Action Server Concepts | ||||
|
|
||||
|
|
@@ -260,19 +285,16 @@ All examples use ES6 classes to encapsulate action functionality: | |||
| ### Common Issues | ||||
|
|
||||
| 1. **Action Server Not Available**: | ||||
|
|
||||
| - Ensure action server is running before starting client | ||||
| - Check that both use the same action name (`fibonacci`) | ||||
| - Verify action type matches (`test_msgs/action/Fibonacci`) | ||||
|
|
||||
|
||||
Copilot
AI
Dec 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change removes a blank line that appears to be unrelated to the message validation feature. This formatting change should not be included in this PR as it modifies content outside the scope of the PR's purpose (message validation).
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| // Copyright (c) 2025 Mahmoud Alghalayini. All rights reserved. | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| 'use strict'; | ||
|
|
||
| const rclnodejs = require('../../../index.js'); | ||
|
|
||
| async function main() { | ||
| await rclnodejs.init(); | ||
| const node = rclnodejs.createNode('action_client_validation_example_node'); | ||
|
|
||
| const Fibonacci = rclnodejs.require( | ||
| 'action_tutorials_interfaces/action/Fibonacci' | ||
| ); | ||
|
|
||
| const actionClient = new rclnodejs.ActionClient( | ||
| node, | ||
| 'action_tutorials_interfaces/action/Fibonacci', | ||
| 'fibonacci', | ||
| { validateGoals: true } | ||
| ); | ||
|
|
||
| const validGoal = { order: 10 }; | ||
| console.log( | ||
| 'Valid goal:', | ||
| rclnodejs.validateMessage(validGoal, Fibonacci.Goal).valid | ||
| ); | ||
|
|
||
| try { | ||
| await actionClient.sendGoal({ order: 'invalid' }); | ||
| } catch (error) { | ||
| if (error instanceof rclnodejs.MessageValidationError) { | ||
| console.log('Caught validation error:', error.issues[0].problem); | ||
| } | ||
| } | ||
|
|
||
| actionClient.destroy(); | ||
| node.destroy(); | ||
| rclnodejs.shutdown(); | ||
| } | ||
|
|
||
| main(); |
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -31,7 +31,6 @@ Graph introspection allows you to: | |||
| This example creates a complete ROS 2 system with multiple nodes and then introspects the graph to display: | ||||
|
|
||||
|
||||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -355,19 +355,16 @@ Multiple lifecycle nodes can be coordinated using external lifecycle managers: | |||
| ### Common Issues | ||||
|
|
||||
|
||||
Copilot
AI
Dec 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change removes a blank line that appears to be unrelated to the message validation feature. This formatting change should not be included in this PR as it modifies content outside the scope of the PR's purpose (message validation).
Copilot
AI
Dec 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change removes a blank line that appears to be unrelated to the message validation feature. This formatting change should not be included in this PR as it modifies content outside the scope of the PR's purpose (message validation).
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -332,19 +332,16 @@ while (running) { | |||
| ### Common Issues | ||||
|
|
||||
|
||||
Copilot
AI
Dec 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change removes a blank line that appears to be unrelated to the message validation feature. This formatting change should not be included in this PR as it modifies content outside the scope of the PR's purpose (message validation).
Copilot
AI
Dec 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change removes a blank line that appears to be unrelated to the message validation feature. This formatting change should not be included in this PR as it modifies content outside the scope of the PR's purpose (message validation).
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| // Copyright (c) 2025 Mahmoud Alghalayini. All rights reserved. | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| 'use strict'; | ||
|
|
||
| const rclnodejs = require('../../../index.js'); | ||
|
|
||
| async function main() { | ||
| await rclnodejs.init(); | ||
| const node = rclnodejs.createNode('client_validation_example_node'); | ||
|
|
||
| const client = node.createClient( | ||
| 'example_interfaces/srv/AddTwoInts', | ||
| 'add_two_ints', | ||
| { validateRequests: true } | ||
| ); | ||
|
|
||
| const validRequest = { a: BigInt(5), b: BigInt(10) }; | ||
| console.log( | ||
| 'Valid request:', | ||
| rclnodejs.validateMessage(validRequest, client.typeClass.Request).valid | ||
| ); | ||
|
|
||
| try { | ||
| client.sendRequest({ a: 'invalid', b: BigInt(10) }, () => {}); | ||
| } catch (error) { | ||
| if (error instanceof rclnodejs.MessageValidationError) { | ||
| console.log('Caught validation error:', error.issues[0].problem); | ||
| } | ||
| } | ||
|
|
||
| node.destroy(); | ||
| rclnodejs.shutdown(); | ||
| } | ||
|
|
||
| main(); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| // Copyright (c) 2025 Mahmoud Alghalayini. All rights reserved. | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| 'use strict'; | ||
|
|
||
| const rclnodejs = require('../../../index.js'); | ||
|
|
||
| rclnodejs.init().then(() => { | ||
| const node = rclnodejs.createNode('publisher_validation_example_node'); | ||
|
|
||
| const publisher = node.createPublisher('std_msgs/msg/String', 'topic', { | ||
| validateMessages: true, | ||
| }); | ||
|
|
||
| publisher.publish({ data: 'Hello ROS' }); | ||
| console.log('Published valid message'); | ||
|
|
||
| try { | ||
| publisher.publish({ data: 12345 }); | ||
| } catch (error) { | ||
| if (error instanceof rclnodejs.MessageValidationError) { | ||
| console.log('Caught validation error:', error.issues[0].problem); | ||
| } | ||
| } | ||
|
|
||
| node.destroy(); | ||
| rclnodejs.shutdown(); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change removes a blank line that appears to be unrelated to the message validation feature. This formatting change should not be included in this PR as it modifies content outside the scope of the PR's purpose (message validation).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do I need to revert these removed lines? @minggangw
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, by the way I noticed that these changes in the readme happens when I do
npm run format