Skip to content

AnswerLayer/answerlayer-embed-demo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AnswerLayer Embed API Demo

A single-page, dependency-free reference client for the AnswerLayer embed API. It loads a dashboard manifest, fetches paginated tile data, and shows how a host application turns the manifest's typed visualization encoding into a rendered chart.

Everything is in one file (index.html) — inline HTML, CSS, and vanilla JS, no build step. serve.py is an optional static server that disables caching so edits show up on reload.

Running

python3 serve.py            # http://localhost:5174
python3 serve.py 8080       # custom port

Plain python3 -m http.server works too; opening index.html directly as a file:// URL also works, subject to the API's CORS policy.

Then in the page:

  1. Set API base URL (e.g. http://localhost:8000), Dashboard ID, and an API key.
  2. Load Manifest — fetches the dashboard's tile list.
  3. Fetch Tile Data — fetches each tile's data.
  4. Fetch Again — repeats the request; the cache_hit badge flips to true when the backend serves from cache.
  5. Use Unique Filter — injects a one-off filter so the next fetch misses the cache.

Form values persist to localStorage.

Subject org (tenant scope)

The optional Subject org ID field is sent as an X-Subject-Org-ID header on every request — embed and clustering alike. It is the platform's row-level tenant scope: the backend reads it off the validated API-key request (never from the body) and applies it as the saved query's subject filter. Leave it blank for the org-level view; set it to scope to one of the customer's end-customers.

Clustering Lab (ML)

The second panel drives the subject-scoped ML proxy at /api/v1/ml/* (backend/app/api/v1/ml_proxy.py → the internal ML container). It uses the same API key and Subject org ID as the embed panel. Clustering is single-tenant: set a Subject org ID to train/read a tenant's model, or leave it blank for the org-level model.

  1. Set a Saved query ID (the feature query the model trains on) and optional config_overrides JSON (e.g. {"n_clusters": "auto"}).
  2. TrainPOST /cluster/train, then auto-polls GET /jobs/{job_id} until the job reaches succeeded/failed. On success it fetches results.
  3. Poll Job — resume polling a job id (e.g. after a timeout) without re-training.
  4. Get ResultsGET /cluster/results: run summary, per-cluster sizes, and per-entity assignments for the current subject scope.
  5. PredictPOST /cluster/predict with an input_data JSON array of row objects; scores them against the latest artifact.

Org and subject org are never in the request body for any ML call — they travel as the X-Org-ID (added by the backend proxy) and X-Subject-Org-ID headers. The proxy is the trust boundary; both scopes come from the authenticated context.

API surface exercised

Call Purpose
GET /api/v1/dashboards/{id}/manifest Tile list with tile_key, the typed visualization encoding, data_url, and pagination defaults
POST {tile.data_url} Tile data; supports filters and cursor pagination
POST {tile.data_url} with result_handle + pagination.cursor Next page of a materialized result (the handle must be one this tile produced)
POST /api/v1/ml/cluster/train Enqueue a clustering job; body is {saved_query_id, config_overrides}. Returns 202 {job_id, status}
GET /api/v1/ml/jobs/{job_id} Poll a training job's lifecycle (queued/running/succeeded/failed)
GET /api/v1/ml/cluster/results?limit=N Latest model's run summary, cluster_sizes, and assignments for the subject scope
POST /api/v1/ml/cluster/predict Score rows against the latest artifact; body is {input_data: [...]}

Requests authenticate with an X-API-Key header; tenant scope (where applicable) travels as the X-Subject-Org-ID header.

Tile data response

{
  "columns": ["region", "revenue"],
  "rows": [["west", 1200], ["east", 980]],
  "row_count": 2,
  "total_rows": 2,
  "next_cursor": null,        // present when more pages exist
  "result_handle": null,      // present when the result was materialized
  "cache_hit": false,
  "execution_time_ms": 41,
  "computed_at": "2026-05-16T01:00:00Z",
  "encoding_warnings": []     // non-empty if the encoding references missing columns
}

Small results come back inline. Larger results are materialized server-side and returned with a result_handle and next_cursor; pass both back to page through the data.

Rendering

Each manifest tile carries a typed visualization object whose encoding maps a chart role to a column name. The demo reads roles straight from it — no column-name or key-casing guessing:

  • chart typevisualization.chart_type (metric, bar, line, area, donut, table)
  • x / label fieldencoding.x (axis charts) or encoding.label (donut)
  • value fieldsencoding.value (metric/donut) or encoding.y (axis charts)

It resolves each role to a column, finds that column's index in the response columns, and draws a metric, bar, or table preview. If a tile's response carries encoding_warnings, the demo shows them — the saved query no longer returns a column the encoding names. A host application is free to ignore the preview and feed columns/rows into its own charting library.

License

MIT — see LICENSE.

About

Single-page reference client for the AnswerLayer embed API

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors