ranuts/node — kleines HTTP-Framework
Ein kleiner, abhängigkeitsfreier HTTP-Werkzeugkasten für Node.js: ein HTTP-Server, ein Router, ein WebSocket-Server, Middleware für Request-Bodys und statische Dateien sowie eine Handvoll Helfer für Kommandozeile und Dateisystem.
⚠️ Nur für Node. Dieser Einstiegspunkt zieht
node:http,node:fs,node:child_processund dergleichen herein. Importiere ihn ausranuts/node, niemals aus Browser-Code.
Import
import { Server, Router, staticMiddleware, body } from 'ranuts/node';Die Middleware, die den Request-Body liest, wird als
bodyexportiert (intern heißt siebodyMiddleware). Einen Export namensbodyMiddlewaregibt es nicht.
Schnellstart
import { Server, Router, staticMiddleware, body } from 'ranuts/node';
const app = new Server();
const router = new Router();
// Routen greifen nur bei exakt gleichem Pfad. Der Handler bekommt den Context der Anfrage.
router.get('/hello', (ctx) => {
ctx.res.setHeader('Content-Type', 'application/json');
ctx.res.end(JSON.stringify({ message: 'hello world' }));
});
// POST mit JSON-Body: body() liest ihn und legt ihn in ctx.request.body ab
router.post('/echo', (ctx) => {
ctx.res.end(JSON.stringify({ youSent: ctx.request.body }));
});
// body() liest den Request-Body UND füllt ctx.request (method / path / url / query),
// woraus der Router liest – also VOR router.routes() registrieren.
app.use(body());
app.use(router.routes());
app.use(router.allowedMethods());
// Statische Dateien ausliefern (für `/` greift ./public/index.html)
app.use(staticMiddleware({ pathname: './public' }));
const server = app.listen(3000, () => {
console.log('Server running at http://localhost:3000');
});
// `server` ist die darunterliegende Server-Instanz von node:http.Die Reihenfolge der Middleware zählt: Der Router liest ctx.request.path und ctx.request.method, und gefüllt werden die von body(). Registriere body() zuerst. Das mitgelieferte body() liest derzeit Request-Bodys vom Typ application/json und multipart/form-data.
API
Server
Standardexport. Ein minimaler Server im Stil von Koa, aufgesetzt auf node:http.
| Element | Beschreibung | Typ |
|---|---|---|
new Server() |
Erzeugt einen Server. Nimmt keine Argumente. | () => Server |
use(middleware) |
Hängt eine Middleware ans Ende der Kette. Gibt void zurück, ist also nicht verkettbar. |
(fn: MiddlewareFunction) => void |
listen(...args) |
Beginnt zu lauschen. Die Argumente gehen unverändert an http.Server.listen. Zurück kommt der darunterliegende http.Server. |
(...args) => http.Server |
middleware |
Das Array der registrierten Middleware. | MiddlewareFunction[] |
ctx |
Der gemeinsam genutzte Anfrage-Context (sein req und sein res werden je Anfrage ausgetauscht). |
Context |
Signatur der Middleware
type Next = () => Promise<void> | Promise<never>;
type MiddlewareFunction = (ctx: Context, next: Next) => void | Promise<void>;Ruf next() auf, um die Kontrolle an die nächste Middleware weiterzugeben. Middleware werden in der Reihenfolge ihrer Registrierung abgearbeitet; ein zweiter Aufruf von next() wirft.
Aufbau des Context
| Feld | Beschreibung | Typ |
|---|---|---|
req |
Die eingehende Anfrage. | http.IncomingMessage |
res |
Die Antwort des Servers. Beschrieben wird sie mit res.setHeader, res.writeHead und res.end. |
http.ServerResponse |
ipv4() |
Liefert die erste nicht interne IPv4-Adresse des Rechners (sonst undefined). |
() => string | undefined |
request |
Von body() hinzugefügt: { method, path, url, query, body }. query ist ein URLSearchParams. |
object (dynamic) |
[key] |
Context ist ein offener Beutel: Middleware darf beliebige Felder daranhängen. |
any |
Router
Standardexport. Registriert Handler je HTTP-Methode und exaktem Pfad und stellt sie über routes() als Middleware bereit.
| Methode | Beschreibung | Typ |
|---|---|---|
new Router() |
Erzeugt einen Router. | () => Router |
get(url, handler) |
Registriert eine GET-Route. |
(url: string, h: Handler) => void |
post(url, handler) |
Registriert eine POST-Route. |
(url: string, h: Handler) => void |
put(url, handler) |
Registriert eine PUT-Route. |
(url: string, h: Handler) => void |
patch(url, handler) |
Registriert eine PATCH-Route. |
(url: string, h: Handler) => void |
del(url, handler) |
Registriert eine DELETE-Route. |
(url: string, h: Handler) => void |
head(url, handler) |
Registriert eine HEAD-Route. |
(url: string, h: Handler) => void |
options(url, handler) |
Registriert eine OPTIONS-Route. |
(url: string, h: Handler) => void |
routes() |
Liefert eine Middleware, die an den passenden Handler weiterreicht. | () => MiddlewareFunction |
allowedMethods() |
Liefert eine Middleware, die mit 404, 405 oder 501 antwortet, wenn Pfad oder Methode nicht passen. |
() => MiddlewareFunction |
Signatur des Handlers
type Handler = (ctx: Context, next: Next) => void;Lies die Daten der Anfrage aus ctx.request (method, path, url, query, body) und antworte über ctx.res. Pfade greifen nur bei exakter Übereinstimmung: Segmente der Form :param gibt es nicht; für Abfrageparameter nimm ctx.request.query.
Middleware
| Symbol | Beschreibung | Typ |
|---|---|---|
body(options?) |
Middleware zum Lesen des Request-Bodys. Füllt ctx.request und verarbeitet application/json und multipart/form-data. Gibt eine Middleware zurück. |
(o?: Partial<ServerBody>) => MiddlewareFunction |
staticMiddleware(opt?) |
Liefert statische Dateien aus opt.pathname (voreingestellt process.cwd()); für / kommt index.html. |
(o?: Partial<Option>) => MiddlewareFunction |
connect(fn) |
Passt eine Middleware im Connect- oder Express-Stil, (req, res, next), an die Middleware dieses Frameworks an. |
(fn) => MiddlewareFunction |
Optionen von body(options)
| Option | Beschreibung | Typ | Standard |
|---|---|---|---|
uploadDir |
Verzeichnis für Datei-Uploads per multipart/form-data. |
string |
'.' |
encoding |
Kodierung des eingehenden Anfrage-Streams. | BufferEncoding |
'utf-8'/'binary' |
json |
Liest JSON-Bodys (bei false bleibt die rohe Zeichenkette stehen). |
boolean |
true |
urlencoded |
Für urlencoded-Bodys vorgemerkt. | boolean |
true |
Optionen von staticMiddleware(option)
| Option | Beschreibung | Typ | Standard |
|---|---|---|---|
pathname |
Wurzelverzeichnis, aus dem Dateien ausgeliefert werden. | string |
process.cwd() |
fileTypes |
Zusätzliche Zuordnungen Dateiendung → MIME-Typ, die registriert werden. |
Record<string, string> |
{} |
WebSocket
| Symbol | Beschreibung | Typ |
|---|---|---|
new WSS(httpServer) |
Hängt einen WebSocket-Server an einen node:http-Server (übernimmt den upgrade-Handschlag und das Framing). |
(server: http.Server) => WSS |
import { Server, WSS } from 'ranuts/node';
const app = new Server();
const server = app.listen(3000);
const wss = new WSS(server);
wss.on('connect', (client) => {
client.on('message', (data) => client.send('echo: ' + data));
});
// wss.broadcast(data) schickt an jeden verbundenen Client; wss.clients ist die Liste.Jeder client bietet send(data, options?), ping(), pong(), close() und socket sowie die Ereignisse message, close und error.
Hilfsmittel
| Symbol | Beschreibung | Signatur |
|---|---|---|
connect(fn) |
Passt eine (req, res, next)-Middleware aus Connect oder Express an die Middleware des Frameworks an. |
(fn) => MiddlewareFunction |
get({ url }) |
Holt per HTTPS-GET einen JSON-Endpunkt; löst mit { success, data, message } auf. |
({ url: string }) => Promise<Response> |
getIPAdress() |
Die erste nicht interne IPv4-Adresse des Rechners, sonst undefined. |
() => string | undefined |
paresUrl(req) |
Zerlegt req.url in { search, query, pathname, path, href } (auf die Schreibweise achten). |
(req: IncomingMessage) => ParseUrl | undefined |
prompt({ message }) |
Stellt im Terminal eine Ja-Nein-Frage; löst bei y oder yes mit true auf. |
({ message, stream?, defaultResponse? }) => Promise<boolean> |
runCommand(cmd, args) |
Startet einen Kindprozess (erbt stdio); löst beim Exit-Code 0 auf. |
(cmd: string, args: string[]) => Promise<void> |
readStream({ path }) |
Erzeugt einen fs.ReadStream für path. |
(o: { path: string, ... }) => ReadStream |
writeStream({ path }) |
Erzeugt einen fs.WriteStream für path. |
(o: { path: string, ... }) => WriteStream |
startTask() |
Startet eine hochauflösende Uhr; liefert ein undurchsichtiges symbol. |
() => symbol |
taskEnd(symbol) |
Vergangene Zeit seit dem zugehörigen startTask() (unter Node Nanosekunden als bigint). |
(s: symbol) => number | bigint |
traverse(dir, cb, pre?) |
Läuft dir rekursiv ab und ruft für jede Datei cb(relPath, absPath, stats) (asynchron). |
(dir, cb, pre?) => Promise<any> |
traverseSync(dir, cb, pre?) |
Synchrone Fassung von traverse. |
(dir, cb, pre?) => void |
isColorSupported |
Wahrheitswert: ob das aktuelle Terminal ANSI-Farben beherrscht. | boolean |
colors |
Helfer für ANSI-Farben, etwa colors.red('text'), dazu reset, bold und dim. |
Record<string, (s: string) => string> |
Siehe auch
Derselbe Einstiegspunkt ranuts/node bringt außerdem Helfer fürs Dateisystem mit, die gesondert beschrieben sind: