Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions postman/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ This folder contains Postman collections for testing the ROS 2 Medkit Gateway RE
Includes below endpoints:
- ✅ GET `/` - Gateway info
- ✅ GET `/areas` - List all areas
- ✅ GET `/components` - List all components

## Quick Start

Expand Down Expand Up @@ -49,6 +50,10 @@ ros2 launch ros2_medkit_gateway demo_nodes.launch.py
6. Click **Send**
7. You should see areas: `[{"id": "powertrain", ...}, {"id": "chassis", ...}, ...]`

8. Click **"GET List Components"**
9. Click **Send**
10. You should see components: `[{"id": "temp_sensor", "namespace": "/powertrain/engine", ...}, ...]`

## API Variables

The environment includes:
Expand Down
20 changes: 19 additions & 1 deletion postman/collections/ros2-medkit-gateway.postman_collection.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"info": {
"name": "ROS 2 Medkit Gateway API",
"description": "Minimal collection: GET / and GET /areas endpoints only",
"description": "Collection for ROS 2 Medkit Gateway REST API endpoints",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
Expand Down Expand Up @@ -43,6 +43,24 @@
"description": "List all discovered areas (powertrain, chassis, body, root)"
},
"response": []
},
{
"name": "GET List Components",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/components",
"host": [
"{{base_url}}"
],
"path": [
"components"
]
},
"description": "List all discovered components across all areas. Returns component metadata including id, namespace, fqn, type, and parent area."
},
"response": []
}
]
}
Expand Down
66 changes: 65 additions & 1 deletion src/ros2_medkit_gateway/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,75 @@ The ROS 2 Medkit Gateway exposes ROS 2 system information and data through a RES

## Endpoints

Current available endpoints:
### Discovery Endpoints

- `GET /health` - Health check endpoint (returns healthy status)
- `GET /` - Gateway status and version information
- `GET /areas` - List all discovered areas (powertrain, chassis, body, root)
- `GET /components` - List all discovered components across all areas

### API Reference

#### GET /areas

Lists all discovered areas in the system.

**Example:**
```bash
curl http://localhost:8080/areas
```

**Response:**
```json
[
{
"id": "powertrain",
"namespace": "/powertrain",
"type": "Area"
},
{
"id": "chassis",
"namespace": "/chassis",
"type": "Area"
}
]
```

#### GET /components

Lists all discovered components across all areas.

**Example:**
```bash
curl http://localhost:8080/components
```

**Response:**
```json
[
{
"id": "temp_sensor",
"namespace": "/powertrain/engine",
"fqn": "/powertrain/engine/temp_sensor",
"type": "Component",
"area": "powertrain"
},
{
"id": "rpm_sensor",
"namespace": "/powertrain/engine",
"fqn": "/powertrain/engine/rpm_sensor",
"type": "Component",
"area": "powertrain"
}
]
```

**Response Fields:**
- `id` - Component name (node name)
- `namespace` - ROS 2 namespace where the component is running
- `fqn` - Fully qualified name (namespace + node name)
- `type` - Always "Component"
- `area` - Parent area this component belongs to

## Quick Start

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class RESTServer {
void handle_health(const httplib::Request& req, httplib::Response& res);
void handle_root(const httplib::Request& req, httplib::Response& res);
void handle_list_areas(const httplib::Request& req, httplib::Response& res);
void handle_list_components(const httplib::Request& req, httplib::Response& res);

GatewayNode* node_;
std::string host_;
Expand Down
31 changes: 31 additions & 0 deletions src/ros2_medkit_gateway/src/rest_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ void RESTServer::setup_routes() {
server_->Get("/areas", [this](const httplib::Request& req, httplib::Response& res) {
handle_list_areas(req, res);
});

// Components
server_->Get("/components", [this](const httplib::Request& req, httplib::Response& res) {
handle_list_components(req, res);
});
}

void RESTServer::start() {
Expand Down Expand Up @@ -129,4 +134,30 @@ void RESTServer::handle_list_areas(const httplib::Request& req, httplib::Respons
}
}

void RESTServer::handle_list_components(const httplib::Request& req, httplib::Response& res) {
(void)req; // Unused parameter

try {
const auto cache = node_->get_entity_cache();

json components_json = json::array();
for (const auto& component : cache.components) {
components_json.push_back(component.to_json());
}

res.set_content(components_json.dump(2), "application/json");
} catch (const std::exception& e) {
res.status = 500;
res.set_content(
json{{"error", "Internal server error"}}.dump(),
"application/json"
);
RCLCPP_ERROR(
rclcpp::get_logger("rest_server"),
"Error in handle_list_components: %s",
e.what()
);
}
}

} // namespace ros2_medkit_gateway
26 changes: 25 additions & 1 deletion src/ros2_medkit_gateway/test/test_integration.test.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,31 @@ def test_02_list_areas(self):
self.assertIn('root', area_ids)
print(f'✓ Areas test passed: {len(areas)} areas discovered')

def test_21_automotive_areas_discovery(self):
def test_03_list_components(self):
"""Test GET /components returns all discovered components."""
components = self._get_json('/components')
self.assertIsInstance(components, list)
# Should have at least 7 demo nodes + gateway node
self.assertGreaterEqual(len(components), 7)

# Verify response structure - all components should have required fields
for component in components:
self.assertIn('id', component)
self.assertIn('namespace', component)
self.assertIn('fqn', component)
self.assertIn('type', component)
self.assertIn('area', component)
self.assertEqual(component['type'], 'Component')

# Verify some expected component IDs are present
component_ids = [comp['id'] for comp in components]
self.assertIn('temp_sensor', component_ids)
self.assertIn('rpm_sensor', component_ids)
self.assertIn('pressure_sensor', component_ids)

print(f'✓ Components test passed: {len(components)} components discovered')

def test_04_automotive_areas_discovery(self):
"""Test that automotive areas are properly discovered."""
areas = self._get_json('/areas')
area_ids = [area['id'] for area in areas]
Expand Down
Loading