====== std.net.rest ====== Session-basierter REST-Client auf Basis von ''std.net.http''. Nimmt eine vollständige Base-URL (''https://api.example.com/v1''), hält Host, Pfad und Auth-Header sitzungsweit und baut alle Request-Pfade automatisch zusammen. HTTP und HTTPS werden transparent unterstützt – das Protokoll wird aus der URL-Scheme erkannt. import std.net.rest; var client: int64 := alloc(REST_SIZE); RestClientInit(client, "https://api.example.com/v1" as int64, "my-bearer-token" as int64); var resp: HTTPResponse := RestGet(client, "/items" as int64); if (RestIsSuccess(resp.statusCode)) { PrintLn(resp.bodyPtr as pchar); } HTTPResponseFree(resp); RestClientFree(client); free(client, REST_SIZE); ---- ===== Imports ===== * ''std.net.http'' * ''std.net.socket'' * ''std.net.dns'' * ''std.net.tls'' * ''std.net.types'' * ''std.alloc'' ---- ===== RestClient-Struct ===== Der Caller alloziert ''REST_SIZE'' Bytes und gibt den Zeiger an ''RestClientInit'' weiter. Die Felder werden intern verwaltet – niemals direkt schreiben. ^ Konstante ^ Offset ^ Inhalt ^ | ''REST_OFF_HOST'' | 0 | Zeiger auf allozierte Host-Kopie (null-terminiert) | | ''REST_OFF_HOSTLEN'' | 8 | Länge des Host-Strings | | ''REST_OFF_BASEPATH'' | 16 | Zeiger auf allozierte BasePath-Kopie (null-terminiert) | | ''REST_OFF_PATHLEN'' | 24 | Länge des BasePath-Strings | | ''REST_OFF_AUTHHDRS'' | 32 | Zeiger auf Auth-Header-String (mmap'd) oder ''0'' | | ''REST_OFF_HTTPS'' | 40 | ''0'' = HTTP, ''1'' = HTTPS | | ''REST_OFF_PORT'' | 48 | TCP-Port; ''0'' = Default (80 / 443) | | ''REST_SIZE'' | — | **56** Bytes | ---- ===== Funktionen ===== ==== Client-Verwaltung ==== ^ Signatur ^ Beschreibung ^ | ''RestClientInit(client: int64, baseUrl: int64, token: int64): void'' | Parst ''baseUrl'' (Scheme, Host, BasePath), übernimmt optionalen Bearer-Token (''token=0'' für kein Auth) | | ''RestClientSetBearerToken(client: int64, token: int64): void'' | Setzt/ersetzt den ''Authorization: Bearer''-Header | | ''RestClientSetApiKey(client: int64, name: int64, value: int64): void'' | Fügt beliebigen Header hinzu (z. B. ''X-API-Key'') | | ''RestClientFree(client: int64): void'' | Gibt Host, BasePath und Auth-Header-Puffer frei | ==== HTTP-Methoden ==== Alle Methoden hängen BasePath + ''path'' zusammen und setzen automatisch die gespeicherten Auth-Header. ^ Signatur ^ Beschreibung ^ | ''RestGet(client: int64, path: int64): HTTPResponse'' | HTTP GET | | ''RestPost(client: int64, path: int64, body: int64, bodyLen: int64): HTTPResponse'' | HTTP POST mit beliebigem Body | | ''RestPut(client: int64, path: int64, body: int64, bodyLen: int64): HTTPResponse'' | HTTP PUT mit beliebigem Body | | ''RestDelete(client: int64, path: int64): HTTPResponse'' | HTTP DELETE | | ''RestPatch(client: int64, path: int64, body: int64, bodyLen: int64): HTTPResponse'' | HTTP PATCH mit beliebigem Body | ==== JSON-Convenience ==== Wie ''RestPost'' / ''RestPut'', setzen aber zusätzlich ''Content-Type: application/json''. ^ Signatur ^ Beschreibung ^ | ''RestJsonPost(client: int64, path: int64, json: int64, jsonLen: int64): HTTPResponse'' | POST mit ''Content-Type: application/json'' | | ''RestJsonPut(client: int64, path: int64, json: int64, jsonLen: int64): HTTPResponse'' | PUT mit ''Content-Type: application/json'' | ==== URL-Helfer ==== ^ Signatur ^ Beschreibung ^ | ''RestBuildPath(client: int64, path: int64, out: int64, outMax: int64): int64'' | Hängt BasePath und ''path'' zusammen (mit Slash-Deduplication); gibt resultierende Länge zurück | | ''RestQueryAppend(buf: int64, bufMax: int64, key: int64, value: int64): int64'' | Hängt ''?key=value'' bzw. ''&key=value'' an; der Wert wird percent-kodiert (RFC 3986 unreserved chars); gibt neue String-Länge zurück | ==== Statuscodes prüfen ==== ^ Signatur ^ Rückgabe ^ | ''RestIsSuccess(statusCode: int64): int64'' | ''1'' wenn 2xx | | ''RestIsClientError(statusCode: int64): int64'' | ''1'' wenn 4xx | | ''RestIsServerError(statusCode: int64): int64'' | ''1'' wenn 5xx | ---- ===== Codebeispiele ===== ==== JSON POST mit Bearer-Token ==== import std.net.rest; var client: int64 := alloc(REST_SIZE); RestClientInit(client, "https://api.example.com/v2" as int64, "eyJhbGci..." as int64); var body: pchar := "{\"name\":\"Alice\",\"active\":true}"; var resp: HTTPResponse := RestJsonPost( client, "/users" as int64, body as int64, StrLen(body)); if (RestIsSuccess(resp.statusCode)) { PrintLn("Erstellt: " + IntToStr(resp.statusCode)); } else { PrintLn("Fehler: " + IntToStr(resp.statusCode)); } HTTPResponseFree(resp); RestClientFree(client); free(client, REST_SIZE); ==== Query-String aufbauen ==== import std.net.rest; var client: int64 := alloc(REST_SIZE); RestClientInit(client, "https://search.example.com" as int64, 0); // Pfad mit Query-Parametern aufbauen var buf: int64 := alloc(512); var blen: int64 := 0; poke8(buf, 0); // leerer String als Ausgangspunkt // /products?category=tools&q=schrauber var pathStart: pchar := "/products"; var pi: int64 := 0; while (peek8(pathStart as int64 + pi) != 0) { poke8(buf + pi, peek8(pathStart as int64 + pi)); pi := pi + 1; } poke8(buf + pi, 0); RestQueryAppend(buf, 512, "category" as int64, "tools" as int64); RestQueryAppend(buf, 512, "q" as int64, "schrauber" as int64); var resp: HTTPResponse := RestGet(client, buf); HTTPResponseFree(resp); free(buf, 512); RestClientFree(client); free(client, REST_SIZE); ==== API-Key als Custom-Header ==== import std.net.rest; var client: int64 := alloc(REST_SIZE); RestClientInit(client, "https://api.service.io/v1" as int64, 0); RestClientSetApiKey(client, "X-API-Key" as int64, "secret-key-12345" as int64); var resp: HTTPResponse := RestGet(client, "/status" as int64); HTTPResponseFree(resp); RestClientFree(client); free(client, REST_SIZE); ---- ===== Hinweise ===== * **Rückgabe ist ''HTTPResponse''**: Jede Methode gibt eine ''HTTPResponse'' aus ''std.net.http'' zurück — nach der Verarbeitung immer ''HTTPResponseFree(resp)'' aufrufen. * **BasePath + path**: ''RestClientInit'' mit ''https://api.example.com/v1'' und ''RestGet(client, "/items")'' ergibt ''GET /v1/items''. Doppelte Slashes an der Naht werden automatisch bereinigt. * **''REST_SIZE'' Bytes extern allozieren**: Der Struct gehört dem Caller — ''alloc(REST_SIZE)'' vor ''RestClientInit'', ''free(client, REST_SIZE)'' nach ''RestClientFree''. * **''RestQueryAppend'' percent-kodiert den Wert**: Erlaubte Zeichen ohne Kodierung (RFC 3986 unreserved): ''A-Z'', ''a-z'', ''0-9'', ''-'', ''.'', ''_'', ''~''. Alles andere wird als ''%XX'' kodiert. Der Key-Parameter wird nicht kodiert. * **Thread-Sicherheit**: Jede Sitzung (''client''-Zeiger) darf nur von einem Thread gleichzeitig verwendet werden. Mehrere Threads = mehrere Client-Instanzen. * **HTTPS transparent**: Wenn die Base-URL mit ''https://'' beginnt, verwendet ''restSend'' intern ''TLSConnect'' / ''TLSWrite'' / ''TLSRead'' — kein Unterschied in der aufrufenden API. ---- ===== Quelldatei ===== ^ Unit ^ Datei ^ | ''std.net.rest'' | ''std/net/rest.lyx'' | Letzte Aktualisierung: 2026-06-15