docs(dashboard): add comprehensive API reference documentation

- Document all 5 API endpoints: /healthz, /api/config, /api/status, /api/metrics, /api/events
- Include request parameters, response schemas, and example curl commands
- Document SSE event types and format with code examples in JavaScript and Go
- Add data retention policies, CORS information, and browser usage guidance
- Link to related documentation

Co-Authored-By: Claude <noreply@anthropic.com>
Bead-Id: bf-4rx
This commit is contained in:
jedarden 2026-06-21 09:58:23 -04:00
parent 225f7cfe51
commit 19e6e9c959

View file

@ -0,0 +1,565 @@
# Dashboard API Reference
This document describes the REST and SSE (Server-Sent Events) API endpoints exposed by the zai-proxy dashboard.
## Base URL
All API endpoints are relative to the dashboard base URL:
```
http://<dashboard-host>:8080
```
The default port is `8080` but can be configured via the `LISTEN_ADDR` environment variable.
---
## CORS
All API endpoints set `Access-Control-Allow-Origin: *`, enabling cross-origin requests from any origin.
---
## Endpoints
### 1. GET /healthz
Health check endpoint that returns the operational status of the dashboard service.
#### Request
```http
GET /healthz
```
No parameters or headers required.
#### Response
**Status Code:** `200 OK`
**Content-Type:** `application/json`
```json
{
"status": "ok"
}
```
#### Example
```bash
curl http://localhost:8080/healthz
```
#### Error Responses
This endpoint does not return errors. A `200 OK` response indicates the service is operational.
---
### 2. GET /api/config
Returns dashboard configuration including scrape interval and target endpoints.
#### Request
```http
GET /api/config
```
No parameters required.
#### Response
**Status Code:** `200 OK`
**Content-Type:** `application/json`
```json
{
"scrape_interval": 5,
"targets": [
"http://zai-proxy.mcp.svc.cluster.local:8080/metrics"
]
}
```
#### Response Fields
| Field | Type | Description |
|-------|------|-------------|
| `scrape_interval` | number | Scrape interval in seconds (default: 5) |
| `targets` | string[] | Array of Prometheus metrics endpoint URLs to scrape |
#### Configuration Sources
- `LISTEN_ADDR` environment variable (default: `:8080`)
- `SCRAPE_INTERVAL` environment variable (default: `5s`)
- `SCRAPE_TARGETS` environment variable (comma-separated URLs, default: `http://zai-proxy.mcp.svc.cluster.local:8080/metrics`)
#### Example
```bash
curl http://localhost:8080/api/config
```
#### Error Responses
This endpoint does not return errors under normal operation.
---
### 3. GET /api/status
Returns the latest health snapshot for each variant (production and/or canary). This endpoint provides a point-in-time status summary of all monitored proxy instances.
#### Request
```http
GET /api/status
```
No parameters required.
#### Response
**Status Code:** `200 OK`
**Content-Type:** `application/json`
```json
{
"production": {
"healthy": true,
"last_scrape": "2026-06-21T10:30:00Z",
"req_rate": 42.5,
"error_rate_pct": 0.12,
"latency_p50_ms": 145,
"concurrent": 8,
"worker_utilization": 0.32,
"rate_limit_rps": 100,
"token_rate_in": 1250.5,
"token_rate_out": 3800.2
},
"canary": {
"healthy": true,
"last_scrape": "2026-06-21T10:30:00Z",
"req_rate": 2.1,
"error_rate_pct": 0.05,
"latency_p50_ms": 138,
"concurrent": 1,
"worker_utilization": 0.08,
"rate_limit_rps": 100,
"token_rate_in": 75.3,
"token_rate_out": 220.7
}
}
```
#### Response Fields
Each variant object contains:
| Field | Type | Description |
|-------|------|-------------|
| `healthy` | boolean | Overall health status (true if data exists) |
| `last_scrape` | string | ISO 8601 timestamp of last successful scrape |
| `req_rate` | number | Current request rate (requests/second) |
| `error_rate_pct` | number | Error rate percentage (0-100) |
| `latency_p50_ms` | number | Median request latency in milliseconds |
| `concurrent` | number | Current number of concurrent requests |
| `worker_utilization` | number | Worker pool utilization ratio (0-1) |
| `rate_limit_rps` | number | Current rate limit in requests/second |
| `token_rate_in` | number | Input token rate (tokens/second) |
| `token_rate_out` | number | Output token rate (tokens/second) |
#### Example
```bash
curl http://localhost:8080/api/status
```
#### Error Responses
| Status Code | Description |
|-------------|-------------|
| `500 Internal Server Error` | Failed to retrieve status from storage |
---
### 4. GET /api/metrics
Returns historical metrics for a specified time range and variant. This is the primary endpoint for querying historical performance data.
#### Request
```http
GET /api/metrics?range={range}&variant={variant}
```
#### Query Parameters
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `range` | string | No | `1h` | Time range for historical data |
| `variant` | string | No | `all` | Variant filter: `production`, `canary`, or `all` |
#### Supported Range Values
- `5m` - 5 minutes
- `15m` - 15 minutes
- `1h` - 1 hour (default)
- `6h` - 6 hours
- `24h` - 24 hours
- `7d` - 7 days
Custom duration strings are also supported via Go's `time.ParseDuration` format (e.g., `2h30m`, `45m`).
#### Data Resolution
- **≤ 1 hour**: Data returned from `metrics_5s` table (5-second granularity)
- **> 1 hour**: Data returned from `metrics_1m` table (1-minute downsampled granularity)
#### Response
**Status Code:** `200 OK`
**Content-Type:** `application/json`
Returns a JSON array of `MetricSnapshot` objects:
```json
[
{
"timestamp": 1766425000000,
"variant": "production",
"requests_2xx": 1250,
"requests_4xx": 5,
"requests_5xx": 2,
"tokens_input": 15000,
"tokens_output": 45000,
"tokens_cache_read": 3000,
"tokens_cache_write": 1200,
"concurrent_requests": 8,
"max_workers": 25,
"rate_limit_rps": 100,
"rate_limit_rejections": 0,
"rate_limit_adj_increase": 0,
"rate_limit_adj_decrease": 0,
"upstream_errors": 1,
"retry_attempts": 2,
"latency_p50": 145,
"latency_p95": 280,
"latency_p99": 450,
"request_size_avg": 1024,
"response_size_avg": 8192,
"token_rate_in": 1250.5,
"token_rate_out": 3800.2,
"token_rate_cache_read": 250.3,
"token_rate_cache_write": 100.1,
"req_rate": 42.5,
"error_rate_pct": 0.12,
"worker_utilization": 0.32,
"status_code_rates": {
"200": 40.2,
"201": 2.0,
"400": 0.3,
"429": 0.1,
"500": 0.1
}
},
...
]
```
#### MetricSnapshot Fields
| Field | Type | Description |
|-------|------|-------------|
| `timestamp` | number | Unix timestamp in milliseconds |
| `variant` | string | Variant name: `production` or `canary` |
| `requests_2xx` | number | Cumulative count of 2xx responses |
| `requests_4xx` | number | Cumulative count of 4xx responses |
| `requests_5xx` | number | Cumulative count of 5xx responses |
| `tokens_input` | number | Cumulative input tokens processed |
| `tokens_output` | number | Cumulative output tokens processed |
| `tokens_cache_read` | number | Cumulative cache-read tokens |
| `tokens_cache_write` | number | Cumulative cache-write tokens |
| `concurrent_requests` | number | Current concurrent requests |
| `max_workers` | number | Maximum worker pool size |
| `rate_limit_rps` | number | Current rate limit (requests/second) |
| `rate_limit_rejections` | number | Cumulative rate limit rejections |
| `rate_limit_adj_increase` | number | Cumulative rate limit increases |
| `rate_limit_adj_decrease` | number | Cumulative rate limit decreases |
| `upstream_errors` | number | Cumulative upstream errors |
| `retry_attempts` | number | Cumulative retry attempts |
| `latency_p50` | number | Median latency in milliseconds |
| `latency_p95` | number | 95th percentile latency in milliseconds |
| `latency_p99` | number | 99th percentile latency in milliseconds |
| `request_size_avg` | number | Average request size in bytes |
| `response_size_avg` | number | Average response size in bytes |
| `token_rate_in` | number | Input token rate (tokens/second) |
| `token_rate_out` | number | Output token rate (tokens/second) |
| `token_rate_cache_read` | number | Cache-read token rate (tokens/second) |
| `token_rate_cache_write` | number | Cache-write token rate (tokens/second) |
| `req_rate` | number | Request rate (requests/second) |
| `error_rate_pct` | number | Error rate percentage (0-100) |
| `worker_utilization` | number | Worker utilization ratio (0-1) |
| `status_code_rates` | object | Per-status-code request rates (requests/second) |
#### Examples
```bash
# Last 5 minutes, all variants
curl "http://localhost:8080/api/metrics?range=5m&variant=all"
# Last hour, production only
curl "http://localhost:8080/api/metrics?range=1h&variant=production"
# Last 24 hours, canary only
curl "http://localhost:8080/api/metrics?range=24h&variant=canary"
# Last 7 days, all variants
curl "http://localhost:8080/api/metrics?range=7d&variant=all"
# Custom duration (2 hours 30 minutes)
curl "http://localhost:8080/api/metrics?range=2h30m&variant=production"
```
#### Error Responses
| Status Code | Description |
|-------------|-------------|
| `400 Bad Request` | Invalid `range` parameter format |
| `500 Internal Server Error` | Failed to query metrics from storage |
---
### 5. GET /api/events
Server-Sent Events (SSE) endpoint for real-time streaming of metric updates. This endpoint provides a persistent connection for receiving live metrics as they are scraped.
#### Request
```http
GET /api/events
```
No query parameters required.
#### Request Headers
| Header | Value |
|--------|-------|
| `Accept` | `text/event-stream` |
| `Cache-Control` | `no-cache` |
#### Response
**Status Code:** `200 OK`
**Content-Type:** `text/event-stream`
**Response Headers:**
| Header | Value |
|--------|-------|
| `Content-Type` | `text/event-stream` |
| `Cache-Control` | `no-cache` |
| `Connection` | `keep-alive` |
| `X-Accel-Buffering` | `no` |
#### SSE Event Format
Events are sent in the standard SSE format:
```
data: <json-payload>\n\n
```
#### Event Types
##### 1. `connected` (Initial Event)
Sent immediately upon connection establishment.
```json
{
"type": "connected",
"scrape_interval": 5,
"variants": ["production", "canary"]
}
```
**Fields:**
| Field | Type | Description |
|-------|------|-------------|
| `type` | string | Event type: `connected` |
| `scrape_interval` | number | Scrape interval in seconds |
| `variants` | string[] | Available variant names |
##### 2. `metrics` (Ongoing Events)
Sent for each new metric snapshot as it arrives (typically every scrape interval).
```json
{
"type": "metrics",
"data": {
"timestamp": 1766425000000,
"variant": "production",
"requests_2xx": 1250,
...
}
}
```
**Fields:**
| Field | Type | Description |
|-------|------|-------------|
| `type` | string | Event type: `metrics` |
| `data` | object | Full `MetricSnapshot` object (see `/api/metrics` response) |
##### 3. Heartbeat (Keepalive)
A comment sent every 30 seconds to keep the connection alive:
```
: heartbeat\n\n
```
This is an SSE comment (prefixed with `:`) and should be ignored by clients but used to detect stale connections.
#### Connection Behavior
- **Persistent Connection:** The connection remains open until the client disconnects or the server terminates.
- **Automatic Reconnect:** Clients should implement reconnection logic with exponential backoff.
- **Buffer Overflow:** Slow clients may be disconnected if their send buffer fills up (16-message buffer per client).
- **Broadcast:** All connected clients receive the same metric updates simultaneously.
#### Example Clients
**JavaScript (Browser):**
```javascript
const eventSource = new EventSource('http://localhost:8080/api/events');
eventSource.onmessage = (event) => {
const message = JSON.parse(event.data);
if (message.type === 'connected') {
console.log('Connected to SSE stream');
console.log('Scrape interval:', message.scrape_interval);
} else if (message.type === 'metrics') {
console.log('New metrics:', message.data);
// Update your UI with the new metrics
}
};
eventSource.onerror = (error) => {
console.error('SSE connection error:', error);
// Implement reconnection logic
};
```
**cURL (for testing):**
```bash
curl -N \
-H "Accept: text/event-stream" \
http://localhost:8080/api/events
```
**Go:**
```go
resp, err := http.Get("http://localhost:8080/api/events")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "data: ") {
data := strings.TrimPrefix(line, "data: ")
var msg model.SSEMessage
json.Unmarshal([]byte(data), &msg)
// Handle message
}
}
```
#### Error Responses
| Status Code | Description |
|-------------|-------------|
| `500 Internal Server Error` | Streaming not supported (server doesn't implement `http.Flusher`) |
---
## Data Retention
The dashboard stores metrics at two granularities with different retention policies:
| Table | Granularity | Retention | Purpose |
|-------|-------------|-----------|---------|
| `metrics_5s` | 5 seconds | 6 hours | High-resolution recent data |
| `metrics_1m` | 1 minute | 7 days | Downsampled historical data |
Data is automatically downsampled from 5-second to 1-minute granularity every 10 minutes. Old data beyond retention periods is automatically cleaned up.
---
## Common Error Response Format
All error responses return plain text with a descriptive message:
```http
HTTP/1.1 400 Bad Request
Content-Type: text/plain
invalid range parameter
```
---
## Rate Limiting
The dashboard API does not implement rate limiting. However, clients should:
1. **Poll `/api/metrics` sparingly** - Use SSE (`/api/events`) for real-time updates instead of polling
2. **Cache `/api/config` responses** - Configuration changes infrequently
3. **Use appropriate `range` values** - Don't request more data than needed
---
## Browser Usage
All endpoints support CORS, enabling direct browser access:
```javascript
// Fetch status
const response = await fetch('http://localhost:8080/api/status');
const status = await response.json();
// Fetch metrics
const response = await fetch('http://localhost:8080/api/metrics?range=1h&variant=production');
const metrics = await response.json();
// SSE stream
const eventSource = new EventSource('http://localhost:8080/api/events');
```
---
## Related Documentation
- [Token Counting](./TOKEN_COUNTING.md) - Detailed token metrics explanation
- [Monitoring Setup](./MONITORING_SETUP.md) - Dashboard deployment and configuration
- [Canary Promotion Procedure](./CANARY_PROMOTION_PROCEDURE.md) - Canary deployment workflow
- [Deployment Guide](./DEPLOYMENT.md) - Production deployment instructions