====== 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