Migrate remaining 7 ref endpoints to SX, add :returns type annotations
Add 14 new IO primitives to boundary.sx: web interop (request-form, request-json, request-header, request-content-type, request-args-all, request-form-all, request-headers-all, request-file-name), response manipulation (set-response-header, set-response-status), ephemeral state (state-get, state-set!), and timing (now, sleep). All 19 reference handlers now have :returns type annotations using types.sx vocabulary. Response meta (headers/status) flows through context vars, applied by register_route_handlers after execution. Only SSE endpoint remains in Python (async generator paradigm). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
(defhandler ref-time
|
||||
:path "/geography/hypermedia/reference/api/time"
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((now (now "%H:%M:%S")))
|
||||
(<>
|
||||
@@ -21,6 +22,7 @@
|
||||
:path "/geography/hypermedia/reference/api/greet"
|
||||
:method :post
|
||||
:csrf false
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((name (request-form "name" "stranger")))
|
||||
(<>
|
||||
@@ -34,6 +36,7 @@
|
||||
:path "/geography/hypermedia/reference/api/status"
|
||||
:method :put
|
||||
:csrf false
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((status (request-form "status" "unknown")))
|
||||
(<>
|
||||
@@ -47,6 +50,7 @@
|
||||
:path "/geography/hypermedia/reference/api/theme"
|
||||
:method :patch
|
||||
:csrf false
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((theme (request-form "theme" "unknown")))
|
||||
(<>
|
||||
@@ -60,6 +64,7 @@
|
||||
:path "/geography/hypermedia/reference/api/item/<item_id>"
|
||||
:method :delete
|
||||
:csrf false
|
||||
:returns "element"
|
||||
(&key)
|
||||
(<>
|
||||
(~doc-oob-code :target-id "ref-wire-sx-delete" :text "\"\"")))
|
||||
@@ -69,6 +74,7 @@
|
||||
(defhandler ref-trigger-search
|
||||
:path "/geography/hypermedia/reference/api/trigger-search"
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((q (request-arg "q" "")))
|
||||
(let ((sx-text (if (= q "")
|
||||
@@ -85,6 +91,7 @@
|
||||
(defhandler ref-swap-item
|
||||
:path "/geography/hypermedia/reference/api/swap-item"
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((now (now "%H:%M:%S")))
|
||||
(<>
|
||||
@@ -97,6 +104,7 @@
|
||||
(defhandler ref-oob
|
||||
:path "/geography/hypermedia/reference/api/oob"
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((now (now "%H:%M:%S")))
|
||||
(<>
|
||||
@@ -111,6 +119,7 @@
|
||||
(defhandler ref-select-page
|
||||
:path "/geography/hypermedia/reference/api/select-page"
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((now (now "%H:%M:%S")))
|
||||
(<>
|
||||
@@ -127,6 +136,7 @@
|
||||
(defhandler ref-slow-echo
|
||||
:path "/geography/hypermedia/reference/api/slow-echo"
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((q (request-arg "q" "")))
|
||||
(sleep 800)
|
||||
@@ -140,6 +150,7 @@
|
||||
(defhandler ref-prompt-echo
|
||||
:path "/geography/hypermedia/reference/api/prompt-echo"
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((name (request-header "SX-Prompt" "anonymous")))
|
||||
(<>
|
||||
@@ -152,5 +163,135 @@
|
||||
(defhandler ref-error-500
|
||||
:path "/geography/hypermedia/reference/api/error-500"
|
||||
:method :get
|
||||
:returns "nil"
|
||||
(&key)
|
||||
(abort 500 "Server error"))
|
||||
|
||||
|
||||
;; ==========================================================================
|
||||
;; Remaining reference endpoints — migrated from Python
|
||||
;; ==========================================================================
|
||||
|
||||
;; --- sx-encoding demo: file upload name ---
|
||||
|
||||
(defhandler ref-upload-name
|
||||
:path "/geography/hypermedia/reference/api/upload-name"
|
||||
:method :post
|
||||
:csrf false
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((name (request-file-name "file")))
|
||||
(let ((display (if (nil? name) "(no file)" name)))
|
||||
(let ((sx-text (str "(span :class \"text-stone-800 text-sm\" \"Received: \" (strong \"" display "\"))")))
|
||||
(<>
|
||||
(span :class "text-stone-800 text-sm" "Received: " (strong display))
|
||||
(~doc-oob-code :target-id "ref-wire-sx-encoding" :text sx-text))))))
|
||||
|
||||
;; --- sx-headers demo: echo custom headers ---
|
||||
|
||||
(defhandler ref-echo-headers
|
||||
:path "/geography/hypermedia/reference/api/echo-headers"
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((all-headers (into (list) (request-headers-all))))
|
||||
(let ((custom (filter
|
||||
(fn (pair) (starts-with? (first pair) "x-"))
|
||||
all-headers)))
|
||||
(let ((sx-text
|
||||
(if (empty? custom)
|
||||
"(span :class \"text-stone-400 text-sm\" \"No custom headers received.\")"
|
||||
(str "(ul :class \"text-sm text-stone-700 space-y-1\" "
|
||||
(join " " (map (fn (pair) (str "(li (strong \"" (first pair) "\") \": \" \"" (nth pair 1) "\")")) custom))
|
||||
")"))))
|
||||
(<>
|
||||
(if (empty? custom)
|
||||
(span :class "text-stone-400 text-sm" "No custom headers received.")
|
||||
(ul :class "text-sm text-stone-700 space-y-1"
|
||||
(map (fn (pair) (li (strong (first pair)) ": " (nth pair 1))) custom)))
|
||||
(~doc-oob-code :target-id "ref-wire-sx-headers" :text sx-text))))))
|
||||
|
||||
;; --- sx-include demo: echo GET query params ---
|
||||
|
||||
(defhandler ref-echo-vals-get
|
||||
:path "/geography/hypermedia/reference/api/echo-vals"
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((vals (into (list) (request-args-all))))
|
||||
(let ((sx-text
|
||||
(if (empty? vals)
|
||||
"(span :class \"text-stone-400 text-sm\" \"No values received.\")"
|
||||
(str "(ul :class \"text-sm text-stone-700 space-y-1\" "
|
||||
(join " " (map (fn (pair) (str "(li (strong \"" (first pair) "\") \": \" \"" (nth pair 1) "\")")) vals))
|
||||
")"))))
|
||||
(<>
|
||||
(if (empty? vals)
|
||||
(span :class "text-stone-400 text-sm" "No values received.")
|
||||
(ul :class "text-sm text-stone-700 space-y-1"
|
||||
(map (fn (pair) (li (strong (first pair)) ": " (nth pair 1))) vals)))
|
||||
(~doc-oob-code :target-id "ref-wire-sx-include" :text sx-text)))))
|
||||
|
||||
;; --- sx-vals demo: echo POST form values ---
|
||||
|
||||
(defhandler ref-echo-vals-post
|
||||
:path "/geography/hypermedia/reference/api/echo-vals"
|
||||
:method :post
|
||||
:csrf false
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((vals (into (list) (request-form-all))))
|
||||
(let ((sx-text
|
||||
(if (empty? vals)
|
||||
"(span :class \"text-stone-400 text-sm\" \"No values received.\")"
|
||||
(str "(ul :class \"text-sm text-stone-700 space-y-1\" "
|
||||
(join " " (map (fn (pair) (str "(li (strong \"" (first pair) "\") \": \" \"" (nth pair 1) "\")")) vals))
|
||||
")"))))
|
||||
(<>
|
||||
(if (empty? vals)
|
||||
(span :class "text-stone-400 text-sm" "No values received.")
|
||||
(ul :class "text-sm text-stone-700 space-y-1"
|
||||
(map (fn (pair) (li (strong (first pair)) ": " (nth pair 1))) vals)))
|
||||
(~doc-oob-code :target-id "ref-wire-sx-vals" :text sx-text)))))
|
||||
|
||||
;; --- sx-retry demo: flaky endpoint (fails 2/3 times) ---
|
||||
|
||||
(defhandler ref-flaky
|
||||
:path "/geography/hypermedia/reference/api/flaky"
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((n (+ (state-get "ref-flaky-n" 0) 1)))
|
||||
(state-set! "ref-flaky-n" n)
|
||||
(if (not (= (mod n 3) 0))
|
||||
(do
|
||||
(set-response-status 503)
|
||||
"")
|
||||
(let ((sx-text (str "(span :class \"text-emerald-700 text-sm\" \"Success on attempt \" \"" n "\" \"!\")")))
|
||||
(<>
|
||||
(span :class "text-emerald-700 text-sm" "Success on attempt " (str n) "!")
|
||||
(~doc-oob-code :target-id "ref-wire-sx-retry" :text sx-text))))))
|
||||
|
||||
;; --- sx-trigger-event demo: response header triggers ---
|
||||
|
||||
(defhandler ref-trigger-event
|
||||
:path "/geography/hypermedia/reference/api/trigger-event"
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((now (now "%H:%M:%S")))
|
||||
(set-response-header "SX-Trigger" "showNotice")
|
||||
(<>
|
||||
(span :class "text-stone-800 text-sm" "Loaded at " (strong now) " — check the border!"))))
|
||||
|
||||
;; --- sx-retarget demo: response header retargets ---
|
||||
|
||||
(defhandler ref-retarget
|
||||
:path "/geography/hypermedia/reference/api/retarget"
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((now (now "%H:%M:%S")))
|
||||
(set-response-header "SX-Retarget" "#ref-hdr-retarget-alt")
|
||||
(<>
|
||||
(span :class "text-violet-700 text-sm" "Retargeted at " (strong now)))))
|
||||
|
||||
Reference in New Issue
Block a user