Spaces:
Sleeping
Sleeping
|
Download docs/api-reference.md from Sid-WC121/visual-notebook: direct link, hf CLI and curl.
- Browser
- Download file 15.4 kB
-
https://huggingface.co/spaces/Sid-WC121/visual-notebook/resolve/main/docs/api-reference.md
- Command line
-
hf download hf://spaces/Sid-WC121/visual-notebook/docs/api-reference.md
-
curl -L -o api-reference.md https://huggingface.co/spaces/Sid-WC121/visual-notebook/resolve/main/docs/api-reference.md
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 | | |