Request primitives, POST support, handler dispatch

OCaml server:
- Accept POST/PUT/PATCH/DELETE for /sx/ paths (was GET-only)
- Parse request body, query string, set per-request context
- Add 16 request primitives: now, state-get/set!, request-form/arg,
  request-json, request-header(s), request-method/body, into, etc.
- URL-encoded body parser for form submissions

Handler dispatch (sx/sx/handlers/dispatch.sx):
- `api` function routes URL paths like (api "click") to handler:ex-click
- `call-handler` checks HTTP method, binds params, evaluates body
- Handlers defined via defhandler in handlers/examples.sx now reachable

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-01 00:54:12 +00:00
parent fe6115f2fc
commit 461fae269b
2 changed files with 212 additions and 4 deletions

View File

@@ -0,0 +1,51 @@
(define
api
(fn
(slug)
(let
((handler-key (str "handler:ex-" slug)) (hdef (env-get handler-key)))
(if
(nil? hdef)
(div
:class "p-8"
(h2 :class "text-rose-600 font-semibold" "Handler not found")
(p :class "text-stone-500" (str "No handler: " handler-key)))
(call-handler hdef)))))
(define
call-handler
(fn
(hdef)
(let
((method (get hdef "method"))
(params (get hdef "params"))
(body (get hdef "body"))
(closure (get hdef "closure")))
(let
((req-method (request-method))
(handler-method (upper (or method "get"))))
(if
(and
(not (= handler-method "GET"))
(not (= req-method handler-method)))
(div
:class "p-4 text-rose-600"
(str
"Method not allowed: expected "
handler-method
" got "
req-method))
(eval-handler-body params body closure))))))
(define
eval-handler-body
(fn
(params body closure)
(if
(or (nil? params) (empty? params))
(eval-expr body closure)
(let
((bindings (map (fn (p) (let ((name (if (symbol? p) (symbol-name p) (str p)))) (if (= name "&key") nil (if (= name "&rest") nil (let ((val (or (request-arg name) (request-form name)))) (list (make-symbol name) (or val nil))))))) (filter (fn (p) (let ((name (if (symbol? p) (symbol-name p) (str p)))) (and (not (= name "&key")) (not (= name "&rest"))))) params))))
(let
((let-form (list (quote let) (filter (fn (b) (not (nil? b))) bindings) body)))
(eval-expr let-form closure))))))