npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

express.mediator

v1.0.6-beta.2

Published

lightweight and easy implementation of an mediator pattern with express.js

Downloads

10

Readme

An lightweight and easy implementation of an mediator pattern with express.js.

const app = new ExpressMediator();
app.get("/", IndexRequest);
@body
export class IndexRequest extends IRequest {
    name!;
}

@requestHandler(IndexRequest)
export class IndexRequestHandler implements IRequestHandler<IndexRequest, string> {
    async handle(value: IndexRequest): Promise<string> {
        return `Hello ${value.name}!`
    }
}

See usage to learn all the different types of implementation.


Please be kind. I tried my best with this documentation but Iam still learning.

sadmouse

Getting Started

Installation

npm i express.mediator

or if you want to access early builds

npm i [email protected](-alpha.X | -beta.X)

Usage

The most magic of the mediator happens in the background. You basically just have to place some decorators onto your existing requests and replace the express app with the new ExpressMediator. In the following captions are all possible types of implementations and examples. Just pick what fits best for your purpose.

Request (required)

A request defines the whole processing for the resource. If you request data is located specifically use an request type to tell the parse pipeline where exactly to expect the data.

@body
class ExampleRequest {
	user!: string;
	password!: string;
}

@body
class ExampleRequest {
	user = "";
	password = "";
}

To use specific types of property declaration see the property setup.

Request Type

All usable http request types are accessable via an specific typescript decorator. There are two different (class and property) decorator types with two (non nullable and nullable) features available. These decorator are needed for the parse pipeline to determine where the data is in the request.

The class decorator function require a functional constructor to access the name of the provided class.

{{HTTPTYPE}}<T extends { new (): {} }>(constructor: T);

The decorator add san default auth entry into the IRequestAuthResolver without any role configuration and disabled anonymous request mode. This is required to ensure that every available handler request is covered by the auth component and a missed configuration will be highlighted correctly.

Request Type Body

Reads the data from the body of express request.

@body
@bodyNullable
Request Type Params

Reads the data from the params of express request.

@params
@paramsNullable
Request Type Query

Reads the data from the query of express request.

@query
@queryNullable
Request Type Empty

Ignores the parsing and won't proceed any value of the request.

@empty

Request Handler (required)

Every request has logic which is located in an handler.

The mediator assigns the handler to the request with a specific decorator.

@body
class ExampleRequest { ... }

@requestHandler(ExampleRequest)
class ExampleHandler implements IRequestHandler<ExampleRequest, string> { ... }

Request Handler in another file

If the handler is not in the same file like the request you have to put the following decorator onto the request. This step is required due to the fact that the handler won't be called by the application setup because the mediator only knowns the request.

Request File
@params
@handler(TestRequestHandler)
class TestRequest_Param {
	data!: string;
}
Handler File
class TestRequestHandler implements IRequestHandler<TestRequest_Param, string> {
	async handle(value: TestRequest_Param): Promise<string> {
		return value.data;
	}
}

Routers

A simplified router can be created to add multiple routes to express respectively multiple requests and handlers to the mediator.

Router Declaration

To create an express mediator router use the fluent router funtion.

const exampleRouter = (instance: IMediatorInstance) => router(instance)
	.get(ExampleRequest0)
	.get(ExampleRequest1, "nextRoute");

Multiple identical paths within the router will throw an configuration error.

Router Registration

The created express mediator router must be registered in the ExpressMediator.

const appMediator = new ExpressMediator();
appMediator.route("/testRoute", exampleRouter);

All the specified routes on the router will be added onto the base path (e.g. nextRoute will be /testRoute/nextRoute).

Access Root Express Application

To access the root express application just call the express app on the ExpressMediator instance.

const app = new ExpressMediator().app;

Tests

The tests are located inside the folder ./tests/ and are constructed with jest respectively ts-jest. To configure jest use the config file jest.config.js.

npm run test

Before uploading the files to npm run the following script.

npm run preupload

This script runs the jest test file jest ./tests/default.test.ts which tests the basic functionalities of the build files in ./lib.

All test files with the prefix ! will be ignored by jest. If you want to change this behavior remove this line inside the jest configuration.

Version Overview

1.0.6

Request Handler Decorator Adjustments

This version introduces the option to specifie any media type and success status code within the request handler decorator declaration.

@requestHandler(TestClass, SuccessHttpType.OK, MediaTypes.common.json)
class TestClassHandler<...> implements IRequestHandler<...> { ... }
@requestHandler(TestClass, SuccessHttpType.Created, MediaTypes.common.txt)
class TestClassHandler<...> implements IRequestHandler<...> { ... }

before

@requestHandler(TestClass)
class TestClassHandler<...> implements IRequestHandler<...> { ... }
@requestHandler(TestClass)
class TestClassHandler<...> implements IRequestHandler<...> { ... }

Like before the default for all successfull proceeded requests is HTTP 200 with an JSON response. The status code property of the request handler interface has been removed.

Parse Pipeline Property Setup

All properties of the registered request will be categorized into the following types.

Required Properties

All properties which have an empty default value will be categorized as an required property. Please read the following special cases to avoid unintentional errors.

value = "";

If the request object won't provide any value for the required fields an parsing error will be thrown. All missing required fields will be summarized into one error response.

Special Case: Numbers, Big Integers and Booleans

Because of the fact that the default value of types like number, bigInt and bool are not separatable from empty values (e.g. an empty string) any declarated value will be treated as an default value (see ignoreable properties).

n0 = 0;
n1 = 60;
b = false;
Special Case: Undefined Flag

Even though the property value is specified with an null assertion operator ? the parser won't be able to specifie those as ignorable properties. If you want to use ignorable properties see ignoreable properties.

value? = "";

Ignorable Properties

All properties which have a filled default value will be added to the parsed object automatically after the initial parsing process when the object does not provide any value for the specific field.

data = "value";

Optional Properties

All properties which have an null assertion operator ? or an non-null assertion operator ! will be treated as optional properties.

data?;
data!;

If the request object won't provide the specified optional properties no error will be thrown.

Router Declaration Refactoring

The declared router for the router registration won't has to return the express router and doesn't need any explicit mediator instance for declaration like before.

const exampleRouter = router().get(exampleRequest);

before

const exampleRouter = (instance: IMediatorInstance) => router(instance).get(exampleRequest).exe();

If the express router is needed for development reasons use the function .getRouter().

MISC

  • role(), roles() and anonymous decorators accept class constructs now (previously functions)
  • exception field has been removed from PrePipelineResponse. Pre pipelines must have to throw pipeline errors explicitly now
  • new ExpressMediator().listen() now accept a number for the port definition only (previously string)
  • IRequest has been removed due to the fact that is was completly unnecessary
  • Logger.get() now only returns the internal logger without any required properties
  • Property data of E__Pipeline is not optional (previously required)