Skip to content

📘 HIX - Complete Reference of U* Helpers

The U* helpers are global functions accessible from any route, controller, or .hrb file without needing to pass oReq as a parameter. The dispatcher calls HIX_SetRequest(oReq) before executing each action, so the helpers always have access to the request of the current thread.


1. Reading the request

Input data

Function Returns Description
UMethod() C HTTP method in uppercase: "GET", "POST", "PUT", "DELETE", "PATCH"
UPath() C Path without query string: "/api/users/42"
UQuery() C Raw query string: "page=1&limit=10"
UGet(cKey, xDef) X Query string parameter. Without arguments returns complete hash
UPost(cKey, xDef) X POST body field (form or JSON). Without arguments returns complete hash
UParam(cKey, xDef) C Route variable :var. Without default throws 400 error if missing
UHeader(cKey, xDef) C HTTP header (case-insensitive)
UCookie(cName, xDef) C Request cookie (parsed once, lazy)
UBody() C Raw body as string
UJson() H/A Body parsed as JSON; NIL if body is not valid JSON
UContentType() C Content-Type in lowercase: "application/json"
UContentLength() N Body length in bytes
UFiles() A Array of hashes of uploaded files (multipart). See uploads section
URequest() O THixRequest object of the current thread (low-level access)
UContext() O THixContext of the current middleware chain (access to oCtx:hData); NIL if not in MW chain

UGet / UPost without arguments: return a hash with all fields.

// Get all GET parameters at once
hParams := UGet()   // { "page" => "1", "limit" => "10" }

// Get a field with default
cNombre := UPost( "nombre", "Anonymous" )

// Route variable with safe default
nId := Val( UParam( "id", "0" ) )

// Route variable without default - throws 400 if missing
cSlug := UParam( "slug" )

UParam with numeric index: when the route uses * the wildcard is captured as _1.

oSrv:AddRouteGet( "static", "/static/*", {||
   cFile := UParam( 1 )   // equivalent to UParam("_1")
} )

Content type and negotiation

Function Returns Description
UIsGet() L .T. if method is GET
UIsPost() L .T. if method is POST
UIsAjax() L .T. if X-Requested-With: XMLHttpRequest
UIsHttps() L .T. if connection is HTTPS
UScheme() C "http" or "https"
UIsJson() L .T. if Content-Type is application/json
UIsForm() L .T. if Content-Type is application/x-www-form-urlencoded
UIsMultipart() L .T. if Content-Type is multipart/form-data
UWantsJson() L .T. if client prefers JSON (Accept header or AJAX)

Client data

Function Returns Description
UIP() C Client's real IP (respects X-Forwarded-For if mode=proxied)
UHost() C Request hostname (Host header)
UPort() N Server port

Multipart uploads

aFiles := UFiles()
FOR EACH hFile IN aFiles
   // hFile["name"]  -> field name
   // hFile["data"]  -> binary content
   // hFile["mime"]  -> file Content-Type
   // hFile["size"]  -> size in bytes
   hb_MemoWrit( "uploads/" + hFile["name"], hFile["data"] )
NEXT

2. Sending responses

Direct responses

Function Description
USendJson(xData [, nStatus]) JSON 200. xData can be hash, array, or string
USendHtml(cHtml [, nStatus]) HTML 200
USendText(cText [, nStatus]) text/plain 200
USendView(cView [, hVars]) Renders template and sends HTML
USendEmpty() 204 No Content
USendError(nStatus, cDetail) HTTP error with detail message
URedirect(cUrl [, nStatus]) Redirect (302 by default)
// Simple JSON response
USendJson( { "ok" => .T. } )

// With custom status
USendJson( { "id" => 42, "name" => "Test" }, 201 )

// Permanent redirect
URedirect( "/new-url", 301 )

// HTTP error
USendError( 403, "Insufficient permissions" )

Fine-grained buffer control

When you need to build the response step by step before sending it:

Function Description
UWrite(cText) Accumulates text in response buffer
UEcho(cText) Alias for UWrite
USetStatus(nStatus) Sets HTTP status of buffer
USetMime(cMime) Sets MIME of buffer ("json", "html", "text" or full MIME)
UGetMime() Returns the currently configured MIME
USetHeader(cKey, cVal) Adds extra header to response
UFlush() Sends accumulated buffer as chunk (initiates streaming if first time)
// Build JSON manually
USetStatus( 201 )
USetMime( "json" )
USetHeader( "X-Request-Id", "abc123" )
UWrite( hb_jsonEncode( { "created" => .T. } ) )
// The dispatcher sends the buffer when the action ends

Cookies in response

Function Description
USetCookie(cName, cVal, nMaxAge) Writes Set-Cookie in response

nMaxAge: - 0 - session cookie (no Max-Age) - -1 - expire immediately (Max-Age=0) - > 0 - duration in seconds

The flags HttpOnly; SameSite=Lax; Path=/ are added automatically.

USetCookie( "session_id", cSid, 3600 )   // 1 hour
USetCookie( "pref", "dark", 0 )          // session
USetCookie( "old_cookie", "", -1 )       // expire

3. Chunked streaming

For SSE, progressive downloads, or long-duration responses:

Function Description
USendStreamStart(cMime, nStatus, hExtra) Initiates chunked response; extra headers in hExtra
USendChunk(cData) Sends a chunk of data
USendStreamEnd() Closes stream (zero-length chunk)
// SSE - Server-Sent Events
oSrv:AddRouteGet( "events", "/events", {||
   LOCAL i := 0
   USendStreamStart( "text/event-stream", 200, ;
      { "Cache-Control" => "no-cache", "X-Accel-Buffering" => "no" } )
   DO WHILE i < 10
      i++
      USendChunk( "data: " + hb_jsonEncode( { "n" => i } ) + hb_eol() + hb_eol() )
      hb_idleSleep( 1 )
   ENDDO
   USendStreamEnd()
} )

4. Session

Function Description
USession() Returns a proxy object with methods Get/Set/Save/Destroy
USession(cKey) Reads a session value; NIL if not exists
USession(cKey, xDef) Reads a value with default
// Read a field
cUser := USession( "user" )

// Write and save
USession():Set( "user", "carles" )
USession():Set( "role", "admin" )
USession():Save()   // renews TTL and emits Set-Cookie

// Destroy session
USession():Destroy()

Requires that HIX_MwSession is registered as middleware on the route.


5. JWT

Function Description
UJwt() Returns the complete JWT payload hash; NIL if no JWT
UJwt(cKey) Returns a claim from payload; NIL if not exists
UJwt(cKey, xDef) Returns a claim with default
UHasScope(cScope) .T. if JWT includes the scope in the scope field
// Read claim
cSub  := UJwt( "sub" )
nExp  := UJwt( "exp", 0 )

// Check scope
IF ! UHasScope( "read:products" )
   USendError( 403, "Insufficient scope" )
   RETURN
ENDIF

Requires that HixMwJwt is registered as middleware on the route.


6. Authentication and roles

Available when the HIX_MwAuth or HIX_MwIsAuth middleware is active.

Function Description
UCurrentUser() Complete hash of authenticated user; NIL if no session
UAuthUser() Hash of the request's user (set by middleware); NIL if not authenticated
UAuthUser(cKey) Field of the user hash
UAuthUser(cKey, xDef) Field of the hash with default
UHasRole(cRole) .T. if user has the role (full access)
UHasRole(cRole, cOp) .T. if user has the role with the specified operation
UGetRoles() Hash of user roles: { "admin" => "", "editor" => "read;write" }
UAuthLogout() Destroys session and clears current user
// Check role
IF ! UHasRole( "admin" )
   USendError( 403, "Administrators only" )
   RETURN
ENDIF

// Check role with granular operation
IF ! UHasRole( "products", "delete" )
   USendError( 403, "No delete permission" )
   RETURN
ENDIF

// Read user data
hUser := UAuthUser()
cEmail := UAuthUser( "email", "" )

// Logout
UAuthLogout()
URedirect( "/login" )

7. Validation

Building a validator

Function Data source
UValidate(hRules) POST (form or JSON)
UValidatePost(hRules) Explicit POST
UValidateGet(hRules) Query string
UValidateParams(hRules) Query string + route variables merged
UValidateJson(hRules) Explicit JSON body
UValidateInput(hRules) Equivalent to UValidatePost (POST form body)
UValidateOrFail(hRules) POST - automatically responds 422 if fails; returns NIL

All accept an optional second parameter hSanitate with sanitization rules.

Typical flow

FUNCTION _CreateUser()
   LOCAL oVal := UValidateOrFail( { ;
      "name"  => "required|string|max:100", ;
      "email" => "required|string|email",   ;
      "age"   => "required|integer|min:18"  ;
   } )
   IF oVal == NIL ; RETURN NIL ; ENDIF   // already responded 422

   cName  := oVal:Get( "name" )
   cEmail := oVal:Get( "email" )
   nAge   := oVal:Get( "age" )
   // ...
   USendJson( { "ok" => .T. }, 201 )
RETURN NIL

Manual error handling

LOCAL oVal := UValidatePost( hRules )
IF ! oVal:Make()
   USendJson( { "errors" => oVal:GetErrorsJson() }, 422 )
   RETURN
ENDIF

Available rules

required            mandatory field (not empty)
string              string type
integer             integer
numeric             number (int or decimal)
boolean             logical
array               array
min:N               string: length >= N  /  number: value >= N
max:N               string: length <= N  /  number: value <= N
minlen:N            string length >= N
maxlen:N            string length <= N
between:N:M         number between N and M
email               email format
url                 starts with http:// or https://
ip                  valid IPv4
regex:PATRON        Harbour regular expression
in:a,b,c            value in list
notin:a,b           value not in list
field               include the field in DataFields() if valid

Sanitization (applied before validation):

trim                AllTrim()
lower               Lower()
upper               Upper()

Quick predicates

Function Description
UIsMail(cStr) .T. if cStr has email format
UIsNumeric(uValue) .T. if value is numeric (number or numeric string)
UIsInteger(uValue) .T. if value is an integer
UIsUrl(cStr) .T. if starts with http:// or https://
UIsIp(cStr) .T. if valid IPv4

8. Views / Templates

Function Description
USendView(cView [, hVars]) Renders template and sends HTML response
UView(cView [, hVars]) Renders template and returns HTML as string

Templates are located in www/views/ with .html extension.

// Render and send
USendView( "users/list.html" )

// With variables
USendView( "users/edit.html", { ;
   "cName" => "Carles", ;
   "nAge"  => 42        ;
} )

// Only get the HTML (to compose partials)
cPartial := UView( "partials/header.html", { "cTitle" => "My app" } )
USendHtml( cPartial + "<main>content</main>" )

Template format:

@args cName, nAge

<html>
<body>
  <h1>Edit: {{ cName }}</h1>
  <p>Age: {{ hb_NToS(nAge) }}</p>
</body>
</html>

9. View helpers

Type conversion

Function Description
UStr(u) Converts any Harbour type to string (C, N, L, D, A, H)
UDateToHtml(dFecha) Harbour date to string "YYYY-MM-DD" for HTML inputs
ULogicToHtmlChecked(lValue) .T."checked", .F."" (for checkboxes)
UHtmlEncode(cText) Escapes HTML entities (&, <, >, ", ') in one pass
UOsFileName(cFileName) Normalizes path separators to the operating system's separator

HTML select

// UHashToHtmlSelect( aHash, cSelect, cKey, cValue )
// aHash: array of hashes with key and value fields
// cSelect: currently selected value
// cKey: name of the key field in each hash (default "key")
// cValue: name of the value field in each hash (default "value")

aItems := { { "key" => "es", "value" => "Spanish" }, ;
            { "key" => "en", "value" => "English" } }
cHtml := UHashToHtmlSelect( aItems, "es", "key", "value" )
// <option value="" ></option>
// <option value="es" selected>Spanish</option>
// <option value="en">English</option>

Named routes

// URoute( cName, param1, param2, ... )
cUrl := URoute( "user", 42 )       // -> "/users/42"
cUrl := URoute( "post", "my-slug" ) // -> "/posts/my-slug"

10. CSRF

Protect HTML forms against Cross-Site Request Forgery attacks.

Function Description
UCsrfToHtml([cToken]) Generates <input type="hidden" name="_csrf" value="...">
HIX_CsrfMakeToken([cData]) Generates a signed CSRF token with the csrf key from HIX_Keys store
HIX_CsrfValidToken(cToken [, nLapsus]) .T. if token is valid. nLapsus in seconds (0 = no expiration)
HIX_CsrfGenRandom([nLen]) Generates random string of nLen bytes
// In the GET action that serves the form
USendView( "form.html", { "cCsrf" => UCsrfToHtml() } )

// In the template
// {{ cCsrf }}   -- emits the <input hidden>

// In the POST action that processes the form
IF ! HIX_CsrfValidToken( UPost( "_csrf" ), 3600 )
   USendError( 403, "Invalid CSRF token" )
   RETURN
ENDIF

11. Resource ID

Signs an opaque ID so it is not predictable in HTML forms.

Function Description
UResourceToHtml(cId) Generates <input type="hidden" name="_resource_id" value="..."> with signed ID
UGetResource([cToken]) Validates token and returns original ID; "" if invalid
// In the view (record list)
// {{ UResourceToHtml( hb_NToS(nId) ) }}

// In the POST action (delete, edit, ...)
cId := UGetResource()   // reads _resource_id from POST automatically
IF Empty( cId )
   USendError( 400, "Invalid resource ID" )
   RETURN
ENDIF
nId := Val( cId )

12. Flash messages

Temporary validation messages per form, stored in session and destroyed when read.

Method Description
UFlash([cFormId]) Creates a TFlash object for the specified form
oFlash:Set(cKey, xVal) Saves a flash value
oFlash:Get(cKey [, xDef]) Reads and deletes the flash value
oFlash:Has(cKey) .T. if value exists
oFlash:Delete(cKey) Deletes a value without reading it
oFlash:Clear() Clears all values for the form
oFlash:Save() Persists changes to session
oFlash:Destroy() Destructor: saves automatically when leaving scope
// Save error in the POST
oFlash := UFlash( "login-form" )
oFlash:Set( "error", "Incorrect credentials" )
oFlash:Set( "email", UPost( "email" ) )
oFlash:Save()
URedirect( "/login" )

// Read in the next GET
oFlash := UFlash( "login-form" )
cError := oFlash:Get( "error", "" )
cEmail := oFlash:Get( "email", "" )

13. Environment and configuration

Function Description
UEnv() Current environment: "dev" or "prod"
UIsDev() .T. if UEnv() == "dev"
UIsProd() .T. if UEnv() == "prod"
UConfig(cKey [, xDef]) Value from THixConfig by field name
UMwConfig(cSection, cKey [, xDef]) Value from www/middlewares/config.json section setup
UNow() Current timestamp as string "YYYYMMDDHHmmss"
URoot() Name of web root folder (default "www")
URootPath() Absolute path to web root with trailing separator
IF UIsDev()
   l( "Debug: " + hb_jsonEncode( hData ) )
ENDIF

cPort := UConfig( "nPort", "8080" )
cKey  := UMwConfig( "auth", "session_user_key", "_auth_user" )

14. Quick reference table

Read request

UMethod()           UPath()             UQuery()
UGet(k,d)           UPost(k,d)          UParam(k,d)
UHeader(k,d)        UCookie(k,d)        UBody()
UJson()             UContentType()      UContentLength()
UFiles()            URequest()          UContext()

Detect type

UIsGet()    UIsPost()   UIsAjax()   UIsHttps()
UIsJson()   UIsForm()   UIsMultipart()  UWantsJson()
UScheme()   UIP()       UHost()         UPort()

Send response

USendJson(x,n)      USendHtml(c,n)      USendText(c,n)
USendView(v,h)      USendEmpty()        USendError(n,c)
URedirect(u,n)      USend(x,n,m,h)

Control buffer

UWrite(c)   UEcho(c)    USetStatus(n)   USetMime(c)
UGetMime()  USetHeader(k,v)  USetCookie(k,v,n)  UFlush()

Streaming

USendStreamStart(m,n,h)   USendChunk(c)   USendStreamEnd()

Session and auth

USession()  USession(k)  USession(k,d)
UJwt()      UJwt(k)      UJwt(k,d)     UHasScope(s)
UCurrentUser()  UAuthUser(k,d)
UHasRole(r)     UHasRole(r,op)  UGetRoles()  UAuthLogout()

Validation

UValidate(h)    UValidatePost(h)  UValidateGet(h)
UValidateParams(h)  UValidateJson(h)  UValidateInput(h)  UValidateOrFail(h)
UIsMail(s)  UIsNumeric(v)  UIsInteger(v)  UIsUrl(s)  UIsIp(s)

Views and helpers

USendView(v,h)  UView(v,h)
UStr(u)  UDateToHtml(d)  ULogicToHtmlChecked(l)  UHtmlEncode(c)
UHashToHtmlSelect(a,s,k,v)  URoute(name, ...)  UOsFileName(f)

CSRF, Resource, Flash, Config

UCsrfToHtml()       HIX_CsrfValidToken(t,n)
UResourceToHtml(id) UGetResource()
UFlash(id)
UEnv()  UIsDev()  UIsProd()  UConfig(k,d)  UMwConfig(s,k,d)
UNow()  URoot()   URootPath()