HTTP im Überblick
Das HTTP-Modul ist getrennt von den I/O-Broker-Actors — HTTP-Server passen nicht in die Form “eine Verbindung, viele Nachrichten”, deshalb bekommen sie eine eigene DSL und Backend- Abstraktion.
import { ActorSystem } from 'actor-ts';import { path, get, post, completeJson, entity, concat } from 'actor-ts/http';
const system = ActorSystem.create('my-app');
const routes = path('api', path('orders', concat( get(async () => completeJson(200, { orders: [] })), post(async (req) => { const order = entity<NewOrder>(req); // ... behandeln ... return completeJson(201, { id: 'o-1' }); }), ), ),);
const binding = await system.http(8080).bind(routes);console.log(`gebunden auf ${binding.host}:${binding.port}`);Drei Dinge passieren hier:
- Die Route-DSL —
path,get,post,concatkomponieren einen Routenbaum. Typsicher; wird beim Bind zu einer flachen Liste kompiliert. - Der Marshaller —
entity<T>(req)dekodiert den Request- Body je nach Content-Type;completeJson/completeTextencoden die Response. - Der Shortcut —
system.http(port).bind(routes)startet einen Server mit dem Standard-Fastify-Backend. Für ein anderes Backend übergibst Dubackend:(siehe unten).
Die drei Bausteine
Abschnitt betitelt „Die drei Bausteine“| Baustein | Lebt in | Seite |
|---|---|---|
| Routing | actor-ts/http exportiert path, get, post, complete* usw. | Route-DSL |
| Marshalling | entity<T>(req)-Dekodierung + completeJson-Kodierung. | Marshalling |
| Backend | Pluggable HTTP-Server — Fastify per Default, Hono, Express. | Backends |
Die DSL baut einen In-Memory-Routenbaum;
system.http(...).bind(routes) flacht ihn ab und registriert
alles beim gewählten Backend.
Die Backends
Abschnitt betitelt „Die Backends“import { HonoBackend } from 'actor-ts/http';
// Default — keine Einrichtung nötig; Fastify ist eine Hard-Dependency:await system.http(8080).bind(routes);
// Explizite Wahl (Express / Hono sind Peer-Deps; Opt-in):await system.http(8080, { backend: new HonoBackend() }).bind(routes);
// Volle Kontrolle — die Extension-Surface bleibt erhalten:import { HttpExtensionId } from 'actor-ts';await system.extension(HttpExtensionId) .newServerAt('0.0.0.0', 8080) .useBackend(new HonoBackend()) .bind(routes);| Backend | Runtime-Eignung | Wann |
|---|---|---|
FastifyBackend (Default) | Bun, Node | Produktions-Default — Fastify ist das am stärksten kampferprobte. |
ExpressBackend | Node, Bun | Das bestehende Express-Middleware-Ökosystem passt sauber rein. |
HonoBackend | Bun, Node, Deno | Schlank + edge-tauglich; die Bun- und Deno-nativeste Option. |
Alle drei implementieren dasselbe HttpServerBackend-Interface —
die Route-DSL kompiliert identisch; das Backend besitzt nur die
Listen-/Dispatch-Schleife.
Siehe die Backend-Seiten für die Konfigurationsoptionen, die jedes akzeptiert.
Der HTTP-Client
Abschnitt betitelt „Der HTTP-Client“const response = await http.singleRequest({ method: 'POST', url: 'https://api.example.com/orders', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ sku: 'book-1' }),});
console.log(response.status, response.body);Der gemeinsame Client umschließt das native fetch der Runtime.
Funktioniert identisch auf Bun, Node und Deno (jede unterstützte
Runtime hat fetch eingebaut).
Für aufwendigere Client-Muster (Retries, Caching) wickle den Client in einen Retry- + Circuit-Breaker-Aufruf.
Middleware
Abschnitt betitelt „Middleware“import { cached, rateLimit } from 'actor-ts/http';
const routes = concat( rateLimit({ max: 100, intervalMs: 1_000 })( cached({ ttlMs: 30_000 })( path('api', /* ... */), ), ),);Das Framework liefert drei:
| Middleware | Was sie tut |
|---|---|
Response-Cache (cached) | Cached die Antwort eines Handlers, key’d über eine key(req)-Funktion. |
Rate-Limit (rateLimit) | Per-Key-Request-Limiter mit Fixed-Window-Counter im Cache. |
Idempotency-Key (idempotent) | Dedupliziert Writes anhand eines Idempotency-Key-Headers. |
Jede ist ein Handler-Wrapper — du rufst sie mit den Optionen auf und übergibst der zurückgegebenen Funktion den Handler, der geschützt werden soll. Kombiniere durch Verschachteln auf Handler-Ebene. Siehe die Middleware-Seiten.
HTTP an Actors anschließen
Abschnitt betitelt „HTTP an Actors anschließen“Der Routen-Handler gibt einen Promise<HttpResponse> zurück —
darin kannst du frei Actor-Calls awaiten:
import {} from 'actor-ts';
const routes = path('orders', path(':id', get(async (req) => { const id = req.path.split('/').pop(); const order = await orderRegistry.ask({ kind: 'get', id }, 5_000,); return completeJson(200, order); }), ),);Das ist das häufige Muster — HTTP-Handler sind ein dünner Adapter: Request parsen, einen Actor fragen, die Antwort marshallen. Halte Business-Logik in Actors; HTTP-Handler bleiben kurz.
Wohin als Nächstes
Abschnitt betitelt „Wohin als Nächstes“- Route-DSL — die volle DSL:
path,get/post/put/usw.,concat,complete*,redirect,reject. - Marshalling —
entity<T>, Content-Type-gesteuerte Dekodierung, Response-Kodierung. - Fastify-Backend — Konfiguration des Default-Backends.
- Bun.serve-Backend / Express-Backend — Alternativen.
- Response-Cache-Middleware — Caching für GET-Responses.
- Rate-Limit-Middleware — Rate-Limiting pro Key.
- Idempotency-Key-Middleware — Write-Deduplizierung für Mutationen.
Die HttpExtension-API-Referenz
deckt die volle Oberfläche ab.