0.1.0 • Published 11 months ago

@mjackson/node-fetch-server v0.1.0

Weekly downloads
-
License
MIT
Repository
github
Last release
11 months ago

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 and Response APIs for building servers, instead of node-specific API
  • Seamless integration with node:http and node: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 { type FetchHandler, createRequestListener } from '@mjackson/node-fetch-server';

let handler: FetchHandler = (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 { type FetchHandler, createRequestListener } from '@mjackson/node-fetch-server';

let handler: FetchHandler = (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}`);
};

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/node-fetch-server@0.0.0 bench /Users/michael/Projects/remix-the-web/packages/node-fetch-server
> bash ./bench/runner.sh

Platform: Darwin (23.5.0)
CPU: Apple M1 Pro
Date: 8/31/2024, 5:43:47 PM

Running benchmark for node:http@22.1.0 ...

Running 30s test @ http://127.0.0.1:3000/
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    22.28ms   71.96ms   1.36s    98.37%
    Req/Sec     2.37k   538.29     9.51k    85.30%
  848851 requests in 30.10s, 174.05MB read
  Socket errors: connect 0, read 544, write 27, timeout 0
Requests/sec:  28198.41
Transfer/sec:      5.78MB

Running benchmark for node-fetch-server@0.0.0 ...

Running 30s test @ http://127.0.0.1:3000/
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    42.57ms  109.55ms   2.00s    98.37%
    Req/Sec     1.03k   282.58     2.78k    77.37%
  368110 requests in 30.10s, 75.48MB read
  Socket errors: connect 0, read 717, write 152, timeout 126
Requests/sec:  12228.31
Transfer/sec:      2.51MB

Running benchmark for express@4.19.2 ...

Running 30s test @ http://127.0.0.1:3000/
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    48.76ms   87.38ms   2.00s    98.90%
    Req/Sec   734.60    190.17     3.03k    79.08%
  261725 requests in 30.09s, 63.15MB read
  Socket errors: connect 0, read 1259, write 110, timeout 200
Requests/sec:   8696.85
Transfer/sec:      2.10MB

License

See LICENSE

0.1.0

11 months ago