visual-notebook / docs /api-reference.md
Sid-WC121
bug fix1
018ab56
|
Raw History Blame Contribute Delete
15.4 kB
# API Reference
This document provides a complete reference for all Visual Notebook API endpoints, including request schemas, response schemas, status codes, and usage examples.
## Base URL
- Development: `http://localhost:8000`
- Production: Same origin (backend serves the frontend)
- All API endpoints are prefixed with `/api`
- The health endpoint is at `/health` (no prefix)
## Authentication
The API uses cookie-based session management. The `session_id` cookie is set automatically after the first CSV upload and sent with all subsequent requests. No explicit authentication is required.
## Common Response Patterns
### Error Responses
All error responses follow the RFC 7807 pattern with a `detail` field:
```json
{
"detail": "Error description"
}
```
### Session Cookie
The first endpoint that creates a session (`POST /api/upload/csv`) sets an `httponly` cookie:
```
Set-Cookie: session_id=abc123def456; HttpOnly; Max-Age=604800; Path=/; SameSite=lax
```
---
## Endpoints
### POST /api/upload/csv
Upload a CSV file, register it in DuckDB, and create a new session.
**Request**: `multipart/form-data`
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `file` | File | Yes | CSV file to upload (must have `.csv` extension) |
**Response**: `200 OK`
```json
{
"dataset_id": "a3b2c1d4",
"table_name": "ds_a3b2c1d4",
"row_count": 15000,
"columns": [
{
"name": "order_id",
"dtype": "INTEGER",
"column_type": "numeric",
"null_count": 0,
"unique_count": 15000,
"min": 1,
"max": 15000,
"mean": 7500.5,
"std": 4330.1,
"q25": 3750.75,
"q50": 7500.5,
"q75": 11250.25,
"count": 15000
},
{
"name": "status",
"dtype": "VARCHAR",
"column_type": "categorical",
"null_count": 5,
"unique_count": 3,
"min": null,
"max": null,
"mean": null,
"std": null,
"q25": null,
"q50": null,
"q75": null,
"count": 14995
}
],
"session_id": "a1b2c3d4e5f6"
}
```
**Error Responses**:
| Status | Condition |
|--------|-----------|
| 400 | File does not have `.csv` extension |
| 413 | File exceeds `MAX_UPLOAD_SIZE` |
---
### GET /api/schema
Retrieve the schema and statistics for the currently loaded dataset.
**Request**: No parameters.
**Response**: `200 OK`
```json
{
"table_name": "ds_a3b2c1d4",
"row_count": 15000,
"columns": [
{
"name": "order_id",
"dtype": "INTEGER",
"column_type": "numeric",
"null_count": 0,
"unique_count": 15000,
"min": 1,
"max": 15000,
"mean": 7500.5,
"std": 4330.1,
"q25": 3750.75,
"q50": 7500.5,
"q75": 11250.25,
"count": 15000
}
]
}
```
**Error Responses**:
| Status | Condition |
|--------|-----------|
| 400 | No dataset loaded in the current session |
---
### GET /api/rows
Retrieve paginated rows from the current dataset.
**Query Parameters**:
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `offset` | integer | 0 | Row offset (0-based) |
| `limit` | integer | 50 | Maximum number of rows to return |
**Response**: `200 OK`
```json
{
"rows": [
{"order_id": 1, "status": "shipped", "amount": 99.99},
{"order_id": 2, "status": "pending", "amount": 45.50}
],
"columns": ["order_id", "status", "amount"],
"offset": 0,
"limit": 50,
"total": 15000
}
```
**Error Responses**:
| Status | Condition |
|--------|-----------|
| 400 | No dataset loaded |
---
### GET /api/ops
List all available data operations.
**Request**: No parameters.
**Response**: `200 OK`
```json
{
"operations": [
{
"key": "filter",
"label": "Filter",
"description": "Filter rows by condition",
"param_schema": {
"type": "object",
"required": ["column", "operator"],
"properties": {
"column": {"type": "string"},
"operator": {"type": "string", "enum": ["eq", "neq", "gt", "lt", "gte", "lte", "contains", "is_null", "is_not_null"]},
"value": {"type": ["string", "number"]}
}
}
},
{
"key": "sort",
"label": "Sort",
"description": "Sort by column",
"param_schema": {
"type": "object",
"required": ["column"],
"properties": {
"column": {"type": "string"},
"descending": {"type": "boolean", "default": false}
}
}
},
{
"key": "select",
"label": "Select Columns",
"description": "Keep only selected columns",
"param_schema": {
"type": "object",
"required": ["columns"],
"properties": {
"columns": {"type": "array", "items": {"type": "string"}}
}
}
},
{
"key": "rename",
"label": "Rename Columns",
"description": "Rename columns using a mapping",
"param_schema": {
"type": "object",
"required": ["mapping"],
"properties": {
"mapping": {"type": "object", "additionalProperties": {"type": "string"}}
}
}
},
{
"key": "groupby",
"label": "Group By",
"description": "Aggregate data by groups",
"param_schema": {
"type": "object",
"required": ["group_by", "aggregations"],
"properties": {
"group_by": {"type": "array", "items": {"type": "string"}},
"aggregations": {"type": "object", "additionalProperties": {"type": "array", "items": {"type": "string"}}}
}
}
},
{
"key": "fill_nulls",
"label": "Fill Nulls",
"description": "Fill null values using a strategy",
"param_schema": {
"type": "object",
"properties": {
"strategy": {"type": "string", "enum": ["forward", "backward", "mean", "zero", "constant"], "default": "forward"},
"columns": {"type": "array", "items": {"type": "string"}},
"value": {"type": ["string", "number"]}
}
}
},
{
"key": "clip",
"label": "Clip Values",
"description": "Clip values to a range",
"param_schema": {
"type": "object",
"required": ["column"],
"properties": {
"column": {"type": "string"},
"lower": {"type": "number"},
"upper": {"type": "number"}
}
}
}
]
}
```
---
### POST /api/ops/{op_key}
Apply a data operation to the current dataset.
**Path Parameters**:
| Parameter | Type | Description |
|-----------|------|-------------|
| `op_key` | string | Operation key (filter, sort, select, rename, groupby, fill_nulls, clip) |
**Request Body**:
```json
{
"op_key": "filter",
"params": {
"column": "amount",
"operator": "gt",
"value": 100
}
}
```
**Response**: `200 OK`
```json
{
"state_id": "e5f6a7b8",
"columns_schema": [
{
"name": "order_id",
"dtype": "INTEGER",
"column_type": "numeric",
"null_count": 0,
"unique_count": 5200,
"min": 1,
"max": 15000,
"mean": 7800.3,
"std": 4200.5,
"q25": 3900.0,
"q50": 7800.0,
"q75": 11700.0,
"count": 5200
}
],
"row_count": 5200,
"sample_rows": [
{"order_id": 5, "status": "shipped", "amount": 150.00},
{"order_id": 12, "status": "pending", "amount": 220.50}
]
}
```
**Error Responses**:
| Status | Condition |
|--------|-----------|
| 400 | No dataset loaded |
| 404 | Operation key not found |
| 422 | Parameter validation failed |
| 500 | Operation execution failed |
**Operation Parameter Examples**:
Filter:
```json
{"column": "status", "operator": "eq", "value": "shipped"}
{"column": "amount", "operator": "gte", "value": 50}
{"column": "notes", "operator": "contains", "value": "urgent"}
{"column": "email", "operator": "is_null"}
```
Sort:
```json
{"column": "amount", "descending": true}
```
Select:
```json
{"columns": ["order_id", "amount", "status"]}
```
Rename:
```json
{"mapping": {"order_id": "id", "amount": "total"}}
```
GroupBy:
```json
{"group_by": ["status"], "aggregations": {"amount": ["mean", "sum", "count"]}}
```
Fill Nulls:
```json
{"strategy": "forward"}
{"strategy": "zero"}
{"strategy": "constant", "value": "N/A", "columns": ["status"]}
```
Clip:
```json
{"column": "amount", "lower": 0, "upper": 1000}
```
---
### POST /api/history/undo
Undo the last operation, reverting to the previous state.
**Request**: No body.
**Response**: `200 OK`
```json
{
"state_id": "a3b2c1d4",
"operation": "upload",
"columns_schema": [
{
"name": "order_id",
"dtype": "INTEGER",
"column_type": "numeric",
"null_count": 0,
"unique_count": 15000,
"min": 1,
"max": 15000,
"mean": 7500.5,
"std": 4330.1,
"q25": 3750.75,
"q50": 7500.5,
"q75": 11250.25,
"count": 15000
}
],
"row_count": 15000
}
```
**Error Responses**:
| Status | Condition |
|--------|-----------|
| 400 | Cannot undo (at the beginning of history) |
---
### POST /api/history/redo
Redo the next operation, advancing to the subsequent state.
**Request**: No body.
**Response**: `200 OK`
Same schema as undo response.
**Error Responses**:
| Status | Condition |
|--------|-----------|
| 400 | Cannot redo (at the end of history) |
---
### POST /api/history/branch
Branch from a specific historical state, resetting the current pointer to that state.
**Request Body**:
```json
{
"state_id": "a3b2c1d4"
}
```
Note: The `state_id` is passed as a query parameter in the current implementation.
**Response**: `200 OK`
```json
{
"state_id": "a3b2c1d4",
"operation": "upload"
}
```
**Error Responses**:
| Status | Condition |
|--------|-----------|
| 404 | State ID not found in history |
---
### GET /api/history
Retrieve the full history tree for the current session.
**Request**: No parameters.
**Response**: `200 OK`
```json
{
"nodes": [
{
"id": "a3b2c1d4",
"operation": "upload",
"params": {"filename": "orders.csv"},
"parent_id": null,
"children": ["e5f6a7b8"],
"is_current": false
},
{
"id": "e5f6a7b8",
"operation": "filter",
"params": {"column": "amount", "operator": "gt", "value": 100},
"parent_id": "a3b2c1d4",
"children": [],
"is_current": true
}
],
"current_id": "e5f6a7b8",
"order": ["a3b2c1d4", "e5f6a7b8"]
}
```
---
### POST /api/viz/chart
Compute a chart specification for the current dataset.
**Request Body**:
```json
{
"chart_type": "histogram",
"params": {
"column": "amount",
"bins": 20
}
}
```
**Chart Type Parameters**:
| Chart Type | Required Params | Optional Params |
|-------------|----------------|-----------------|
| `histogram` | `column` | `bins` (default: 20) |
| `scatter` | `x_col`, `y_col` | `color_col` |
| `bar_topn` | `category_col` | `value_col`, `n` (default: 15), `sort_desc` (default: true) |
| `timeline` | `date_col`, `value_col` | `agg` (default: "sum") |
| `heatmap` | `x_col`, `y_col`, `value_col` | `agg` (default: "mean") |
| `map` | `lat_col`, `lon_col` | `label_col` |
**Response**: `200 OK`
For ECharts-based charts (histogram, scatter, bar_topn, timeline, heatmap):
```json
{
"chart_type": "histogram",
"spec": {
"animation": true,
"animationDuration": 600,
"grid": {"left": 60, "right": 30, "top": 60, "bottom": 50, "containLabel": true},
"title": {"text": "Distribution of amount", "left": "center"},
"tooltip": {"trigger": "item", "backgroundColor": "rgba(255,255,255,0.95)"},
"xAxis": {"type": "category", "data": ["0-50", "50-100", "100-150"]},
"yAxis": {"type": "value", "name": "Count"},
"series": [{"type": "bar", "data": [3200, 5100, 4500]}]
}
}
```
For map charts:
```json
{
"chart_type": "map",
"spec": {
"type": "map",
"points": [{"lat": 40.7, "lon": -74.0, "label": "NYC"}],
"bounds": {"minLat": 25.0, "maxLat": 48.0, "minLon": -125.0, "maxLon": -67.0},
"center": {"lat": 36.5, "lon": -96.0},
"pointCount": 1500
}
}
```
**Error Responses**:
| Status | Condition |
|--------|-----------|
| 400 | No dataset loaded, or chart requires DuckDB backend |
| 422 | Missing required parameter |
| 500 | Chart computation failed |
---
### GET /api/export/csv
Export the current dataset as a CSV file download.
**Request**: No parameters.
**Response**: `200 OK` with `Content-Type: text/csv`
The response is a file download with the table name as the filename.
**Error Responses**:
| Status | Condition |
|--------|-----------|
| 400 | No dataset loaded |
---
### POST /api/checkpoint
Save a checkpoint of the current session state, including the history tree and data.
**Request**: No body.
**Response**: `200 OK`
```json
{
"path": "checkpoints/a1b2c3d4e5f6/checkpoint_20240101_120000.json",
"timestamp": "20240101_120000",
"state_id": "e5f6a7b8"
}
```
---
### GET /api/checkpoints
List all saved checkpoints for the current session.
**Request**: No parameters.
**Response**: `200 OK`
```json
[
{
"path": "checkpoints/a1b2c3d4e5f6/checkpoint_20240101_120000.json",
"timestamp": "20240101_120000",
"session_id": "a1b2c3d4e5f6"
},
{
"path": "checkpoints/a1b2c3d4e5f6/checkpoint_20240101_090000.json",
"timestamp": "20240101_090000",
"session_id": "a1b2c3d4e5f6"
}
]
```
---
### GET /health
Health check endpoint for infrastructure monitoring.
**Request**: No parameters.
**Response**: `200 OK`
```json
{
"status": "ok",
"version": "0.1.0"
}
```
---
## Status Code Summary
| Code | Meaning | When Used |
|------|---------|-----------|
| 200 | Success | All successful responses |
| 400 | Bad Request | No dataset loaded, invalid state transition |
| 404 | Not Found | Unknown operation key or history state |
| 413 | Payload Too Large | File exceeds MAX_UPLOAD_SIZE |
| 422 | Unprocessable Entity | Parameter validation failure |
| 500 | Internal Server Error | Operation or chart computation failure |