# small-middlewares

> Small middlewares library for any purposes

Latest version **1.0.0** (published 2021-11-09) · Apache-2.0 license · 0 weekly downloads

## Install

```sh
npm install small-middlewares
pnpm add small-middlewares
yarn add small-middlewares
bun add small-middlewares
```

## Health

**Score 20/100 (F)** — status: abandoned.

Positive: esm support; no vulnerabilities.

Warnings: low downloads; no types.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 1.0.0 |
| Published | 2021-11-09 |
| First published | 2021-11-07 |
| Weekly downloads | 0 |
| License | Apache-2.0 |
| TypeScript types | none |
| Module format | ESM + CommonJS |
| Dependencies | 0 |
| Unpacked size | 28.7 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | Constantin Tsukanov |
| Maintainers | ya-kostik |
| Keywords | small, middleware, tiny, middlewares, small-middlewares, web, app, api, custom |

## Links

- npm: https://www.npmjs.com/package/small-middlewares
- Repository: git@github.com:ya-kostik/small-middlewares
- npm.io page: https://npm.io/package/small-middlewares

## Alternatives

- [@opentelemetry/exporter-zipkin](https://npm.io/package/@opentelemetry/exporter-zipkin.md) — 14.8M weekly downloads
- [pusher-js](https://npm.io/package/pusher-js.md) — 2.0M weekly downloads
- [browserify](https://npm.io/package/browserify.md) — 1.7M weekly downloads
- [sqs-consumer](https://npm.io/package/sqs-consumer.md) — 1.7M weekly downloads
- [@sanity/eventsource](https://npm.io/package/@sanity/eventsource.md) — 930.8K weekly downloads

## Recent versions

- 1.0.0 (latest) — 2021-11-09
- 0.0.3 — 2021-11-09
- 0.0.2 — 2021-11-09
- 0.0.1 — 2021-11-07

## README

# small-middlewares
Small middlewares library for any purposes

# Install
## Yarn
```sh
yarn add small-middlewares
```
## NPM
```sh
npm install small-middlewares
```

# Usage examples
You should create an instance, and use it where you want.

```js
const instance = new Middlewares();
instance.use(() => console.info('You are in the first step'));
instance.use(() => console.info('You are one step closer'));
instance.use(() => console.info('You are in the third step'));

const result = await instance.process();
if (result) {
	// it happens, because all middlewares are completed, and result is true
	doSomethingAfterMiddlewaresChain();
}
```

## Stop execution chain
If you want to stop middlewares execution, just return `false` from one of them.

```js
const instance = new Middlewares();
instance.use(() => console.info('You are in the first step'));
instance.use(() => console.info('You are one step closer'));
instance.use((user) => user === 'admin');
instance.use(() => console.info('It happens only if user is admin'));

const user = 'notAdmin';
const result = await instance.process(user);
if (result) {
	// it not happens, because result is now false
	doSomethingAfterMiddlewaresChain();
}
```

## In classes

For example in pseudoclass:
```js
import { Middlewares } from 'small-middlewares';

class Log {
	constructor() {
		this.before = new Middlewares();
		this.after = new Middlewares();
	}

	#run(values) {
		console.info('You reached the log');
		console.log(values);
	}

	async run(values) {
		if (!await this.before.process(values)) return;
		this.#run(values);
		await this.after(values);
	}
}

const logger = new Log();

logger.before.use(() => console.info('You are in the first step'));
logger.before.use(() => console.info('You are one step closer'));
logger.before.use((values) => {
	// If we want to stop chain, when «values» is not an Array
	// we return false from middleware
	return Array.isArray(values);
});
```

## In HTTP routes
```js
import { createServer } from 'http';
import { Middlewares } from 'small-middlewares';

import { User } from './storage/models.js';

const middlewares = new Middlewares();

// Any middleware could be an async function
const isUser = async (req, res, scope) => {
	const user = await User.findByToken(req.headers.authorization);
	// stops chain, if no user found
	if (!user) return false;
	scope.user = user;
};

const isAdmin = (req, res, scope) => {
	const { user } = scope;
	// stops chain, if user is not an admin
	return user.isAdmin;
};

const logHeaders = (req) => {
	// just log every headers object
	console.dir(req.headers, { depth: 10 });
};

middlewares.use(logHeaders, isUser, isAdmin);

createServer(async (req, res) => {
	try {
		const scope = {};
		const result = await middlewares.process(req, res, scope);

		if (!result) {
			res.writeHead(400);
			return res.end('Bad Request');
		}

		res.writeHead(200, { 'Content-Type': 'application/json' });
		return res.end(JSON.stringify(scope.user));
	} catch(err) {
		console.error(err);
		res.writeHead(500);
		return res.end('Internal Error');
	}

}).
	listen(3000);
```

# Methods
## `instance.use(...middlewares)`
It adds one or many middlewares into the chain.
Each middleware is a new param

## `instance.unuse(...middlewares)`
It removes one or many middlewares from the chain.
Each middleware is a new param

## `instance.useFirst(...middlewares)`
It like use, but it adds middelewares in the head of the chain.
Each middleware is a new param

## `instance.useBefore(middleware, ...middlewares)`
It adds one or many middlewares before a specific middleware (first param).
Each middleware is a new param

## `instance.useAfter(middleware, ...middlewares)`
It adds one or many middlewares after a specific middleware (first param).
Each middleware is a new param

## `instance.reset()`
Removes all middlewares from the chain

## `instance.process(...args)`
Asynchronously calls middlewares from chain with the `...args`, one by one.
If any middleware returns or resolves `false`, chain will stop, and the method will resolve `false`.
In other case, the method will resolve `true`.

## `instance.processWithStop(...args)`
It like the process method, but has differenes.
Asynchronously calls middlewares from chain with the `...args` and `stop`, one by one.

`stop` is a special function, if middleware will call `stop`, it will stop the chain.
Let's rewrite one of the previous examples:
```js
const instance = new Middlewares();
instance.use(() => console.info('You are in the first step'));
instance.use(() => console.info('You are one step closer'));
instance.use((user, stop) => {
	// if user is not admin, middleware will stop chain
	if (user !== 'admin') stop();
});
instance.use(() => console.info('It happens only if user is admin'));

const user = 'notAdmin';
const result = await instance.process(user);
if (result) {
	// it not happens, because result is now false
	doSomethingAfterMiddlewaresChain();
}
```

The `processWithStop` does not check that returns or resolves a middleware.
The chain stops only when `stop` function were called.

It also possible to put an error into the `stop` function params.
If middleware does this, the error will be thrown from `processWithStop`.

The method resolves `false`, when it was stopped, and `true` in other case.

## `instance.wrap(fn)`
This method returns a new function, which wraps around `fn`.
When the wrapped function calls, it will process middlewares of the `instance`.

`fn` will be called only when the chain will be completed.

You can change a context of the wrapped function if you wish.
You just need to attach it to an object, or you could use `.bind`, `.apply` or `.call` methods.

The wrapped function resolves result of the `fn` or `undefined`, if the chain has not completed.

## `instance.wrapWithStop(fn)`
This method like wrap, but it uses the `processWithStop` instead of the `process`.

---
_Source: https://npm.io/package/small-middlewares · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
