GData Server — HTTP Response Formats (content negotiation)

The notes HTTP front end (notes_web.py, served on the REST app — 127.0.0.1:8021/notes/{key} via stunnel) content-negotiates the response format from the Accept header. The whole URL tail after /notes/ is the note key, so format is chosen purely by header — no ?query or .suffix, which would collide with keys containing ?, ., etc.

Formats

text/html — rendered page. Default for browsers, /, and absent Accept.

application/json (and application/jsonhtl+json) — raw JSONHTL document, passthrough.

application/yaml (also text/yaml, application/x-yaml) — direct YAML of the document.

text/markdown — Markdown render. text/plain is an alias (JSONHTL Markdown is human-readable).

Anything the client demands that we cannot produce returns 406 Not Acceptable. All responses set Vary: Accept. Higher q-values win over source order.

Try it

curl -H 'Accept: application/json'  http://127.0.0.1:8021/notes/README
curl -H 'Accept: application/yaml'  http://127.0.0.1:8021/notes/README
curl -H 'Accept: text/markdown'     http://127.0.0.1:8021/notes/README

Implementation

Negotiation + JSON/YAML live in notes_web.py (negotiate_format / _serve_note). Markdown comes from the shared jsonhtl_md.py (canonical JSONHTL→Markdown), also used by notes_to_pdf.py; both HTML renderers (web and the wx desktop gdata-browser) share the same inline-span map so strong/em/italic/bold/code render identically. svg/image blocks render in every format (data-URI in HTML/Markdown), so a fixed-sheet plot is viewable either way; runnable sheets are shown as static content, never executed, over HTTP.

Deployed to gravlax 2026-07-28 (copied notes_web.py + new jsonhtl_md.py to /home/john/py/gdata-server/, restarted both gdata-mcp-server units). See infrastructure for the restart-both rule.

updated 2026-07-28  ·  tags gdata-server, http, rendering