Skip to content

etienne-graveyard/tumau

Repository files navigation

tumau logo

🏺 Tumau

A node HTTP framework written in Typescript

Tumau is NodeJS server framework (just like Express or Koa) with almost no external dependencies and written in TypeScript.

Gist

import { createServer, TumauResponse, RequestConsumer } from 'tumau';

const server = createServer((ctx) => {
  const request = ctx.get(RequestConsumer);
  return TumauResponse.withText(`Hello World ! (from ${request.url})`);
});

server.listen(3002, () => {
  console.log(`Server is up at http://localhost:3002`);
});

Benefits over Express/Koa/Other

  • Written in Typescript (strong yet easy-to-use types)
  • Almost no external dependency (easy to audit)
  • Simple to extends (using middleware)
  • Modular, you can take only what you need.

Install

# npm
npm install tumau

# yarn
yarn add tumau

Dependencies

-chemin for the router path matching (chemin itself has zero dependencies). -miid for the middleware system (miid itself has zero dependencies).

Overview

Like many other server, Tumau is based on middleware. A middleware is like a layer the request has to go though. At some point a response is created by one of the middleware and the response has to travel back to the outside (go through every layer in the opposite order) to be sent.

middleware

A middleware can stop the chain and return a response. In that case the next middleware will not be called !

next

For TypeScript users

Contexts are typed when you create them:

import { createKey } from 'tumau';
// here we could omit <number> because it would be infered
const NumKey = createKey<number>(0);
// you can omit the default value
const NameKey = createKey<string>();

Middleware

A middleare is a function that:

  • receives the context and the next function
  • can return a response or null (or a promise of one of them)
type Middleware = (ctx, next) => null | Response | Promise<null | Response>;

Example:

const myMiddleware = async (ctx, next) => {
  // 1. We receive a ctx object
  console.log(ctx); // { get, getOrFail, has, with }
  // 2. We call `next` to call the next middleware
  const response = await next(ctx);
  // 3. The next middleware return a response
  console.log(response);
  // 4. We return that response
  return response;
};

The next function

The next function is always async (it return a Promise). It take a context as parameter and return a Promise of a Response or null

type Next = () => Promise<Response | null>;

Some examples

// Return a response, ignore next middleware
const middleware = () => Response.withText('Hello');

// Return a response if the next middleware did not
const middleware = async (ctx, next) => {
  const response = await next();
  if (response === null) {
    return Response.withText('Not found');
  }
  return response;
};

// Add a item to the context before calling the next middleware
// return whatever the next middleware return
const middleware = (ctx) => {
  const nextCtx = ctx.with(ReceivedAtContext.Provide(new Date()));
  return next(nextCtx);
};

Conbining multiple Middlewares

The createServer function take only one middleware as parameter. To use multiple middleware you need to combine them with compose :

import { createServer, compose } from 'tumau';

const composed = compose(logger, cors, main);

const server = createServer(composed);

Note: Middlewares are executed in the order they are passed to compose. In the example above: logger, then cors, then main (then the reverse order on the way up).

Performance

Is it fast ?

I'm no expert in benchmarks but from my attempt to measure it, it's a bit faster than Koa and Express but not as fast as fastify.

What does "Tumau" means

According to Google Traduction it is the translation of "server" in Maori but I'm not sure which definition it apply to. Anyway I thought it would make a cool name and it was not used on NPM so...