Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
53 changes: 46 additions & 7 deletions docs/getting_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ Response:

Topic paths use URL encoding: ``/`` becomes ``%2F``

Step 5: Call Services
---------------------
Step 5: Call Services and Actions
----------------------------------

The operations endpoints let you call ROS 2 services and actions.

Expand All @@ -171,11 +171,13 @@ The operations endpoints let you call ROS 2 services and actions.

curl http://localhost:8080/api/v1/components/calibration/operations

**Call a service:**
**Call a service (synchronous execution):**

Services return immediately with status ``200 OK``:

.. code-block:: bash

curl -X POST http://localhost:8080/api/v1/components/calibration/operations/calibrate \
curl -X POST http://localhost:8080/api/v1/components/calibration/operations/calibrate/executions \
-H "Content-Type: application/json" \
-d '{}'

Expand All @@ -184,11 +186,48 @@ Response:
.. code-block:: json

{
"status": "success",
"kind": "service",
"response": {"success": true, "message": "Calibration triggered"}
"id": "exec-12345",
"status": "completed",
"capability": "execute",
"x-medkit": {
"kind": "service",
"response": {"success": true, "message": "Calibration triggered"}
}
}

**Send an action goal (asynchronous execution):**

Actions return ``202 Accepted`` immediately with an execution ID for polling:

.. code-block:: bash

curl -X POST http://localhost:8080/api/v1/apps/long_calibration/operations/long_calibration/executions \
-H "Content-Type: application/json" \
-d '{"parameters": {"order": 5}}'

Response (202 Accepted):

.. code-block:: json

{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "running"
}

**Poll action status:**

.. code-block:: bash

curl http://localhost:8080/api/v1/apps/long_calibration/operations/long_calibration/executions/a1b2c3d4-e5f6-7890-abcd-ef1234567890

**Cancel a running action:**

.. code-block:: bash

curl -X DELETE http://localhost:8080/api/v1/apps/long_calibration/operations/long_calibration/executions/a1b2c3d4-e5f6-7890-abcd-ef1234567890

Returns ``204 No Content`` on success.

Step 6: Manage Parameters
-------------------------

Expand Down
120 changes: 118 additions & 2 deletions docs/requirements/specs/operations.rst
Original file line number Diff line number Diff line change
@@ -1,52 +1,168 @@
Operations
==========

This section describes the operations API for executing
diagnostic operations such as ROS 2 services and actions.

Operations Overview
-------------------

An **operation resource** represents an executable diagnostic object. In ros2_medkit,
operations map to:

- **ROS 2 Services** - Synchronous operations that return immediately with results
- **ROS 2 Actions** - Asynchronous operations that return an execution ID for status tracking

The API supports:

- **Synchronous execution**: Service calls return after the operation completes
- **Asynchronous execution**: Action goals return immediately with an execution ID; clients poll for status

.. req:: GET /{entity}/operations
:id: REQ_INTEROP_033
:status: open
:tags: Operations

The endpoint shall list all supported operations that can be executed on the addressed entity.

**Response attributes:**

- ``items``: Array of OperationDescription objects
- ``id``: Unique identifier for the operation (M)
- ``name``: Operation name (O)
- ``proximity_proof_required``: If true, requires co-location proof (M, always false for ROS 2)
- ``asynchronous_execution``: If true, operation is asynchronous (M; true for actions, false for services)
- ``x-medkit``: ROS 2-specific metadata (ros2_kind, ros2_service/ros2_action, ros2_type, type_info)

.. req:: GET /{entity}/operations/{op-id}
:id: REQ_INTEROP_034
:status: open
:tags: Operations

The endpoint shall return the definition and metadata of the addressed operation.

**Response attributes:**

- ``item``: OperationDescription object with full operation details
- ``modes``: Mode requirements for execution (C, not applicable for ROS 2)

.. req:: POST /{entity}/operations/{op-id}/executions
:id: REQ_INTEROP_035
:status: open
:tags: Operations

The endpoint shall start a new execution of the addressed operation on the entity.

**Request body:**

- ``timeout``: Timeout in seconds (O)
- ``parameters``: Operation parameters (C, maps to service request or action goal)

**Response for synchronous execution (200 OK):**

- ``parameters``: Response data from service call

**Response for asynchronous execution (202 Accepted):**

- ``id``: Execution ID (goal_id) for monitoring
- ``status``: ExecutionStatus (running, completed, failed, stopped)
- Location header pointing to execution status endpoint

.. req:: GET /{entity}/operations/{op-id}/executions
:id: REQ_INTEROP_036
:status: open
:tags: Operations

The endpoint shall list active and past executions of the addressed operation.

**Response:**

- ``items``: Array of objects with ``id`` field containing execution identifiers

.. req:: GET /{entity}/operations/{op-id}/executions/{exec-id}
:id: REQ_INTEROP_037
:status: open
:tags: Operations

The endpoint shall return the current status and any result details of the addressed operation execution.

**Response:**

- ``status``: ExecutionStatus (running, completed, failed, stopped)
- ``capability``: Currently executing capability (execute, stop, etc.)
- ``parameters``: Response parameters or feedback data (C)
- ``x-medkit``: ROS 2-specific details (goal_id, ros2_status, ros2_action, ros2_type)

.. req:: PUT /{entity}/operations/{op-id}/executions/{exec-id}
:id: REQ_INTEROP_038
:status: open
:tags: Operations

The endpoint shall control the addressed operation execution (e.g. execute, freeze, reset or other supported capabilities) and may update execution parameters, if supported.
The endpoint shall control the addressed operation execution (e.g. execute, freeze, reset, stop)
and may update execution parameters, if supported.

**Request body:**

- ``capability``: Capability to execute (M) - supported: ``stop``
- ``timeout``: Timeout in seconds (O)
- ``parameters``: Updated parameters (C)

**Supported capabilities for ROS 2 actions:**

- ``stop``: Maps to ROS 2 action cancel - stops the running action
- ``execute``, ``freeze``, ``reset``: Not supported (returns 400 Bad Request)

**Response:**

- ``id``: Execution ID
- ``status``: Updated execution status
- Location header for status polling

.. req:: DELETE /{entity}/operations/{op-id}/executions/{exec-id}
:id: REQ_INTEROP_039
:status: open
:tags: Operations

The endpoint shall terminate the addressed operation execution (if still running) and remove its execution resource, if cancellation is supported.
The endpoint shall terminate the addressed operation execution (if still running) and remove
its execution resource, if cancellation is supported.

**Response:** 204 No Content on successful termination

ExecutionStatus Values
----------------------

The SOVD ExecutionStatus type maps to ROS 2 action statuses:

+---------------+-----------------------------------+
| SOVD Status | ROS 2 Action Status |
+===============+===================================+
| running | ACCEPTED, EXECUTING, CANCELING |
+---------------+-----------------------------------+
| completed | SUCCEEDED |
+---------------+-----------------------------------+
| failed | CANCELED, ABORTED |
+---------------+-----------------------------------+
| stopped | (not directly mapped) |
+---------------+-----------------------------------+

Capability Mapping
------------------

SOVD operation capabilities map to ROS 2 as follows:

+------------+-----------------+-------------------+--------+
| Capability | Description | ROS 2 Mapping | Method |
+============+=================+===================+========+
| execute | Start operation | Send action goal | POST |
+------------+-----------------+-------------------+--------+
| stop | Stop operation | Cancel action | PUT |
+------------+-----------------+-------------------+--------+
| terminate | Stop + remove | Cancel + cleanup | DELETE |
+------------+-----------------+-------------------+--------+
| status | Get status | Get goal status | GET |
+------------+-----------------+-------------------+--------+
| freeze | I/O control | Not applicable | — |
+------------+-----------------+-------------------+--------+
| reset | I/O control | Not applicable | — |
+------------+-----------------+-------------------+--------+

2 changes: 1 addition & 1 deletion docs/tutorials/authentication.rst
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ Response:
TOKEN="eyJhbGciOiJIUzI1NiIs..."

# Protected endpoint (POST requires auth in "write" mode)
curl -X POST http://localhost:8080/api/v1/components/calibration/operations/calibrate \
curl -X POST http://localhost:8080/api/v1/components/calibration/operations/calibrate/executions \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{}'
Expand Down
18 changes: 18 additions & 0 deletions docs/tutorials/heuristic-apps.rst
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,24 @@ When ``true`` (default), the gateway creates synthetic Components to group Apps:
curl http://localhost:8080/api/v1/components/perception/apps
# Returns: [{"id": "lidar_driver"}, {"id": "camera_node"}]

.. note::

Synthetic components are **logical groupings only**. They do not aggregate
operations or data from their hosted Apps. To access operations (services/actions),
you must query the Apps within the component:

.. code-block:: bash

# List Apps in the component
curl http://localhost:8080/api/v1/components/perception/apps

# Get operations for a specific App
curl http://localhost:8080/api/v1/apps/lidar_driver/operations

The component endpoint ``GET /components/{id}/operations`` aggregates operation
listings from all hosted Apps for convenience, but execution must target the
specific App that owns the operation.

When ``false``, each node is its own Component (no grouping):

.. code-block:: bash
Expand Down
4 changes: 2 additions & 2 deletions docs/tutorials/integration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -184,12 +184,12 @@ Services and actions under your namespace become Operations:

.. code-block:: cpp

// Service: POST /api/v1/components/my_node/operations/reset
// Service: POST /api/v1/components/my_node/operations/reset/executions
srv_reset_ = create_service<std_srvs::srv::Trigger>(
"reset",
std::bind(&MyNode::handle_reset, this, _1, _2));

// Action: POST /api/v1/components/my_node/operations/calibrate
// Action: POST /api/v1/components/my_node/operations/calibrate/executions
action_calibrate_ = rclcpp_action::create_server<Calibrate>(
this, "calibrate",
std::bind(&MyNode::handle_goal, this, _1, _2),
Expand Down
13 changes: 10 additions & 3 deletions postman/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ All endpoints are prefixed with `/api/v1` for API versioning.
- ✅ GET `/api/v1/` - Server capabilities and entry points
- ✅ GET `/api/v1/version-info` - Gateway status and version
- ✅ GET `/api/v1/areas` - List all areas
- ✅ GET `/api/v1/areas/{area_id}` - Get area capabilities
- ✅ GET `/api/v1/areas/{area_id}/contains` - List components contained in area
- ✅ GET `/api/v1/components` - List all components with operations and type schemas
- ✅ GET `/api/v1/components/{component_id}` - Get component capabilities
- ✅ GET `/api/v1/components/{component_id}/hosts` - List apps hosted on component (SOVD 7.6.2.4)
- ✅ GET `/api/v1/components/{component_id}/depends-on` - List component dependencies
- ✅ GET `/api/v1/areas/{area_id}/components` - List components in specific area

### Component Data Endpoints
Expand All @@ -29,9 +34,11 @@ All endpoints are prefixed with `/api/v1` for API versioning.

### Operations Endpoints (Services & Actions)
- ✅ GET `/api/v1/components/{component_id}/operations` - List all operations (services & actions) with schema info
- ✅ POST `/api/v1/components/{component_id}/operations/{operation}` - Call service or send action goal
- ✅ GET `/api/v1/components/{component_id}/operations/{operation}/status` - Get action status
- ✅ DELETE `/api/v1/components/{component_id}/operations/{operation}?goal_id=...` - Cancel action
- ✅ GET `/api/v1/components/{component_id}/operations/{operation_id}` - Get operation details
- ✅ POST `/api/v1/components/{component_id}/operations/{operation_id}/executions` - Execute operation
- ✅ GET `/api/v1/components/{component_id}/operations/{operation_id}/executions` - List executions
- ✅ GET `/api/v1/components/{component_id}/operations/{operation_id}/executions/{execution_id}` - Get execution status
- ✅ DELETE `/api/v1/components/{component_id}/operations/{operation_id}/executions/{execution_id}` - Cancel execution

### Configurations Endpoints (ROS 2 Parameters)
- ✅ GET `/api/v1/components/{component_id}/configurations` - List all parameters
Expand Down
Loading