Coder Social home page Coder Social logo

routup / routup Goto Github PK

View Code? Open in Web Editor NEW
30.0 2.0 0.0 5.69 MB

A fast, lightweight, runtime agnostic and asynchronous routing framework.

Home Page: https://routup.net

License: MIT License

JavaScript 1.59% TypeScript 98.41%
api rest route router routing http typescript web middleware http-server

routup's Introduction

Routup banner

Routup πŸ§™β€

npm version main codecov Known Vulnerabilities Conventional Commits

Routup is a fast, lightweight, runtime agnostic and asynchronous routing framework. Helpers provide additional functionalities to interact with the request and manipulate the response.

It can be used independently of the selected runtime environment (Node.Js, Bun, ... ) πŸŽ‰. Moreover, it is even 228% faster than Express (more).

Table of Contents

Installation

npm install routup --save

Features

  • πŸš€ runtime agnostic (Node.JS, Bun, Deno, ...)
  • πŸ“ different handler types (base & error)
  • ✨ promise (async) support for core- & error-handlers
  • πŸ“Œ robust hook system
  • πŸ”Œ powerful plugin system
  • 🧰 tree shakeable response & request helpers
  • 🀝️ different handler declaration styles (shorthand & verbose)
  • πŸ“ nestable routers
  • πŸ‘• TypeScript support
  • 🀏 minimalistic to fit into any solution with minimum overhead
  • & much more

Documentation

To read the docs, visit https://routup.net

Usage

The following examples are intended to give a small insight into the use of the framework. However, it is highly recommended to read the documentation, as all concepts and basics are taught there.

Handlers

Both core and error handlers, can be defined in two different ways. Core handler functions can have up to 3 arguments (req, res, next) whereas error handler functions can have up to 4 arguments (err, req, res, next). This should be familiar to anyone who has used express before.

Shorthand

With the shorthand variant, only the handler function is passed as argument to the coreHandler & errorHandler function.

import { createServer } from 'node:http';
import {
    coreHandler,
    createNodeDispatcher,
    errorHandler,
    Router,
    useRequestParam
} from 'routup';

const router = new Router();

router.get('/', coreHandler(() => 'Hello, World!'));
router.get('/greet/:name', coreHandler((req) => `Hello, ${useRequestParam(req, 'name')}!`));
router.use(errorHandler((err) => `An error with statusCode ${err.statusCode} occured.`));

const server = createServer(createNodeDispatcher(router));
server.listen(3000)

Verbose

The verbose variant is more complex, but offers the possibility to set additional information like path, method, ... in the handler definition.

import { createServer } from 'node:http';
import {
    coreHandler,
    createNodeDispatcher,
    errorHandler,
    Router,
    useRequestParam
} from 'routup';

const router = new Router();

router.get(coreHandler({
    path: '/',
    fn: () => 'Hello, World!',
}));

router.get(coreHandler({
    path: '/greet/:name',
    fn: (req) => `Hello, ${useRequestParam(req, 'name')}!`
}))

router.use(errorHandler({
    fn: (err) => `An error with statusCode ${err.statusCode} occured.`
}))

const server = createServer(createNodeDispatcher(router));
server.listen(3000)

Runtimes

It is possible to use any javascript runtime environment. Below are examples for Bun and Deno. These use the web dispatcher to submit requests based on the web api. Besides the node- & web-dispatcher, there is also a plain dispatcher that underlies the web dispatcher, which can be controlled via a simple API.

Bun

import {
    coreHandler,
    createWebDispatcher,
    Router
} from 'routup';

const router = new Router();

router.get('/', coreHandler(() => 'Hello, World!'));

const dispatch = createWebDispatcher(router);

Bun.serve({
    async fetch(request) {
        return dispatch(request);
    },
    port: 3000,
});

Deno

import {
    coreHandler,
    createWebDispatcher,
    Router
} from 'routup';

const router = new Router();

router.get('/', coreHandler(() => 'Hello, World!'));

const dispatch = createWebDispatcher(router);

const server = Deno.listen({
    port: 3000
});
for await (const conn of server) {
    const httpConn = Deno.serveHttp(conn);

    for await (const requestEvent of httpConn) {
        const response = await dispatch(
            requestEvent.request
        );
        requestEvent.respondWith(response);
    }
}

Plugins

According to the fact that routup is a minimalistic framework, it depends on plugins to cover some typically http framework functions, which are not integrated in the main package.

Name Description
assets Serve static files from a directory.
basic Bundle of the body, cookie and query plugin.
body Read and parse the request body.
cookie Read and parse request cookies and serialize cookies for the response.
decorators Create request handlers with class-, method- & parameter-decorators.
prometheus Collect and serve metrics for prometheus.
query Read and parse the query string of the request url.
rate-limit Rate limit incoming requests.
rate-limit-redis Redis adapter for the rate-limit plugin.
swagger Serve generated docs from URL or based on a JSON file.

Benchmarks

  • CPUs: 24
  • RAM: 63.9GB
  • Node: v18.16.0
  • Date: Wed Sep 13 2023 15:11:58 GMT+0200 (MitteleuropΓ€ische Sommerzeit)
  • Method: autocannon -c 100 -d 40 -p 10 localhost:3000 (two rounds; one to warm-up, one to measure)
Package Requests/s Latency (ms) Throughput/MB
http 61062 15.87 10.89
fastify 59679 16.26 10.70
koa 45763 21.35 8.16
routup 44588 21.91 9.02
hapi 41374 23.67 7.38
express 13376 74.18 2.39

Benchmarks were generated using autocannon. To recreate the results, this can be done using the benchmarks' repository.

Contributing

Before starting to work on a pull request, it is important to review the guidelines for contributing and the code of conduct. These guidelines will help to ensure that contributions are made effectively and are accepted.

License

Made with πŸ’š

Published under MIT License.

routup's People

Contributors

dependabot[bot] avatar semantic-release-bot avatar tada5hi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

routup's Issues

Feature: Public API

Cleanup/enhance public api.

@routup/body

  • createRequestHandler -> createHandler
  • createRequestJsonHandler -> createJsonHandler
  • createRequestRawHandler -> createRawHandler
  • createRequestTextHandler -> createTextHandler
  • createRequestUrlEncodedHandler -> createUrlEncodedHandler

@rotup/cookie

  • createRequestHandler -> createHandler
  • useRequestCookie(s) -> useCookie(s) ??
  • setResponseCookie -> setCookie ??
  • parseRequestCookie -> parseCookie ??

@routup/core

  • send -> respond | sendResponse
  • sendAccepted -> respondAccepted | sendResponseAccepted
  • sendCreatad -> respondCreated | sendResponseCreated

@routup/query

  • createRequestHandler -> createHandler
  • useRequestQuery -> useQuery ??
  • parseRequestQuery -> parseQuery ??

@rotuup/rate-limit

  • setRequestRateLimitInfo -> setRateLimitInfo ??
  • useRequestRateLimitInfo -> useRateLimitInfo ??

@routup/swagger

  • createUIHandler(document: string, options: UIOptions) -> createUIHandler(input: string | UIOptions & {document: string})

Feature: Plugin System

Allow packages to be defined as a plugin.

  • allow modifying router instance via install function
  • allow registering hooks

Signature

type Hooks = {
    onError: (error: ErrorProxy, event: DispatcherEvent) => boolean | void,
    onDispatch: (event: DispatcherEvent) => void | Promise<void>,
    onDispatched: (event: DispatcherEvent) => void | Promise<void>
}

type PluginContext = {
    name? string,
    path?: string,
    options?: Options
}

export type PluginInstallFn<Options> = (router: Router, options: Options) => any;
export type Plugin<Options = any> = Hooks & {
    name: string,
    version?: string,
    path?: string,
    install: PluginInstallFn<Options>
}

Usage

import { plugin } from '@rotup/plugin';

const router = new Router();

// install
router.install(plugin, {
    options: {
       foo: 'bar',
    }
});

// remove
router.uninstall(plugin);

Feature: Replace Node modules

  • etag generation with web crypto api
  • use polifyll for path.extname + path.basename
  • remove env option from config/options
  • remove explicit URL import for useRequestPath method
  • remove Router listen method to avoid importing createServer
  • remove helper sendFile due dependent on node:fs

Feature: Handler Style

A handler should be declared in different ways/styles.

Style:

  • mutiple arguments
  • single argument

The single argument style should have the following properties:

  • request/req
  • response/res
  • next
  • (method)
  • (path)
  • (params)
  • (cookies)
  • (body)

method, path, params should be evaluated on demand. Otherwise execution overhead and perfomance issues.

Feature: Config Container

Global config container ( singleton ) to set known and additional properties, like:

  • etag (& threshold)

Feature: Error Handling

There should be a simple way to throw an error for various standard errors (not-found, bad-request, ...). Also, error messages that are not of type error (aka instanceof ) or not thrown by a standard error should be decorated accordingly.

Feature: Hooks

onError
This hook is triggered when an error occurs during the request handling process. It allows you to intercept and handle errors, perform custom logging, or even modify the error response. It's essential for robust error handling.

onDispatch
This hook is triggered before a request is dispatched to the appropriate handler. It can be useful for tasks like request logging, authentication checks, or any pre-processing you need to perform on incoming requests.

onDispatched
This hook is triggered after a request has been successfully dispatched and processed. It's useful for tasks that should occur after the main request handling, such as additional logging, response manipulation, or triggering other actions based on the request outcome.

onRouteMatch
Triggered when a route is successfully matched. It can be used for route-specific logic or to gather data about matched routes.

type Hooks = {
    onError: (error: ErrorProxy, event: DispatcherEvent) => boolean | void,
    onDispatch: (event: DispatcherEvent) => void | Promise<void>,
    onDispatched: (event: DispatcherEvent) => void | Promise<void>
}

Feature: Benchmark comparision

Is your feature request related to a problem? Please describe.

Describe the solution you'd like

Describe alternatives you've considered

Additional context

Feature: Handler recognition

Handlers declared using defineHelper or defineErrorHandler should also be identified by a type property, so that a handler type does not have to be identified by the number of function arguments.

Types:

  • default
  • error

Feature: Define Helper

Provide defineHandler, defineErrorHandler helper, to provide intellisense without the need for jsdoc annotations in non typescript projects.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.