API-Referenz
Die tatsächliche Oberfläche von ApiController, req und res: was es gibt, mit Signatur. Steht ein Member nicht hier, gibt es ihn nicht.
ApiController
Basisklasse, von der alle Controller erben. Sie liefert die JSON-Hilfsmittel, die Ergebnisse mit ihrem Statuscode, die Protokollierung und die beiden Haken des Lebenszyklus. Das JWT wird hier NICHT erzeugt: es stellt die Middleware aus, wenn der Login mit X-Auth-Status antwortet.
Antwortmethoden
| Eigenschaft / Methode | Typ | Beschreibung |
Ok(obj) | 200 | Das normale Ergebnis. Serialisiert das Objekt und antwortet mit 200. Der bevorzugte Weg, der das responseformat des Servers beachtet. |
OkRaw(json) | 200 | Dasselbe, aber mit fertigem JSON. Der Partner von TableToJson(). |
Created(obj, location) | 201 | Für das, was Sie gerade angelegt haben. location ist optional und setzt den Location-Header. |
NoContent() | 204 | Es hat geklappt, und es gibt nichts zurückzugeben. Typisch für ein DELETE. |
BadRequest(msg, code) | 400 | Was der Client geschickt hat, taugt nicht. code ist Ihrer und reist in den Problem Details mit. |
Unauthorized(msg) · Forbidden(msg) | 401 · 403 | Nicht ausgewiesen, oder ausgewiesen und ohne Recht. |
NotFound(msg) | 404 | Das Angeforderte gibt es nicht. |
Fail(status, msg, code) | frei wählbar | Jeder andere Fehler, mit dem Statuscode, den Sie angeben. |
newObject(fields) | Object | Erzeugt ein VFP-Objekt mit diesen Eigenschaften auf NULL. fields ist eine kommagetrennte Liste. |
ToJson(obj) · ParseJson(txt) | String · Object | Serialisieren und deserialisieren, über JSONFox. Die Umkehrung von ToJson heißt ParseJson; ein FromJson gibt es nicht. |
LogInfo · LogWarning · LogError · LogFromException | Void | Schreiben in das Serverprotokoll. Das letzte gibt die ganze Ausnahme samt Zeile aus. |
Was bei einem Fehler zurückkommt
Seit 0.9.15 werden Fehlerergebnisse als Problem Details (RFC 9457) beschrieben - dasselbe Format wie in ASP.NET - und mit Content-Type: application/problem+json; charset=utf-8 ausgeliefert.
{
"type": "about:blank",
"title": "Not Found",
"status": 404,
"detail": "No existe el artículo ZZZZ",
"instance": "/articulos/ZZZZ",
"code": "not_found"
}
detail ist Ihre Nachricht, die Sie an this.NotFound(...) übergeben haben; code ist Ihrer und reist als Erweiterungsmitglied, was die RFC für Fremdes erlaubt; title ist die Reason-Phrase des Codes und wird nicht übersetzt, weil sie maschinenlesbar ist; instance setzt die Engine. Die 200er ändern sich NICHT: sie kommen ohne Umschlag. Und wenn Ihr Server responseformat: foxserver deklariert, ändert sich auch dieses Format nicht.
Lebenszyklus-Hooks
| Eigenschaft / Methode | Typ | Beschreibung |
BeforeEndpoint(req, res) | Boolean | Läuft vor jedem Endpunkt DIESES CONTROLLERS. Ein .F. bricht die Anfrage ab. Hier öffnet man die Tabellen. |
AfterEndpoint(req, res) | Void | Läuft nach jedem Endpunkt dieses Controllers. Hier schließt man sie wieder. |
FoxServerRequest
Objekt, das alle Informationen der eingehenden HTTP-Anfrage kapselt. Als Parameter req in allen Endpunkten verfügbar.
Eigenschaften
| Eigenschaft / Methode | Typ | Beschreibung |
Method | String | GET, POST, PUT, PATCH, DELETE |
uri | Object | Ein OBJEKT, keine Zeichenkette: Scheme, Host, Port, AbsolutePath, PathAndQuery und AbsoluteUri. Der Pfad ohne Query steht in uri.AbsolutePath. |
Params | Object | Parameter der Route. req.Params.id aus /{id}, oder req.GetParam("id", "") mit Vorgabewert. |
query | Object | Query-String. req.query.page aus ?page=2, oder req.GetQuery("page", 1). |
Headers | Object | Die Header. Gelesen mit req.GetHeader("Authorization", ""), geprüft mit req.HasHeader(). |
RawBody | String | Der unverarbeitete Rumpf. Auch req.GetRawBody(). Das ist zu lesen, wenn der Rumpf fehlen kann oder ein Datum nicht durch JSONFox laufen soll. |
json | Object | Der bereits geparste JSON-Rumpf. req.HasJsonBody() sagt, ob es ihn gibt, und req.HasJsonError() / req.JsonError, wenn er nicht geparst werden konnte. |
ContentType | String | Der Content-Type der Anfrage. |
AuthenticatedUser | Object | Bei geprüftem Token: .id, .name und .role. |
Claims | Object | Die zusätzlichen Claims des Tokens. req.GetClaim(Name, Vorgabe), req.HasClaim(Name) und req.ClaimNames(). |
MultipartData · FormFields | Object | Uploads und Formulare: req.file(Feld), req.files(Feld), req.HasFiles(), req.GetFormField(Feld, Vorgabe). |
req.path, req.body, req.remoteIP und req.scheme gibt es nicht Und eine nicht vorhandene Eigenschaft zu lesen liefert Leere, ohne einen Fehler zu melden – die unangenehmste Art, sich zu irren. Der Pfad steht in req.uri.AbsolutePath, der Rumpf in req.RawBody und die Methode in req.Method. Die IP des Clients wird dem Controller NICHT zugänglich gemacht.
Methoden
ABCParameter, Header und JSON-Rumpf lesen
* Un parametro de ruta, con valor por defecto
lcId = req.GetParam("id", "")
* Una cabecera: GetHeader, no req.headers[...]
IF req.HasHeader("X-Api-Key")
lcKey = req.GetHeader("X-Api-Key", "")
ENDIF
* El JSON del cuerpo, con cuidado: leer una propiedad que no vino
* da error 1734, asi que se comprueba antes o se envuelve en TRY.
IF req.HasJsonBody() AND !ISNULL(req.json)
TRY
lcCiudad = NVL(req.json.direccion.ciudad, "")
CATCH
lcCiudad = ""
ENDTRY
ENDIF
FoxServerResponse
Objekt zum Erstellen und Senden der HTTP-Antwort. Als Parameter res in allen Endpunkten verfügbar. Alle Methoden sind verkettbar (geben res zurück).
| Eigenschaft / Methode | Beschreibung |
status(code) | Setzt den HTTP-Statuscode (200, 201, 400, 401, 404, 500...) |
json(jsonStr) | Sendet JSON-Body. Setzt Content-Type: application/json automatisch. |
send(text) | Sendet Klartext oder HTML als Body. |
header(key, value) | Fügt einen Antwort-Header hinzu oder überschreibt ihn. Verkettbar. |
location(url) | Setzt den Location-Header. Mit status(301) oder status(302) für Weiterleitung verwenden. |
sendFile(path, disp) | Sendet eine Datei. disp kann "inline" (im Browser anzeigen) oder "attachment" (Download erzwingen) sein. |
events(tipo) | Deklariert einen SSE-Ereignistyp, den dieser Endpunkt unterstützt. Ohne Deklaration kann ihn niemand abonnieren. |
emit(tipo, json) | Sendet ein SSE-Ereignis aus einem beliebigen Endpunkt. Framing, Retry und Pings übernimmt die Middleware. |
Beispiel
ABCAntworten durch Verketten der res-Methoden
* Standard success response
res.status(200).json(THIS.ToJson(loResult))
* Created with location header
res.status(201)
.header("Location", "/api/v1/users/" + lcNewId)
.json(THIS.ToJson(loResult))
* Error response
res.status(400).json('{"error":"Name is required"}')
* File download
res.status(200)
.header("Content-Disposition", 'attachment; filename="report.pdf"')
.sendFile("C:\reports\report.pdf", "attachment")
ApiController: Detaillierte Methoden
Objekt- und JSON-Verwaltung
| Eigenschaft / Methode | Beschreibung |
NewObject(fields) | Erstellt ein VFP-Objekt mit auf NULL initialisierten Eigenschaften. fields ist eine kommagetrennte Liste: "status,data,message". |
NewObjectFromCursor(cursor, session) | Erstellt ein VFP-Objekt mit der Struktur eines Cursors. Nutzlich für Vorlagen auf Basis von Tabellenstrukturen. |
ToJson(obj) | Serialisiert ein VFP-Objekt via JSONFox in einen JSON-String. |
ParseJson(jsonStr) | Deserialisiert einen JSON-String in ein VFP-Objekt via JSONFox. |
TableToJson(cursor, currentRow) | Konvertiert einen Cursor in JSON. currentRow=.T. gibt den aktuellen Datensatz als Objekt zurück; .F. gibt alle als Array. |
TableToJsonObject(cursor, currentRow, session) | Wie TableToJson, gibt aber eine VFP-Objektkollektion statt eines JSON-Strings zurück. |
MasterToJSON(master, detail, expr, attr) | Generiert hierarchisches Master-Detail-JSON. expr ist die Join-Bedingung, attr der Name des Detail-Arrays im JSON. |
ABCMasterToJSON: Bestellungen mit ihren Positionen
* Ejemplo: maestro-detalle con MasterToJSON
SELECT id, fecha, cliente FROM pedidos INTO CURSOR curPedidos
SELECT id, pedido_id, producto, cantidad FROM lineas INTO CURSOR curLineas
lcJson = THIS.MasterToJSON("curPedidos", "curLineas", "curPedidos.id = curLineas.pedido_id", "lineas")
res.status(200).json(lcJson)
Text- und Formatierungshilfsprogramme
| Eigenschaft / Methode | Beschreibung |
Format(template, p0..p10) | Ersetzt Platzhalter {0}, {1}, ... im Template. Ahnlich wie String.Format in C#. |
EscapeCharsToJSON(text) | Maskiert Sonderzeichen für die sichere Verwendung in JSON. |
EscapeCharsToHTML(text) | Maskiert Sonderzeichen für die Verwendung in HTML. |
Content(req, source) | Serialisiert source in das Format, das der Client über Accept-Header oder ?format= anfordert (json, xml, csv). |
TableToXml(cursor, currentRow) | Konvertiert einen Cursor in XML. |
TableToCsv(cursor, currentRow) | Konvertiert einen Cursor in CSV. |
Datum-, Codierungs- und ID-Dienstprogramme
| Eigenschaft / Methode | Typ | Beschreibung |
NewGuid() | String | Generiert eine GUID ohne geschweifte Klammern oder Bindestriche. Für alle PKs verwenden. |
DTOUNX(dt, useMsec) | Number | Konvertiert einen VFP-DateTime in einen Unix-Zeitstempel. useMsec=.T. gibt Millisekunden zurück. |
UNXTOD(timestamp) | DateTime | Konvertiert einen Unix-Zeitstempel (Sekunden oder Millisekunden) in einen VFP-DateTime. |
Base64URLEncode(input) | String | Codiert in Base64URL (wird in JWT und sicheren URLs verwendet). |
Base64URLDecode(input) | String | Decodiert von Base64URL. |
ABCUnix-Zeitstempel, GUIDs und Format
* Conversiones de fecha
lnTs = THIS.DTOUNX(DATETIME(), .F.) && segundos
ldFecha = THIS.UNXTOD(1716825600)
* Identificadores
lcId = THIS.NewGuid() && "a1b2c3d4e5f647g8h9i0j1k2l3m4n5o6"
* Formato de mensajes
lcMsg = THIS.Format("Usuario {0} accedio a {1} desde {2}", lcUser, lcUrl, lcIp)
Lebenszyklus und Ressourcen
| Eigenschaft / Methode | Beschreibung |
Initialize() | Wird beim Erstellen einer Instanz automatisch ausgeführt. Konfiguriert cPath, lädt JSONFox und ApiService. |
LoadJsonFox() | Lädt JSONFox.app wenn noch nicht verfügbar. Wird intern von Initialize() aufgerufen. |
GetGlobalResource(name) | Ruft eine gemeinsame globale Ressource (Verbindungen, Konfigurationen) über den Anwendungslebenszyklus ab. |
SetWorkingDirectory(path) | Setzt cPath und ruft Initialize() auf. Nutzlich für Tests außerhalb des FoxServer-Zyklus. |
CleanUp() / Release() / Dispose() | Gibt Ressourcen am Ende des Controller-Lebenszyklus frei. Werden automatisch von FoxServer aufgerufen. |
FoxServerRequest: Detaillierte Methoden
| Eigenschaft / Methode | Beschreibung |
GetHeader(key, default) | Gibt den Wert des angegebenen HTTP-Headers zurück. Falls nicht vorhanden wird default zuruckgegeben. |
GetParam(key, default) | Gibt einen URL-Routenparameter zurück (z.B. {id}). Gibt default zurück wenn nicht vorhanden. |
GetQuery(key, default) | Gibt einen Query-String-Parameter zurück (?key=value). Gibt default zurück wenn nicht vorhanden. |
GetQueryParams() | Gibt alle Query-Parameter als FoxServerTupleDictionary zurück. |
HasJsonBody() | .T. wenn die Anfrage einen gültig geparsten JSON-Body hat. Vor dem Zugriff auf req.json.* pruefen. |
GetRawBody() | Gibt den ungeparsten Anfrage-Body zurück. Notwendig für die Webhook-Signaturverifizierung. |
GetFormField(key, default) | Gibt den Wert eines Multipart- oder URL-kodierten Formularfeldes zurück. |
HasFormField(key) | .T. wenn das Formularfeld in der Anfrage vorhanden ist. |
File(field) | Gibt das Objekt einer über Multipart hochgeladenen Datei zurück. Bietet FileName und SaveToFile(path). |
Files(field) | Gibt eine Kollektion von Dateien zurück, die unter demselben Feldnamen hochgeladen wurden. |
ABCHeader, Rumpf, hochgeladene Dateien und Webhook-Signatur
* Leer headers y params
lcToken = req.GetHeader("Authorization", "")
lcId = req.GetParam("id", "")
lcPage = req.GetQuery("page", "1")
* Verificar body antes de acceder
IF req.HasJsonBody()
lcEmail = req.json.email
ELSE
res.status(400).json('{"error":"JSON body required"}')
RETURN
ENDIF
* Subir archivo
loFile = req.File("avatar")
IF !ISNULL(loFile)
loFile.SaveToFile(THIS.cPath + "uploads\" + loFile.FileName)
ENDIF
* Webhook: raw body para HMAC
lcRaw = req.GetRawBody()
lcSig = req.GetHeader("X-Signature", "")
Kollektionen
FoxServerTupleDictionary
Schlüssel-Wert-Worterbuch für Headers, Params und Query. Zugriff ohne Beachtung der Groß-/Kleinschreibung.
| Eigenschaft / Methode | Beschreibung |
Count | Anzahl der Eintrage. |
GetKey(n) | Schlüssel an Position n (Basis 1). |
GetValue(n) | Wert an Position n. |
Contains(key) | .T. wenn der Schlüssel vorhanden ist. |
GetValueByKey(key) | Wert nach Schlusselnamen. |
ABCAlle Query-Parameter durchlaufen
* Iterar todos los query params
loParams = req.GetQueryParams()
FOR lnI = 1 TO loParams.Count
lcKey = loParams.GetKey(lnI)
lcVal = loParams.GetValue(lnI)
THIS.LogInfo(THIS.Format("Param {0}={1}", lcKey, lcVal))
ENDFOR
FoxServerTuple
Einfaches Schlüssel-Wert-Paar. Interne Komponente von FoxServerTupleDictionary.
| Eigenschaft / Methode | Beschreibung |
Key | Name des Schlüssels. |
Value | Zugeordneter Wert. |
Weiter: FAQ →