RustBridge provides a RESTful API and WebSocket interface for accessing device data.
http://localhost:3000
RustBridge supports optional API key authentication. When enabled, all API endpoints (except excluded paths) require a valid API key.
Enable authentication in config.yaml:
auth:
enabled: true
api_keys:
- "your-secret-key-1"
- "your-secret-key-2"
exclude_paths:
- "/health"
- "/metrics"Include the API key in the X-API-Key header:
# With authentication
curl -H "X-API-Key: your-secret-key-1" http://localhost:3000/api/devices
# Excluded paths work without authentication
curl http://localhost:3000/health
curl http://localhost:3000/metricsMissing API Key (401 Unauthorized):
{
"error": "unauthorized",
"message": "Missing X-API-Key header"
}Invalid API Key (401 Unauthorized):
{
"error": "unauthorized",
"message": "Invalid API key"
}Exclude paths support wildcards:
auth:
exclude_paths:
- "/health"
- "/public/*" # Matches /public/info, /public/docs/api, etc.All responses are JSON with the following structure:
{
"data": { ... },
"timestamp": "2025-12-27T10:30:00Z"
}Error responses:
{
"error": {
"code": "DEVICE_NOT_FOUND",
"message": "Device 'plc-99' not found"
},
"timestamp": "2025-12-27T10:30:00Z"
}Health check endpoint.
Response:
{
"status": "healthy",
"version": "1.0.0",
"uptime_seconds": 3600
}API information and capabilities.
Response:
{
"name": "RustBridge",
"version": "1.0.0",
"features": {
"mqtt": true,
"websocket": true,
"prometheus": true
},
"device_count": 5,
"register_count": 42
}List all configured devices.
Response:
[
{
"id": "plc-main",
"name": "Main PLC Controller",
"device_type": "tcp",
"enabled": true,
"connected": true,
"last_poll": "2025-12-27T10:30:00Z",
"poll_interval_ms": 1000,
"register_count": 8,
"error_count": 0
},
{
"id": "sensor-01",
"name": "Temperature Sensor",
"device_type": "rtu",
"enabled": true,
"connected": true,
"last_poll": "2025-12-27T10:29:58Z",
"poll_interval_ms": 2000,
"register_count": 3,
"error_count": 0
}
]Get details of a specific device.
Parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string | Device ID |
Response:
{
"id": "plc-main",
"name": "Main PLC Controller",
"device_type": "tcp",
"connection": {
"host": "192.168.1.100",
"port": 502,
"unit_id": 1
},
"enabled": true,
"connected": true,
"last_poll": "2025-12-27T10:30:00Z",
"poll_interval_ms": 1000,
"statistics": {
"total_reads": 86400,
"successful_reads": 86350,
"failed_reads": 50,
"avg_response_ms": 12.5
}
}Get all register values for a device.
Parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string | Device ID |
Response:
[
{
"name": "temperature",
"value": 23.5,
"raw": [235],
"unit": "°C",
"address": 0,
"register_type": "holding",
"timestamp": "2025-12-27T10:30:00Z",
"quality": "good"
},
{
"name": "pressure",
"value": 4.2,
"raw": [16640, 0],
"unit": "bar",
"address": 10,
"register_type": "holding",
"timestamp": "2025-12-27T10:30:00Z",
"quality": "good"
}
]Get a specific register value.
Parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string | Device ID |
name |
string | Register name |
Response:
{
"name": "temperature",
"value": 23.5,
"raw": [235],
"unit": "°C",
"address": 0,
"register_type": "holding",
"data_type": "u16",
"scale": 0.1,
"timestamp": "2025-12-27T10:30:00Z",
"quality": "good"
}Write a value to a register (holding registers and coils only).
Parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string | Device ID |
name |
string | Register name |
Request Body:
{
"value": 25.0
}Response:
{
"success": true,
"name": "setpoint",
"value": 25.0,
"raw_written": [250],
"timestamp": "2025-12-27T10:30:00Z"
}Error Response (read-only register):
{
"error": {
"code": "REGISTER_READ_ONLY",
"message": "Register 'temperature' is read-only (input register)"
}
}Real-time data stream via WebSocket.
Connection:
const ws = new WebSocket('ws://localhost:3000/ws');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log(data);
};Message Types:
- Register Update
{
"type": "register_update",
"device_id": "plc-main",
"register": {
"name": "temperature",
"value": 23.5,
"unit": "°C",
"timestamp": "2025-12-27T10:30:00Z"
}
}- Device Status Change
{
"type": "device_status",
"device_id": "plc-main",
"connected": true,
"timestamp": "2025-12-27T10:30:00Z"
}- Error Event
{
"type": "error",
"device_id": "plc-main",
"error": "Connection timeout",
"timestamp": "2025-12-27T10:30:00Z"
}Subscription (filter messages):
// Subscribe to specific devices
ws.send(JSON.stringify({
"action": "subscribe",
"devices": ["plc-main", "sensor-01"]
}));
// Subscribe to specific registers
ws.send(JSON.stringify({
"action": "subscribe",
"devices": ["plc-main"],
"registers": ["temperature", "pressure"]
}));
// Unsubscribe
ws.send(JSON.stringify({
"action": "unsubscribe"
}));Prometheus metrics endpoint.
Response (text/plain):
# HELP rustbridge_register_value Current register value
# TYPE rustbridge_register_value gauge
rustbridge_register_value{device="plc-main",register="temperature"} 23.5
rustbridge_register_value{device="plc-main",register="pressure"} 4.2
# HELP rustbridge_register_reads_total Total register reads
# TYPE rustbridge_register_reads_total counter
rustbridge_register_reads_total{device="plc-main",status="success"} 86350
rustbridge_register_reads_total{device="plc-main",status="error"} 50
# HELP rustbridge_device_connected Device connection status
# TYPE rustbridge_device_connected gauge
rustbridge_device_connected{device="plc-main"} 1
rustbridge_device_connected{device="sensor-01"} 1
See Prometheus Metrics for the full metrics reference.
| Code | HTTP Status | Description |
|---|---|---|
DEVICE_NOT_FOUND |
404 | Device ID does not exist |
REGISTER_NOT_FOUND |
404 | Register name does not exist |
REGISTER_READ_ONLY |
400 | Cannot write to input register |
INVALID_VALUE |
400 | Value out of range or wrong type |
DEVICE_DISCONNECTED |
503 | Device is not connected |
MODBUS_ERROR |
502 | Modbus communication error |
TIMEOUT |
504 | Request timeout |
Currently no rate limiting is applied. Rate limiting is planned for v1.1.0.
CORS is enabled by default. All origins are allowed. Configure with server.cors_enabled: false to disable.