Skip to content

Add canopy browse html handler - #25

Merged
noha merged 2 commits into
mainfrom
add-canopy-browse-html-handler
Jul 27, 2026
Merged

Add canopy browse html handler#25
noha merged 2 commits into
mainfrom
add-canopy-browse-html-handler

Conversation

@noha

@noha noha commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

No description provided.

noha and others added 2 commits July 23, 2026 18:04
…ON branch)

Fourth of the planned HTTP endpoints. Reuses existing, already-tested machinery
instead of inventing new write semantics:

- Scalar payload (e.g. "y", 42, true) parsed via the existing asCanopy/STON
  path (same reader Canopy's JSON config import already uses), then written
  via the target leaf's own value: (CanopyCell/CanopyAccessor).
- JSON object payload parsed the same way into a CanopyBranchNode, then
  applied via the existing CanopyBranchNode>>apply: - the same mechanism
  already used for config hot-reload/canopySetupFrom:. This answers the
  earlier open design question (merge-conflict-style vs overwrite): apply:
  overwrites existing keys and silently ignores keys the target branch does
  not declare - intentional, matches the rest of the system (an HTTP PUT
  cannot invent a new accessor slot that wasn't declared via pragma).
- 400 Bad Request when payload shape and target node shape don't match
  (object onto a scalar leaf, or scalar onto a branch).
- 404 unchanged from the GET path (shared resolveNode:).

handleRequest: now dispatches GET/PUT to handleGet:/handlePut:, 405 for
anything else (DELETE stays disallowed).

Stacked on add-canopy-browse-get-handler - merge that one (and its own base,
add-canopy-json-visitor) first.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
PR 5: content negotiation on top of the pure REST handler, per Norbert's
explicit constraint not to touch/pollute CanopyBrowseHandler itself.

CanopyBrowseHtmlHandler wraps a CanopyBrowseHandler (Option A - composition,
not subclassing) and only requires one visibility change on the wrapped
class: resolveNode: moved from 'private' to 'accessing' (per Norbert:
'accessing', not a new 'public' category) so the wrapper can resolve the
target node itself instead of depending on the JSON response shape.

Behaviour:
- Accept without text/html -> delegates entirely to the wrapped handler,
  unchanged (JSON, same as before this PR).
- Accept: text/html on a leaf (GET or PUT) -> renders a small HTML page:
  current value + a form that PUTs the edited value back via a few lines of
  inline fetch() JS (HTML forms can't PUT natively). Values are HTML-escaped.
- Accept: text/html on a branch -> still JSON, regardless of Accept.
  Deliberately out of scope: clickable child links need trailing-slash
  canonicalisation for correct relative URL resolution (otherwise a link
  from /a resolves as a sibling of a, not a child) - a real but separate
  concern, not folded into this PR.
- PUT write itself is delegated to the wrapped handler's own handlePut: (400/
  404 handling fully reused); only re-rendered as HTML on success.

Canopy-Core-Tests: 73/73 green (8 new for this handler).

Stacked on add-canopy-browse-put-support (PR 4).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@noha
noha merged commit f32b4c4 into main Jul 27, 2026
4 checks passed
@noha
noha deleted the add-canopy-browse-html-handler branch July 27, 2026 18:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant