Skip to content

Getting started

Terminal window
npm install @johnhenry/webwire

Latest on npm: @johnhenry/[email protected].

Node only, no CDN build. Converts between Node's http objects and Fetch API Request/Response. Some subpaths import in a browser, but they only make sense with Node objects.

Node 26 or newer. The package is ESM only ("type": "module"), with no dependencies.

import {
toWebRequest, toWebResponse, writeWebResponse,
toNodeRequestOptions, setTrailers, getTrailers,
} from "@johnhenry/webwire";

Each function also has its own subpath: @johnhenry/webwire/to-web-request, /to-web-response, /write-web-response, /to-node-request-options, and /trailers. Each of those modules exports its function both by name and as the default export.

Convert the incoming request, build a Response, write it back:

import http from "node:http";
import { toWebRequest, writeWebResponse } from "@johnhenry/webwire";
const server = http.createServer(async (req, res) => {
const request = toWebRequest(req);
const { pathname } = new URL(request.url);
await writeWebResponse(new Response(`Hello from ${pathname}`), res);
});
server.listen(8000);

toWebRequest() builds an absolute URL from req.url and the Host header, so request.url is http://localhost:8000/... here, not just a path. A non-GET/HEAD request carries req itself as its streamed body, so await request.json() or request.text() works as usual.

Two things this example leaves out, both covered in Serving: toWebRequest() can throw (an unparseable request target is tagged .status = 400), and writeWebResponse() never throws about a streamed body failing midway; it calls onError instead.

toNodeRequestOptions() turns a Request into the options for http.request(); toWebResponse() turns the response Node hands back into a Response:

import http from "node:http";
import https from "node:https";
import { toNodeRequestOptions, toWebResponse } from "@johnhenry/webwire";
function nodeFetch(request) {
const { isHTTPS, requestOptions } = toNodeRequestOptions(request);
const doRequest = isHTTPS ? https.request : http.request;
return new Promise((resolve, reject) => {
const req = doRequest(requestOptions, async (nodeRes) => {
const chunks = [];
for await (const chunk of nodeRes) chunks.push(chunk);
resolve(toWebResponse(nodeRes, Buffer.concat(chunks)));
});
req.on("error", reject);
req.end();
});
}
const res = await nodeFetch(new Request("http://localhost:8000/hi"));
console.log(res.status, await res.text());

This sends no body. toNodeRequestOptions() returns plain data and leaves the request body to you; see Calling out.