Hello friends,
I am now trying to convert my microservice, which previously worked via request and response JSON files, to an HTTP server using Harbour.
I'm curious to see the results.
Here is a first draft - I will try now testing:
Best regards,
Otto
I am now trying to convert my microservice, which previously worked via request and response JSON files, to an HTTP server using Harbour.
I'm curious to see the results.
Here is a first draft - I will try now testing:
//============================================================================//
// //
// HARBOUR MICROSERVICE β HTTP JSON //
// //
// Ziel: //
// - Microservice, der eine DBF-Datei (KUNDEN.DBF) mit CDX-Index //
// ΓΌber einen lokalen HTTP-Endpunkt abfragt //
// - Bei GET-Request wie //
// http://localhost:9090/search?name=ABCD //
// werden alle Kunden geliefert, deren Name mit "ABCD" beginnt //
// //
// Sicherheit: //
// - Der Server bindet NUR auf 127.0.0.1 (localhost) //
// β keine Verbindung von auΓen mΓΆglich //
// //
//============================================================================//
#include "hbcompat.ch"
#include "fileio.ch"
#include "hbjson.ch"
REQUEST DBFCDX
REQUEST HB_INET
REQUEST HB_SOCKET
FUNCTION Main()
LOCAL oSocket, oListen, cRequest, cName, hResult, aResult := {}
LOCAL cLine, cParam, aParam, cKey
LOCAL cDBF := "x:\xwhdaten\DATAWIN\KUNDEN.dbf"
// Starte Server: lausche NUR auf 127.0.0.1:9090 β nur lokal erreichbar!
oListen := hb_inetCreate()
IF ! hb_inetBind(oListen, 9090, "127.0.0.1")
? "Fehler: Port 9090 ist nicht verfΓΌgbar oder bereits belegt."
RETURN
ENDIF
? "Microservice lΓ€uft lokal auf http://127.0.0.1:9090"
// Datenbank vorbereiten (KUNDEN.DBF mit Index KU_NAME)
USE (cDBF) ALIAS kunden NEW SHARED VIA "DBFCDX"
SET INDEX TO x:\xwhdaten\DATAWIN\KUNDEN.CDX
ORDSETFOCUS("KU_NAME") // Suchindex
// Endlosschleife: Anfragen verarbeiten
DO WHILE .T.
oSocket := hb_inetAccept(oListen)
IF oSocket == NIL
LOOP
ENDIF
cRequest := hb_inetRecvLine(oSocket) // z.β―B. "GET /search?name=ABCD HTTP/1.1"
IF cRequest == NIL
hb_inetClose(oSocket)
LOOP
ENDIF
IF "GET /search?" $ cRequest
// ==== Anfrage parsen ====
cParam := StrToken(cRequest, "?", 2) // hole "name=ABCD HTTP/1.1"
aParam := hb_aTokens(StrToken(cParam, " ", 1), "&") // zerlege in name=ABCD, ...
cName := "" // Suche nach Name initialisieren
FOR EACH cLine IN aParam
a := hb_aTokens(cLine, "=")
IF Lower(a[1]) == "name"
cName := Upper(UrlDecode(a[2]))
ENDIF
NEXT
// ==== Suche starten ====
IF !Empty(cName)
DBSEEK(cName)
DO WHILE !EOF() .AND. Left(Upper(TRIM(kunden->name)), Len(cName)) == cName
AAdd(aResult, { ;
"name" => kunden->name, ;
"plz" => kunden->plz, ;
"ort" => kunden->ort ;
})
DBSKIP()
ENDDO
ENDIF
// ==== Ergebnis vorbereiten ====
hResult := { ;
"status" => "ok", ;
"query" => cName, ;
"results" => aResult }
// ==== JSON-Antwort senden ====
hb_inetSend(oSocket, "HTTP/1.1 200 OK" + CRLF )
hb_inetSend(oSocket, "Content-Type: application/json" + CRLF + CRLF )
hb_inetSend(oSocket, hb_jsonEncode(hResult) + CRLF )
ELSE
// 404 bei nicht unterstΓΌtztem Request
hb_inetSend(oSocket, "HTTP/1.1 404 Not Found" + CRLF + CRLF )
ENDIF
// Verbindung schlieΓen und Daten zurΓΌcksetzen
hb_inetClose(oSocket)
aResult := {} // Ergebnisse fΓΌr nΓ€chsten Request leeren
ENDDO
CLOSE kunden
RETURN NIL
// Hilfsfunktion: URL-Parameter dekodieren (z.β―B. %20 β Leerzeichen)
STATIC FUNCTION UrlDecode( c )
LOCAL i, cOut := "", nLen := Len(c), nChar
i := 1
DO WHILE i <= nLen
IF SubStr(c, i, 1) == "%"
nChar := Val( "0x" + SubStr(c, i+1, 2) )
cOut += Chr(nChar)
i += 3
ELSE
cOut += SubStr(c, i, 1)
i++
ENDIF
ENDDO
RETURN cOutBest regards,
Otto