IR
irwinrodriguez.dev
Zuruck zur Dokumentation

Routing

FoxServer verwendet HELP-Kommentare in VFP-Methoden zur Routendeklaration. Es gibt keine separaten Routenkonfigurationsdateien: die Deklaration befindet sich direkt neben dem Controller-Code.

HELP-Kommentar-Syntax

Jede Endpunkt-Methode muss einen HELP-Kommentar in diesem Format haben:

PROCEDURE NombreMetodo(req, res) HELP "METODO: ruta/path [public]"
TeilBeschreibungBeispiel
HTTP-MethodeGET, POST, PUT, PATCH, DELETE, HEADGET
RoutePfad relativ zum Server-Prafix. Kann {Parameter} enthalten.products/{id}
Sichtbarkeitpublic = kein JWT erforderlich. Ohne dieses Token = JWT obligatorisch.public

Unterstutzte HTTP-Methoden

MethodeBeschreibungHat Body?Routenbeispiel
GETDaten abrufenNeinGET: products public
POSTRessource erstellenJaPOST: products public
PUTAktualisieren (vollstandig)JaPUT: products/{id} public
PATCHAktualisieren (partiell)JaPATCH: products/{id} public
DELETERessource loschenNeinDELETE: products/{id} public
HEADNur HeaderNeinHEAD: products public

URL-Parameter

* Single parameter
PROCEDURE GetProduct(req, res) HELP "GET: products/{id} public"
    LOCAL lcId
    lcId = req.params.id          && /api/products/42 -> "42"
    res.status(200).json(...)
ENDPROC

* Multiple parameters
PROCEDURE GetVariant(req, res) HELP "GET: products/{id}/variants/{vid} public"
    LOCAL lcProductId, lcVariantId
    lcProductId = req.params.id   && /api/products/42/variants/black -> "42"
    lcVariantId = req.params.vid  && "black"
    res.status(200).json(...)
ENDPROC

Query-String

Query-String-Parameter (?Schlussel=Wert) werden uber req.query abgerufen:

PROCEDURE SearchProducts(req, res) HELP "GET: products/search public"
    * GET /api/products/search?name=Widget&minprice=10&page=2
    LOCAL lcName, lnMin, lnPage
    lcName  = req.query.name               && "Widget"
    lnMin   = VAL(req.query.minprice)      && 10
    lnPage  = IIF(EMPTY(req.query.page), 1, VAL(req.query.page))
    res.status(200).json(...)
ENDPROC

Request-Objekt — Eigenschaften

EigenschaftTypBeschreibung
methodStringHTTP-Methode (GET, POST, usw.)
urlUriVollstandige Anfrage-URL
pathStringPfad ohne Query-String
paramsObjectURL-Parameter ({id} → params.id)
queryObjectQuery-String-Parameter (?key=val)
headersDictHTTP-Header (Gro-/Kleinschreibung egal)
bodyStringAnfrage-Body als Klartext
jsonObjectGeparster JSON-Body (wenn Content-Type: application/json)
contentTypeStringWert des Content-Type-Headers
remoteIPStringIP-Adresse des Clients

Response-Objekt — Methoden

MethodeSignaturBeschreibung
status(code)res.status(200)Setzt den HTTP-Code. Gibt res fur Verkettung zuruck.
json(jsonStr)res.json('{"ok":true}')Sendet JSON-Body. Setzt Content-Type: application/json.
send(text)res.send("Hallo")Sendet Klartext oder HTML.
header(key, val)res.header("X-Id","123")Fugt einen Antwort-Header hinzu oder uberschreibt ihn.
location(url)res.location("/api/v2")Setzt den Location-Header (fur Weiterleitungen).
sendFile(path, disp)res.sendFile("C:\\rep.pdf","attachment")Sendet eine Datei. disp: "inline" oder "attachment".
* Chaining example — multiple headers + JSON response
res.status(201)
   .header("X-Resource-Id", lcNewId)
   .header("Cache-Control", "no-cache")
   .json(THIS.ToJson(loResponse))

Controller-Lebenszyklus

Jeder Controller kann Hooks definieren, die vor und nach jedem Endpunkt ausgefuhrt werden:

DEFINE CLASS ProductsController AS ApiController OLEPUBLIC

    FUNCTION BeforeEndpoint(req, res) AS BOOLEAN
        SET DELETED ON
        SET EXCLUSIVE OFF
        USE data\products SHARED
        RETURN .T.   && .F. here would abort the request
    ENDFUNC

    PROCEDURE AfterEndpoint(req, res)
        CLOSE DATABASES ALL
    ENDPROC

    PROCEDURE GetProducts(req, res) HELP "GET: products public"
        && Products table is already open (BeforeEndpoint)
        && It will be closed automatically (AfterEndpoint)
        res.status(200).json(...)
    ENDPROC

ENDDEFINE

Offentliche vs. geschutzte Routen

Die Sichtbarkeit wird mit dem public-Schlusselwort im HELP-Kommentar gesteuert:

* PUBLIC endpoint — no JWT needed
PROCEDURE GetProducts(req, res) HELP "GET: products public"
    res.status(200).json(...)
ENDPROC

* PRIVATE endpoint — JWT required (omit "public")
PROCEDURE DeleteProduct(req, res) HELP "DELETE: products/{id}"
    && Client must send: Authorization: Bearer eyJhb...
    res.status(200).json(...)
ENDPROC
Wenn JWT-Middleware aktiv ist, mussen Endpunkte ohne public den Token im Header Authorization: Bearer {token} senden.

Weiter: Middleware →