docs(rag): adopt endpoint helpers + no-inline-semicolon style

Update idioms skeleton to use REQUIRE_PG/REQUIRE_JSON_BODY/API_OK/API_ERR,
and add the style rule banning inline ';' multi-statements (visual-review
readability) to idioms + gotchas.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
CharlesKWON
2026-06-15 14:49:07 +09:00
parent cf370564f3
commit 537a302c92
2 changed files with 42 additions and 14 deletions

View File

@@ -9,36 +9,49 @@ summary: Battle-tested patterns from the production solmade app for building HTT
All snippets are from the real `solmade` app (`/Users/charleskwon/solmade`).
## 1. HTTP endpoint skeleton
## 1. HTTP endpoint skeleton (use the shared helpers)
One `FUNCTION Main()` per `.prg` file under `app/api/`.
One `FUNCTION Main()` per `.prg` file under `app/api/`. Use the helpers in
`app/lib/api.prg` instead of repeating PG/JSON/error boilerplate:
- `REQUIRE_PG() → nPG` — PG handle; on failure emits a 500 JSON error and returns -1.
- `REQUIRE_JSON_BODY() → hBody | NIL` — parsed JSON body; on failure emits 400, returns NIL.
- `API_OK( [hPayload] ) → NIL` — sends `{"ok":true, ...payload}`.
- `API_ERR( nStatus, cMsg [, hExtra] ) → NIL` — sends `{"ok":false,"error":cMsg, ...}`.
xBase can't force the caller to return, so the convention is "helper sets the response,
caller returns immediately." `API_OK`/`API_ERR` return NIL so you can write
`RETURN API_ERR( 400, "…" )` on one line.
```five
// POST /api/press-save.prg
FUNCTION Main()
LOCAL nPG := LABDB_GET_PG()
LOCAL hBody, nUser, aRows
LOCAL nPG := REQUIRE_PG()
LOCAL hBody, nUser
IF nPG < 0
ctx_set( "status", 500 )
AP_JSONRESPONSE( { "ok" => .f., "error" => "PG not connected" } )
RETURN NIL
ENDIF
hBody := hb_jsonDecode( AP_BODY() ) // parse JSON request body
IF ! HB_ISHASH( hBody )
ctx_set( "status", 400 )
AP_JSONRESPONSE( { "ok" => .f., "error" => "body must be JSON object" } )
hBody := REQUIRE_JSON_BODY()
IF hBody == NIL
RETURN NIL
ENDIF
nUser := Val( ctx_get( "auth_user_id", "0" ) ) // authed user (string → int)
IF Empty( nUser )
RETURN API_ERR( 401, "login required" )
ENDIF
AP_JSONRESPONSE( { "ok" => .t. } )
RETURN NIL
RETURN API_OK( { "id" => 123 } )
```
Core verbs:
> STYLE: always write `IF`/`FOR`/`WHILE` bodies on their own indented lines. Do NOT use
> inline `;` to pack multiple statements on one line (`IF nPG < 0 ; RETURN NIL ; ENDIF`
> is banned — it hurts visual review). The trailing-`;` line *continuation* (for long
> strings/SQL/args) is a different, allowed use.
Core verbs (used by/inside the helpers):
- `AP_BODY()` → raw request body (decode with `hb_jsonDecode`).
- `AP_GETPAIRS( .t. )` → hash of query-string params (GET).
- `AP_JSONRESPONSE( hHash )` → serialize + send JSON response.

View File

@@ -79,7 +79,22 @@ about; they still resolve at runtime via the registry. To silence, add the name
known-function set in `compiler/analyzer/analyzer.go` (e.g. `HB_GETCHARSET` etc. were added
there). A warning is not an error.
## 10. Density is a double-edged sword when debugging
## 10. STYLE: no inline `;` multi-statements (banned)
Five aims to be easy for a human to verify by eye. Do **not** pack multiple statements
onto one line with `;`: `IF nPG < 0 ; RETURN NIL ; ENDIF`, `IF Empty(x) ; x:="y" ; ENDIF`
are banned — they hurt visual review. Always expand:
```five
IF nPG < 0
RETURN NIL
ENDIF
```
(The *trailing* `;` for line continuation — joining a long string/SQL/arg list across
lines — is a different, allowed feature. The ban is only on `;` as a statement separator.)
## 11. Density is a double-edged sword when debugging
One line doing a lot means one line failing does a lot. When a dense statement misbehaves,
expand it (split the chained `hb_*`/`PG_*`/`LLM_CHAT` calls into temporaries) to localize