Skip to content
This repository has been archived by the owner on Sep 14, 2020. It is now read-only.

kirruss/compose

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

80 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@kirrus/compose

GitHub Workflow Status Code Climate coverage Code Climate maintainability Code Climate technical debt

npm bundle size npm npm npm type definitions

Type-safe middleware composition utility for the Kirrus framework

@kirrus/compose is a module part of the kirrus namespace, used for composing middleware in a typesafe and lazy manner

import { Middleware, MiddlewareComposer } from "@kirrus/compose"

type Context<T = {}> = T & {
    body: object
    headers: Map<string, string>
    method: string
    url: string
    status: number
}

const context: Context = {
    body: {},
    headers: new Map(),
    method: "GET",
    url: "/hello",
    status: 200
}

const logger: Middleware<Context> = async (ctx, next) => {
    await next()
    const rt = ctx.headers.get("X-Response-Time")
    console.log(`${ctx.method} ${ctx.url} - ${rt}`)
}

const xResponseTime: Middleware<Context> = async (ctx, next) => {
    const start = Date.now()
    await next()
    const ms = Date.now() - start
    ctx.headers.set("X-Response-Time", `${ms}ms`)
}

const helloHandler: Middleware<Context> = () => {
    return {
        status: 200,
        body: {
            status: 200,
            message: "Hello from /hello !"
        }
    }
}
const composedMiddleware = new MiddlewareComposer<Context>()
    .use(logger)
    .use(xResponseTime)
    .use(helloHandler)
    .getMiddleware()

composedMiddleware(context, async () => {})

This package exposes a type(Middleware) and a class(MiddlewareComposer).

The type Middleware is used for defining what a middleware and it looks as follows:

interface IMiddleware<T, R extends T> {
    getMiddleware(): Middleware<T, R>
}

type FunctionMiddleware<T, R extends T> = (
    ctx: T,
    next: () => Promise<void>
) => Awaitable<DeepPartial<R> | void>

type Middleware<T, R extends T = T> =
    | IMiddleware<T, R>
    | FunctionMiddleware<T, R>

In most use cases, you'll find yourself writing middleware that fit FunctionMiddleware type, but just in case you want to do something fancy like a custom router, the IMiddleware type has been exposed too 🙂

For usage of MiddlewareComposer, see Using this module

Installation

To install the compose module, simply type:

npm i @kirrus/compose

Using this module

import { Middleware, MiddlewareComposer } from "@kirrus/compose"

// This is the type of the context
// we'll be using for type safety
type Context = { count: number }

// This is the initial context
// adding a basic count property
// and giving it an initial value of 0
const context: Context = { count: 0 }

// This is the first middleware
// that increases the count property
// of the context
const increaseCount: Middleware<Context> = async (ctx, next) => {
    ctx.count++

    await next()
}

// This is the second middleware
// that doubles the count property
// of the context
const doubleCount: Middleware<Context> = async (ctx, next) => {
    ctx.count *= 2

    await next()
}

// And finally this is our middleware composer instance
// that we provide with a chain of middleware
// in the order we want the middleware to be executed
// using the .use(middleware) method
// and finally get the resulting composed middleware
// using the .getMiddleware() method
const composedMiddleware = new MiddlewareComposer<Context>()
    .use(increaseCount)
    .use(doubleCount)
    .getMiddleware()

// The initial context
console.log(context) // { count: 0 }

// We apply the composed middleware
// on our context
// providing an empty next function
// Note: this assumes top-level await
await composedMiddleware(context, async () => {})

// The resulting context
console.log(context) // { count: 2 }

Documentation

You can find the automatically generated changelog here

The documentation in markdown format can be found here

Contributing

To contribute, check the contribution guide here

Unlicence

@kirrus/compose and all other repos under the kirrus organisation use the Unlicense.