@mjackson/node-fetch-server
v0.5.0
Published
Build servers for Node.js using the web fetch API
Downloads
163,083
Maintainers
Readme
node-fetch-server
node-fetch-server
allows you to build servers for Node.js that use the web Fetch API primitives (namely Request
and Response
) instead of the traditional req
/res
API used in libraries like Express.
This web standard API is already used in many places across the JavaScript ecosystem:
When you write servers using the Request
and Response
APIs, you maximize the chances that your code will be portable across these different JavaScript runtimes.
Features
- Use web standard
Request
andResponse
APIs for building servers, instead of node-specific API - Seamless integration with
node:http
andnode:https
modules - Supports custom hostnames (e.g. using
process.env.HOST
on a VPS to set the host portion of incoming request URLs) - Supports streaming responses using
new Response(stream)
- Exposes remote client address info
Installation
npm install @mjackson/node-fetch-server
Usage
import * as http from 'node:http';
import { createRequestListener } from '@mjackson/node-fetch-server';
function handler(request: Request) {
return new Response('Hello, world!');
}
let server = http.createServer(createRequestListener(handler));
server.listen(3000);
By default request.url
is derived from the value of the Host
HTTP header and the connection protocol being used. To support custom hostnames using e.g. a HOST
environment variable, you can use the host
option:
import * as assert from 'node:assert/strict';
import * as http from 'node:http';
import { createRequestListener } from '@mjackson/node-fetch-server';
function handler(request: Request) {
// This is now true
assert.equal(new URL(request.url).host, process.env.HOST);
return new Response('Hello, world!');
}
let server = http.createServer(createRequestListener(handler, { host: process.env.HOST }));
server.listen(3000);
Information about the remote client IP and port is passed as the 2nd argument to your FetchHandler
:
import { type FetchHandler } from '@mjackson/node-fetch-server';
let handler: FetchHandler = (request, client) => {
return new Response(`The client IP address is ${client.address}`);
};
Low-level API
In addition to the high-level createRequestListener()
API, this package also provides 2 low-level APIs that are useful when building custom fetch
-based servers in Node.js:
createRequest(req: http.IncomingMessage, res: http.ServerResponse, options: RequestOptions): Request
sendResponse(res: http.ServerResponse, response: Response): Promise<void>
These two functions serve as an efficient, minimal translation layer between Node.js req
/res
objects and fetch Request
/Response
objects. You could build your own custom server like this:
import * as http from 'node:http';
import { createRequest, sendResponse } from '@mjackson/node-fetch-server';
let server = http.createServer(async (req, res) => {
let request = createRequest(req, res, { host: process.env.HOST });
try {
let response = await customAppLogic(request);
await sendResponse(res, response);
} catch (error) {
console.error(error);
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end('Internal Server Error');
}
});
server.listen(3000);
Related Packages
fetch-proxy
- Build HTTP proxy servers using the web fetch API
Benchmark
A basic "hello world" benchmark shows node-fetch-server
introduces considerable overhead on top of a vanilla node:http
server. However, it is still able to serve more requests per second (and has higher overall throughput) than Express v4, so the slowdown should be acceptable for most applications.
> @mjackson/[email protected] bench /Users/michael/Projects/remix-the-web/packages/node-fetch-server
> bash ./bench/runner.sh
Platform: Darwin (24.0.0)
CPU: Apple M1 Pro
Date: 11/14/2024, 2:30:22 PM
Running benchmark for node:[email protected] ...
Running 30s test @ http://127.0.0.1:3000/
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 9.97ms 31.92ms 786.67ms 99.09%
Req/Sec 4.45k 268.33 6.38k 93.69%
1594257 requests in 30.02s, 326.89MB read
Socket errors: connect 0, read 1317, write 6, timeout 0
Requests/sec: 53110.92
Transfer/sec: 10.89MB
Running benchmark for [email protected] ...
Running 30s test @ http://127.0.0.1:3000/
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 22.74ms 81.06ms 1.46s 98.22%
Req/Sec 2.42k 185.82 4.30k 91.80%
866347 requests in 30.03s, 177.64MB read
Socket errors: connect 0, read 1496, write 3, timeout 0
Requests/sec: 28849.46
Transfer/sec: 5.92MB
Running benchmark for [email protected] ...
Running 30s test @ http://127.0.0.1:3000/
12 threads and 400 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 36.46ms 125.89ms 1.99s 97.89%
Req/Sec 1.56k 146.86 2.93k 88.25%
558504 requests in 30.06s, 134.76MB read
Socket errors: connect 0, read 1261, write 11, timeout 36
Requests/sec: 18579.11
Transfer/sec: 4.48MB
License
See LICENSE