fafdeprecated

Fast as fuck, easy to use http server written in typescript

Usage no npm install needed!

<script type="module">
  import faf from 'https://cdn.skypack.dev/faf';
</script>

README

THIS PROJECT HAS BEEN DEPRECATED Please check out htts

Fast as fuck, easy to use http server written in typescript

Faf takes inspiration from the fetch API. It is simple and expressive, it has a very small footprint and it is also very performant. Simplicity is what it does well. Take a look at the example repo.

Installation

$ npm install faf

Usage

import { HttpServer, HttpStatus, Response } from "faf";

const http = new HttpServer();

http.post("/products", async (request) => {
  // You should validate this with your library of choice
  const body = await request.json();
  const product = await prisma.product.create(body);
  return Response.json(product, HttpStatus.Created);
});

const { port } = await http.bind(4000);
console.log(`Listening on port ${port}`);

Dynamic and Query Params

Faf normalizes both query and dynamic params into a single URLSearchParams instance. note: dynamic params override query string params.

// incoming url: /products/5?limit=10
http.get("/products/:id", (request) => {
  const { url } = request;
  console.log(url.pathname); // /products/5
  console.log(url.searchParams); // URLSearchParams { 'id' => '5', 'limit' => '10' }
});

CORS

Faf comes with cors support out of the box. It is a fair simple implementation (for now) taken mostly from @koa/cors and expressjs/cors.

const http = new HttpServer({ cors: true });

// or
const http = new HttpServer({
  cors: { origin: "https://example.com", allowedHeaders: ["x-token"] },
});

Sockets

Faf is built around Node's core http module. It exposes the underlying server so it can be used alongside websocket libraries, such as Socket.IO or ws.

Socket.IO

import { HttpServer } from "faf";
import { Server as SocketServer } from "socket.io";

const http = new HttpServer();
const io = new SocketServer(http.server, {
  /* other options */
});

io.on("connection", (socket) => {
  // work your magic
});

await http.bind(4000);

WS

import { HttpServer } from "faf";
import { WebSocket } from "ws";

const http = new HttpServer();

// Create a WebSocket server completely detached from the HTTP server.
const wss = new WebSocket.Server({ clientTracking: false, noServer: true });

http.server.on("upgrade", (request, socket, head) => {
  // Nice place to do some authentication

  wss.handleUpgrade(request, socket, head, (socket) => {
    wss.emit("connection", socket, request);
  });
});

wss.on("connection", (socket, request) => {
  // Work your magic...
});

await http.bind(4000);

Benchmarks

Command

bombardier -c 126 -n 1000000 http://localhost:4000/example

Code

import { HttpServer, Response } from "faf";

const http = new HttpServer();

http.get("/example", () => Response.text("Hello world"));

http.bind(4000);

Output

Statistics        Avg      Stdev        Max
  Reqs/sec     26228.48    1717.36   28772.79
  Latency        4.69ms   197.48us    19.60ms
  HTTP codes:
    1xx - 0, 2xx - 1000000, 3xx - 0, 4xx - 0, 5xx - 0
    others - 0
  Throughput:     5.73MB/s

Here's the ouput for the express equivalent.

Statistics        Avg      Stdev        Max
  Reqs/sec      8880.65     839.30    9964.55
  Latency       14.19ms     0.93ms    69.20ms
  HTTP codes:
    1xx - 0, 2xx - 1000000, 3xx - 0, 4xx - 0, 5xx - 0
    others - 0
  Throughput:     2.60MB/s