IR
irwinrodriguez.dev
Zurück zur Dokumentation

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 / MethodeTypBeschreibung
Ok(obj)200Das normale Ergebnis. Serialisiert das Objekt und antwortet mit 200. Der bevorzugte Weg, der das responseformat des Servers beachtet.
OkRaw(json)200Dasselbe, aber mit fertigem JSON. Der Partner von TableToJson().
Created(obj, location)201Für das, was Sie gerade angelegt haben. location ist optional und setzt den Location-Header.
NoContent()204Es hat geklappt, und es gibt nichts zurückzugeben. Typisch für ein DELETE.
BadRequest(msg, code)400Was der Client geschickt hat, taugt nicht. code ist Ihrer und reist in den Problem Details mit.
Unauthorized(msg) · Forbidden(msg)401 · 403Nicht ausgewiesen, oder ausgewiesen und ohne Recht.
NotFound(msg)404Das Angeforderte gibt es nicht.
Fail(status, msg, code)frei wählbarJeder andere Fehler, mit dem Statuscode, den Sie angeben.
newObject(fields)ObjectErzeugt ein VFP-Objekt mit diesen Eigenschaften auf NULL. fields ist eine kommagetrennte Liste.
ToJson(obj) · ParseJson(txt)String · ObjectSerialisieren und deserialisieren, über JSONFox. Die Umkehrung von ToJson heißt ParseJson; ein FromJson gibt es nicht.
LogInfo · LogWarning · LogError · LogFromExceptionVoidSchreiben 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 / MethodeTypBeschreibung
BeforeEndpoint(req, res)BooleanLäuft vor jedem Endpunkt DIESES CONTROLLERS. Ein .F. bricht die Anfrage ab. Hier öffnet man die Tabellen.
AfterEndpoint(req, res)VoidLä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 / MethodeTypBeschreibung
MethodStringGET, POST, PUT, PATCH, DELETE
uriObjectEin OBJEKT, keine Zeichenkette: Scheme, Host, Port, AbsolutePath, PathAndQuery und AbsoluteUri. Der Pfad ohne Query steht in uri.AbsolutePath.
ParamsObjectParameter der Route. req.Params.id aus /{id}, oder req.GetParam("id", "") mit Vorgabewert.
queryObjectQuery-String. req.query.page aus ?page=2, oder req.GetQuery("page", 1).
HeadersObjectDie Header. Gelesen mit req.GetHeader("Authorization", ""), geprüft mit req.HasHeader().
RawBodyStringDer unverarbeitete Rumpf. Auch req.GetRawBody(). Das ist zu lesen, wenn der Rumpf fehlen kann oder ein Datum nicht durch JSONFox laufen soll.
jsonObjectDer bereits geparste JSON-Rumpf. req.HasJsonBody() sagt, ob es ihn gibt, und req.HasJsonError() / req.JsonError, wenn er nicht geparst werden konnte.
ContentTypeStringDer Content-Type der Anfrage.
AuthenticatedUserObjectBei geprüftem Token: .id, .name und .role.
ClaimsObjectDie zusätzlichen Claims des Tokens. req.GetClaim(Name, Vorgabe), req.HasClaim(Name) und req.ClaimNames().
MultipartData · FormFieldsObjectUploads 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

Parameter, 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 / MethodeBeschreibung
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

Antworten 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 / MethodeBeschreibung
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.
MasterToJSON: 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 / MethodeBeschreibung
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 / MethodeTypBeschreibung
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.
Unix-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 / MethodeBeschreibung
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 / MethodeBeschreibung
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.
Header, 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 / MethodeBeschreibung
CountAnzahl 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.
Alle 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 / MethodeBeschreibung
KeyName des Schlüssels.
ValueZugeordneter Wert.

Weiter: FAQ →