@priestine/routing
Advanced tools
Comparing version 1.4.0 to 2.0.0
{ | ||
"name": "@priestine/routing", | ||
"version": "1.4.0", | ||
"version": "2.0.0", | ||
"description": "Simple, declarative and dependency-free routing for Node.js", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
107
README.md
# @priestine/routing | ||
[![pipeline](https://gitlab.com/priestine/routing/badges/master/pipeline.svg)](https://gitlab.com/priestine/routing) [![codecov](https://codecov.io/gl/priestine/routing/branch/master/graph/badge.svg)](https://codecov.io/gl/priestine/routing) [![licence: MIT](https://img.shields.io/npm/l/@priestine/routing.svg)](https://gitlab.com/priestine/routing) [![docs: typedoc](https://img.shields.io/badge/docs-typedoc-blue.svg)](https://priestine.gitlab.io/routing) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier) [![versioning: semantics](https://img.shields.io/badge/versioning-semantics-912e5c.svg)](https://gitlab.com/priestine/semantics) [![npm](https://img.shields.io/npm/dt/@priestine/routing.svg)](https://www.npmjs.com/package/@priestine/routing) [![npm](https://img.shields.io/npm/v/@priestine/routing.svg)](https://www.npmjs.com/package/@priestine/routing) | ||
[![pipeline](https://gitlab.com/priestine/routing/badges/master/pipeline.svg)](https://gitlab.com/priestine/routing) [![codecov](https://codecov.io/gl/priestine/routing/branch/master/graph/badge.svg)](https://codecov.io/gl/priestine/routing) [![licence: MIT](https://img.shields.io/npm/l/@priestine/routing.svg)](https://gitlab.com/priestine/routing) [![docs: typedoc](https://img.shields.io/badge/docs-typedoc-blue.svg)](https://priestine.gitlab.io/routing) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier) [![versioning: semantics](https://img.shields.io/badge/versioning-semantics-912e5c.svg)](https://gitlab.com/priestine/semantics) [![npm](https://img.shields.io/npm/dt/@priestine/routing.svg)](https://www.npmjs.com/package/@priestine/routing) [![npm](https://img.shields.io/npm/v/@priestine/routing.svg)](https://www.npmjs.com/package/@priestine/routing) [![bundlephobia-min](https://img.shields.io/bundlephobia/min/@priestine/routing.svg)](https://bundlephobia.com/result?p=@priestine/routing) [![bundlephobia-minzip](https://img.shields.io/bundlephobia/minzip/@priestine/routing.svg)](https://bundlephobia.com/result?p=@priestine/routing) | ||
@@ -92,15 +92,18 @@ `@priestine/routing` brings simple and eloquent routing to Node.js. It currently only works with Node.js `http` server | ||
- **methods** - an array of HTTP methods that IncomingMessage method must be in | ||
- **middleware** - an array of `IMiddlewareLike` that will be processed inside a Pipeline if current IncomingMessage | ||
matches given url and methods | ||
- **middleware** - an array of `IMiddlewareLike` or an `HttpPipeline` that will be processed if current | ||
IncomingMessage matches given url and methods | ||
```javascript | ||
const router = HttpRouter.empty(); | ||
router.register('/', ['POST', 'PUT'], [ | ||
(ctx) => ctx.response.setHeader('Content-Type', 'application/json'), | ||
(ctx) => ctx.response.end('{ "success": true }'), | ||
]); | ||
router | ||
.register('/', ['POST', 'PUT'], [ | ||
(ctx) => ctx.response.setHeader('Content-Type', 'application/json'), | ||
(ctx) => ctx.response.end('{ "success": true }'), | ||
]) | ||
.register('/1', ['GET'], MyCustomHttpPipeline) | ||
; | ||
``` | ||
- `router.get` (or one of **get**, **post**, **put**, **patch**, **delete**, **options**, **head**) registers a | ||
route with the same method and accepts only url and array of middleware | ||
route with the same method and accepts only url and an HttpPipeline or array of middleware | ||
@@ -115,4 +118,4 @@ ```javascript | ||
- `router.beforeEach` and `router.afterEach` accept array of middleware that will be executed before/after each | ||
registered pipeline | ||
- `router.beforeEach` and `router.afterEach` accept array of middleware or a pipeline that will be executed | ||
before/after each registered pipeline | ||
@@ -173,3 +176,3 @@ ```javascript | ||
Middleware is a reusable piece of business logic that encapsulates one specific step. | ||
Middleware in `@priestine/routing` can be functional or class-based. Each middleware is provided with `ctx` argument: | ||
Middleware in `@priestine/routing` can be function- or class-based. Each middleware is provided with `ctx` argument: | ||
@@ -180,3 +183,3 @@ ```javascript | ||
response: ServerResponse, | ||
intermediate: { route: { url: string | RegExp, method: string } } & object, | ||
intermediate: { route: { url: string | RegExp, method: string } } & TIntermediate, | ||
error: Error | undefined, | ||
@@ -186,11 +189,18 @@ } | ||
If middleware is deterministic (meaning that it returns the context object or Promise resolving into the context | ||
object), the context object will be overriden by given value if it successfully validates through `isMiddlewareContext` | ||
guard. This is done for two reasons: | ||
1. Custom transformations for the context that entirely change it | ||
2. Easier testing | ||
Having said that, it is entirely optional and you can omit returning the context, thus the argument context will | ||
be passed to the next piece of middleware automatically. | ||
For passing any computed data to next middleware, you should assign it to `ctx.intermediate` that serves a purpose of | ||
transferring data along the pipeline. | ||
#### Function Middleware | ||
**Function middleware** is a fancy name for a function that accepts `ctx`. You don't need to return `ctx` after the | ||
computation is finished as it is done for you automatically. If the computation is asynchronous, you nee to return it | ||
wrapped into a Promise that resolves `ctx` object or rejects with an error. This will force the Pipeline to await for | ||
the Promise to resolve before moving on to the next middleware. | ||
**Function middleware** is a fancy name for a function that accepts `ctx`. | ||
@@ -217,5 +227,2 @@ ```javascript | ||
**Class-based middleware** must implement `IMiddleware` interface (it must have a `$process`) method that accepts `ctx`. | ||
You don't need to return `ctx` after the computation is finished as it is done for you automatically. If the computation | ||
is asynchronous, you nee to return it wrapped into a Promise that resolves `ctx` object or rejects with an error. This | ||
will force the Pipeline to await for the Promise to resolve before moving on to the next middleware. | ||
@@ -227,3 +234,3 @@ **NOTE**: When registering middleware in the Router, you must provide an **instance** of a class-based middleware. | ||
static applicationJson() { | ||
return new MyMiddleware('application/json'); | ||
return new SetContentTypeHeader('application/json'); | ||
} | ||
@@ -245,13 +252,19 @@ | ||
#### Parallel vs waterfall | ||
#### Parallel vs waterfall (Lazy vs Eager) | ||
Asynchronous middleware in the pipeline can be executed in either in parallel or sequentially. Each middleware can | ||
Asynchronous middleware in the pipeline can be executed either in parallel or sequentially. Each middleware can | ||
dictate which type of execution must be applied to it: | ||
- parallel execution does not block the pipeline and allows next middleware start processing even if the promise of | ||
current middleware has not been resolved. It this case, the Promise containing the result of current middleware | ||
- **parallel** execution does not block the pipeline and allows next middleware start processing even if the promise of | ||
current middleware has not been resolved. In this case, the Promise containing the result of current middleware | ||
computation can be directly assigned to the `ctx.intermediate` key and *awaited* later where necessary. This approach | ||
allows doing extra checks simultaneously and exit the pipeline if something is not right. Example: | ||
allows doing extra checks simultaneously and exit the pipeline if something is not right. This can be referred to as | ||
Lazy execution. Example: | ||
```javascript | ||
/** | ||
* `GetCurrentPost` doesn't block the next piece of middleware that can trigger exiting the pipeline | ||
* if user is not authenticated thus not allowed to see posts in this imaginary scenario. This allows writing middleware | ||
* in arbitrary order in some cases. | ||
*/ | ||
const GetCurrentPost = (ctx) => { | ||
@@ -274,12 +287,14 @@ ctx.intermediate.post = db.collection('posts').findOne({ id: ctx.intermediate.params.id }); | ||
In the example above `GetCurrentPost` doesn't block the next piece of middleware that can trigger exiting the pipeline | ||
if user is not authenticated thus not allowed to see posts in this imaginary scenario. This allows writing middleware | ||
in arbitrary order in some cases. | ||
- waterfall execution blocks the pipeline until current middleware is done. This is convenient in cases where further | ||
- **waterfall** execution blocks the pipeline until current middleware is done. This is convenient in cases where further | ||
execution of the pipeline heavily relies on the result of computation. To inform the pipeline that it needs to wait for | ||
current middleware to *await*, you need to return a Promise inside the middleware, that resolves with amended | ||
`ctx`: | ||
current middleware to resolve, you need to return a Promise inside the middleware. This can be referred to as Eager | ||
execution. Example: | ||
```javascript | ||
/** | ||
* `IsAuthorized` blocks the middleware until the `ctx` is resolved. Thus, the Promise is rejected, | ||
* the pipeline will be exited and no further computation will be executed, being replaced with emitting a | ||
* `pipelineError` event. | ||
*/ | ||
const IsAuthorized = (ctx) => new Promise((resolve, reject) => { | ||
@@ -290,3 +305,3 @@ db.collection('users').findOne({ _id: ctx.intermediate.userId }) | ||
ctx.intermediate.userAuhorized = true; | ||
resolve(ctx); | ||
resolve(); // To make this middleware deterministic, use resolve(ctx) | ||
return; | ||
@@ -309,12 +324,9 @@ } | ||
In the example above `IsAuthorized` blocks the middleware until the `ctx` is resolved. Thus, the Promise is rejected, | ||
the pipeline will be exited and no further computation will be executed, being replaced with `HttpRouter.onError`. | ||
#### Generic Context | ||
#### IGenericMiddlewareLike | ||
`@priestine/routing` is written in TypeScript and provides generic context interfaces for providing typings of | ||
`@priestine/routing` is written in TypeScript and provides generic context interfaces for describing types of | ||
`ctx.intermediate`: | ||
```typescript | ||
import { IGenericHttpContext } from '@priestine/routing'; | ||
import { IHttpContext } from '@priestine/routing'; | ||
@@ -328,3 +340,3 @@ interface IUserAware { | ||
export const GetUser = (ctx: IGenericHttpContext<IUserAware>) => { | ||
export const GetUser = (ctx: IHttpContext<IUserAware>) => { | ||
ctx.intermediate.user = { | ||
@@ -357,7 +369,8 @@ _id: '123123123123', | ||
Error handling in `@priestine/routing` is done using the same concept of middleware yet error handlers are registered | ||
statically to be available anywhere: | ||
Error handling in `@priestine/routing` provides a statically available event emitter that you can use to trigger and/or | ||
subscribe to events. Internally, there is only one base event that is emitted by `@priestine/routing` which is called | ||
**pipelineError**. This event is emitted if incoming request does not match any of registered routes: | ||
```javascript | ||
HttpRouter.onError([ | ||
HttpRouter.eventEmitter.on('pipelineError', (ctx) => HttpPipeline.of([ | ||
(ctx) => ctx.response.setHeader('Content-Type', 'application/json'), | ||
@@ -369,13 +382,11 @@ (ctx) => ctx.intermediate.body = { | ||
(ctx) => ctx.response.end(JSON.stringify(ctx.intermediate.body)), | ||
]); | ||
]).$process(ctx)); | ||
``` | ||
If something goes wrong, the middleware pipeline is aborted and a new pipeline of `HttpRouter.errorHandlers` (provided | ||
with `HttpRouter.onError`) is issued using the `ctx` of the pipeline that broke down. You can debug the nature of the | ||
If something goes wrong, the middleware pipeline is aborted and a new pipeline assigned with event listener | ||
is processed using the `ctx` of the pipeline that broke down. You can debug the nature of the | ||
error by checking the contents of the `ctx.intermediate` as it will have all the amendments up to the moment where it | ||
crashed. | ||
**NOTE**: `beforeEach` and `afterEach` are not applied to error handlers! | ||
To force quitting current pipeline, you can either **throw** (synchronous middleware) or **reject()** (asynchronous | ||
middleware). |
@@ -0,3 +1,5 @@ | ||
export * from './is-matcher'; | ||
export * from './is-middleware-context'; | ||
export * from './is-middleware-object.guard'; | ||
export * from './is-pipeline'; | ||
export * from './is-regexp-matcher.guard'; |
@@ -6,2 +6,4 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
__export(require("./is-matcher")); | ||
__export(require("./is-middleware-context")); | ||
__export(require("./is-middleware-object.guard")); | ||
@@ -8,0 +10,0 @@ __export(require("./is-pipeline")); |
@@ -9,3 +9,3 @@ "use strict"; | ||
*/ | ||
exports.isMiddlewareObject = (x) => '$process' in x; | ||
exports.isMiddlewareObject = (x) => typeof x === 'object' && '$process' in x; | ||
//# sourceMappingURL=is-middleware-object.guard.js.map |
@@ -9,3 +9,3 @@ "use strict"; | ||
*/ | ||
exports.isPipeline = (x) => '$process' in x && 'done' in x && 'isEmpty' in x; | ||
exports.isPipeline = (x) => '$process' in x && 'done' in x && 'isEmpty' in x && 'next' in x && 'throw' in x; | ||
//# sourceMappingURL=is-pipeline.js.map |
@@ -9,3 +9,3 @@ "use strict"; | ||
*/ | ||
exports.isRegExpMatcher = (x) => 'url' in x && typeof x.url !== 'string' && 'source' in x.url; | ||
exports.isRegExpMatcher = (x) => typeof x === 'object' && 'url' in x && typeof x.url !== 'string' && 'source' in x.url; | ||
//# sourceMappingURL=is-regexp-matcher.guard.js.map |
@@ -7,2 +7,3 @@ import { IDefaultIntermediate } from './default-intermediate.interface'; | ||
* @interface IGenericMiddlewareContext<TIntermediate> | ||
* @deprecated use IMiddlewareContext<T> instead | ||
*/ | ||
@@ -9,0 +10,0 @@ export interface IGenericMiddlewareContext<TIntermediate> extends IMiddlewareContext { |
@@ -11,2 +11,3 @@ /** | ||
* Evaluate incoming message and deduce if it matches current route. | ||
* | ||
* @param {TRequest} message | ||
@@ -16,2 +17,9 @@ * @returns {boolean} | ||
matches(message: TRequest): boolean; | ||
/** | ||
* Prepend given prefix to matcher URL. | ||
* | ||
* @param prefix | ||
* @returns {IMatcher<TUrl, TRequest>} | ||
*/ | ||
withPrefix(prefix: string | RegExp): IMatcher<TUrl, TRequest>; | ||
} |
@@ -8,7 +8,7 @@ import { IDefaultIntermediate } from './default-intermediate.interface'; | ||
*/ | ||
export interface IMiddlewareContext { | ||
export interface IMiddlewareContext<TAdditional = {}> { | ||
/** | ||
* Data passed from previous middleware. | ||
*/ | ||
intermediate: IDefaultIntermediate; | ||
intermediate: IDefaultIntermediate & TAdditional; | ||
} |
@@ -10,3 +10,9 @@ /** | ||
export interface IMiddleware<TContext> { | ||
/** | ||
* Process current middleware with given context. | ||
* | ||
* @param {TContext} ctx | ||
* @returns {any} | ||
*/ | ||
$process(ctx: TContext): any; | ||
} |
@@ -0,1 +1,2 @@ | ||
import { IHttpMiddlewareLike } from '../../http/interfaces'; | ||
import { IMiddlewareContext } from './middleware-context.interface'; | ||
@@ -30,2 +31,12 @@ import { IMiddlewareLike } from './middleware-like.interface'; | ||
concat(x: IPipeline<TContext>): IPipeline<TContext>; | ||
/** | ||
* @param {IHttpMiddlewareLike} value | ||
* @returns {IMiddlewareLike<TContext>} | ||
*/ | ||
next(value?: IHttpMiddlewareLike): IteratorResult<IMiddlewareLike<TContext>>; | ||
/** | ||
* @param value | ||
* @returns {IteratorResult<any>} | ||
*/ | ||
throw(value?: any): IteratorResult<any>; | ||
} |
@@ -18,2 +18,3 @@ /// <reference types="node" /> | ||
* URL for matching. | ||
* | ||
* @protected | ||
@@ -24,2 +25,3 @@ */ | ||
* HTTP method for matching. | ||
* | ||
* @protected | ||
@@ -39,2 +41,3 @@ */ | ||
* URL for matching. | ||
* | ||
* @returns {T} | ||
@@ -45,2 +48,3 @@ */ | ||
* Method for matching. | ||
* | ||
* @returns {keyof typeof HttpMethods} | ||
@@ -51,2 +55,3 @@ */ | ||
* Check if current IncomingMessage matches current route. | ||
* | ||
* @param {string} url | ||
@@ -58,2 +63,9 @@ * @param {string} method | ||
/** | ||
* Prepend given prefix to matcher URL. | ||
* | ||
* @param prefix | ||
* @returns {IMatcher<TUrl, TRequest>} | ||
*/ | ||
abstract withPrefix(prefix: string | RegExp): IHttpMatcher<any>; | ||
/** | ||
* Extract IncomingMessage URL pathname. | ||
@@ -60,0 +72,0 @@ * |
@@ -26,2 +26,3 @@ "use strict"; | ||
* URL for matching. | ||
* | ||
* @returns {T} | ||
@@ -34,2 +35,3 @@ */ | ||
* Method for matching. | ||
* | ||
* @returns {keyof typeof HttpMethods} | ||
@@ -36,0 +38,0 @@ */ |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const errors_1 = require("../errors"); | ||
const http_router_1 = require("../http-router"); | ||
@@ -23,4 +24,4 @@ /** | ||
if (route.value.isEmpty) { | ||
ctx.intermediate.error = new Error(`Cannot ${ctx.request.method} ${ctx.request.url}`); | ||
http_router_1.HttpRouter.handleError(ctx); | ||
ctx.intermediate.error = errors_1.HttpError.from(new Error(`Cannot ${ctx.request.method} ${ctx.request.url}`)).withStatusCode(404); | ||
http_router_1.HttpRouter.eventEmitter.emit('pipelineError', ctx); | ||
return; | ||
@@ -27,0 +28,0 @@ } |
@@ -12,2 +12,3 @@ "use strict"; | ||
const guards_1 = require("../common/guards"); | ||
const guards_2 = require("./guards"); | ||
const http_router_1 = require("./http-router"); | ||
@@ -93,2 +94,3 @@ /** | ||
return __awaiter(this, void 0, void 0, function* () { | ||
let internalCtx = Object.assign({}, ctx); | ||
while (!this.done) { | ||
@@ -98,7 +100,10 @@ try { | ||
const process = guards_1.isMiddlewareObject(next) ? next.$process : next; | ||
yield process(ctx); | ||
const result = yield process(internalCtx); | ||
if (result && guards_2.isHttpMiddlewareContext(result)) { | ||
internalCtx = Object.assign({}, result); | ||
} | ||
} | ||
catch (e) { | ||
ctx.intermediate.error = e; | ||
yield http_router_1.HttpRouter.handleError(ctx); | ||
http_router_1.HttpRouter.eventEmitter.emit('pipelineError', ctx); | ||
return; | ||
@@ -105,0 +110,0 @@ } |
@@ -100,3 +100,3 @@ /// <reference types="node" /> | ||
*/ | ||
add(url: string | RegExp, methods: Array<keyof typeof HttpMethods>, middleware: IPipeline<IHttpContext> | IHttpMiddlewareLike[]): this; | ||
add(url: string | RegExp | IHttpMatcher<any>, methods: Array<keyof typeof HttpMethods>, middleware: IPipeline<IHttpContext> | IHttpMiddlewareLike[]): this; | ||
/** | ||
@@ -103,0 +103,0 @@ * Check if internal map has given key. |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const guards_1 = require("../common/guards"); | ||
const guards_2 = require("./guards"); | ||
const helpers_1 = require("./helpers"); | ||
@@ -100,3 +101,4 @@ const http_pipeline_1 = require("./http-pipeline"); | ||
: http_pipeline_1.HttpPipeline.empty(); | ||
return route ? { key: { url: route.url, method: route.method }, value } : { key: undefined, value }; | ||
const key = route ? { url: route.url, method: route.method } : undefined; | ||
return { key, value }; | ||
} | ||
@@ -112,5 +114,11 @@ /** | ||
add(url, methods, middleware) { | ||
url = helpers_1.mergePrefixAndUrl(this._prefix, url); | ||
methods.forEach((method) => { | ||
const key = typeof url === 'string' ? matchers_1.StringHttpMatcher.of({ url, method }) : matchers_1.RegExpHttpMatcher.of({ url, method }); | ||
const key = (guards_2.isHttpMatcher(url) | ||
? url | ||
: typeof url === 'string' | ||
? matchers_1.StringHttpMatcher.of({ url, method }) | ||
: matchers_1.RegExpHttpMatcher.of({ | ||
url: url, | ||
method, | ||
})).withPrefix(this._prefix); | ||
this._routes.set(key, guards_1.isPipeline(middleware) ? middleware : http_pipeline_1.HttpPipeline.of(middleware)); | ||
@@ -117,0 +125,0 @@ }); |
@@ -0,5 +1,7 @@ | ||
/// <reference types="node" /> | ||
import { EventEmitter } from 'events'; | ||
import { IPipeline } from '../common/interfaces'; | ||
import { HttpMethods } from './enums'; | ||
import { HttpRouteMap } from './http-route-map'; | ||
import { IHttpContext, IHttpMiddlewareLike } from './interfaces'; | ||
import { IHttpContext, IHttpMatcher, IHttpMiddlewareLike } from './interfaces'; | ||
/** | ||
@@ -20,3 +22,3 @@ * HTTP router provides fluent interface for registering routeMap. | ||
* | ||
* @param {string | RegExp} prefix | ||
* @param {IHttpMatcher<any> | >string | RegExp} prefix | ||
* @returns {HttpRouter} | ||
@@ -33,29 +35,8 @@ */ | ||
/** | ||
* Handle caught error by creating an emergency Pipeline from the HttpRouter.errorHandlers and process it using | ||
* current context. | ||
* Static router event bus. | ||
* | ||
* @param {IHttpContext} ctx | ||
* @type {module:events.internal.EventEmitter} | ||
*/ | ||
static handleError(ctx: IHttpContext): void; | ||
static eventEmitter: EventEmitter; | ||
/** | ||
* Array of error handler middleware. This middleware is used by Router.handleError for processing unhandled errors. | ||
* | ||
* @type {((ctx: IHttpContext) => void)[]} | ||
*/ | ||
protected static _errorHandlers: IHttpMiddlewareLike[]; | ||
/** | ||
* Register middleware to handle errors that occur during pipeline execution. | ||
* | ||
* **NOTE**: this is going to get deprecated soon. | ||
* | ||
* @param {IHttpMiddlewareLike[]} middleware | ||
*/ | ||
static onError(middleware: IHttpMiddlewareLike[]): void; | ||
/** | ||
* Getter for _errorHandlers. | ||
* | ||
* @returns {IHttpMiddlewareLike[]} | ||
*/ | ||
static readonly errorHandlers: IHttpMiddlewareLike[]; | ||
/** | ||
* Internally stored HttpRouteMap. | ||
@@ -95,3 +76,3 @@ * | ||
* | ||
* @param {string | RegExp} url | ||
* @param {IHttpMatcher<any> | >string | RegExp} url | ||
* @param {Array<keyof typeof HttpMethods>} methods | ||
@@ -101,3 +82,3 @@ * @param {IPipeline<IHttpContext> | IHttpMiddlewareLike[]} middleware | ||
*/ | ||
register(url: string | RegExp, methods: Array<keyof typeof HttpMethods>, middleware: IPipeline<IHttpContext> | IHttpMiddlewareLike[]): this; | ||
register(url: IHttpMatcher<any> | string | RegExp, methods: Array<keyof typeof HttpMethods>, middleware: IPipeline<IHttpContext> | IHttpMiddlewareLike[]): this; | ||
/** | ||
@@ -107,7 +88,7 @@ * Helper method for registering GET routes. | ||
* @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html | ||
* @param {string | RegExp} url | ||
* @param {IHttpMatcher<any> | >string | RegExp} url | ||
* @param {IPipeline<IHttpContext> | IHttpMiddlewareLike[]} middleware | ||
* @returns {HttpRouteMap} | ||
*/ | ||
get(url: string | RegExp, middleware: IPipeline<IHttpContext> | IHttpMiddlewareLike[]): HttpRouter; | ||
get(url: IHttpMatcher<any> | string | RegExp, middleware: IPipeline<IHttpContext> | IHttpMiddlewareLike[]): HttpRouter; | ||
/** | ||
@@ -117,7 +98,7 @@ * Helper method for registering POST routes. | ||
* @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html | ||
* @param {string | RegExp} url | ||
* @param {IHttpMatcher<any> | >string | RegExp} url | ||
* @param {IPipeline<IHttpContext> | IHttpMiddlewareLike[]} middleware | ||
* @returns {HttpRouter} | ||
*/ | ||
post(url: string | RegExp, middleware: IPipeline<IHttpContext> | IHttpMiddlewareLike[]): HttpRouter; | ||
post(url: IHttpMatcher<any> | string | RegExp, middleware: IPipeline<IHttpContext> | IHttpMiddlewareLike[]): HttpRouter; | ||
/** | ||
@@ -127,7 +108,7 @@ * Helper method for registering PUT routes. | ||
* @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html | ||
* @param {string | RegExp} url | ||
* @param {IHttpMatcher<any> | >string | RegExp} url | ||
* @param {IPipeline<IHttpContext> | IHttpMiddlewareLike[]} middleware | ||
* @returns {HttpRouter} | ||
*/ | ||
put(url: string | RegExp, middleware: IPipeline<IHttpContext> | IHttpMiddlewareLike[]): HttpRouter; | ||
put(url: IHttpMatcher<any> | string | RegExp, middleware: IPipeline<IHttpContext> | IHttpMiddlewareLike[]): HttpRouter; | ||
/** | ||
@@ -137,7 +118,7 @@ * Helper method for registering PATCH routes. | ||
* @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html | ||
* @param {string | RegExp} url | ||
* @param {IHttpMatcher<any> | >string | RegExp} url | ||
* @param {IPipeline<IHttpContext> | IHttpMiddlewareLike[]} middleware | ||
* @returns {HttpRouter} | ||
*/ | ||
patch(url: string | RegExp, middleware: IPipeline<IHttpContext> | IHttpMiddlewareLike[]): HttpRouter; | ||
patch(url: IHttpMatcher<any> | string | RegExp, middleware: IPipeline<IHttpContext> | IHttpMiddlewareLike[]): HttpRouter; | ||
/** | ||
@@ -147,7 +128,7 @@ * Helper method for registering DELETE routes. | ||
* @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html | ||
* @param {string | RegExp} url | ||
* @param {IHttpMatcher<any> | >string | RegExp} url | ||
* @param {IPipeline<IHttpContext> | IHttpMiddlewareLike[]} middleware | ||
* @returns {HttpRouter} | ||
*/ | ||
delete(url: string | RegExp, middleware: IPipeline<IHttpContext> | IHttpMiddlewareLike[]): HttpRouter; | ||
delete(url: IHttpMatcher<any> | string | RegExp, middleware: IPipeline<IHttpContext> | IHttpMiddlewareLike[]): HttpRouter; | ||
/** | ||
@@ -157,7 +138,7 @@ * Helper method for registering OPTIONS routes. | ||
* @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html | ||
* @param {string | RegExp} url | ||
* @param {IHttpMatcher<any> | >string | RegExp} url | ||
* @param {IPipeline<IHttpContext> | IHttpMiddlewareLike[]} middleware | ||
* @returns {HttpRouter} | ||
*/ | ||
options(url: string | RegExp, middleware: IPipeline<IHttpContext> | IHttpMiddlewareLike[]): HttpRouter; | ||
options(url: IHttpMatcher<any> | string | RegExp, middleware: IPipeline<IHttpContext> | IHttpMiddlewareLike[]): HttpRouter; | ||
/** | ||
@@ -167,7 +148,7 @@ * Helper method for registering HEAD routes. | ||
* @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html | ||
* @param {string | RegExp} url | ||
* @param {IHttpMatcher<any> | >string | RegExp} url | ||
* @param {IPipeline<IHttpContext> | IHttpMiddlewareLike[]} middleware | ||
* @returns {HttpRouter} | ||
*/ | ||
head(url: string | RegExp, middleware: IPipeline<IHttpContext> | IHttpMiddlewareLike[]): HttpRouter; | ||
head(url: IHttpMatcher<any> | string | RegExp, middleware: IPipeline<IHttpContext> | IHttpMiddlewareLike[]): HttpRouter; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const events_1 = require("events"); | ||
const enums_1 = require("./enums"); | ||
const http_pipeline_1 = require("./http-pipeline"); | ||
const http_route_map_1 = require("./http-route-map"); | ||
@@ -32,3 +32,3 @@ /** | ||
* | ||
* @param {string | RegExp} prefix | ||
* @param {IHttpMatcher<any> | >string | RegExp} prefix | ||
* @returns {HttpRouter} | ||
@@ -51,29 +51,2 @@ */ | ||
/** | ||
* Handle caught error by creating an emergency Pipeline from the HttpRouter.errorHandlers and process it using | ||
* current context. | ||
* | ||
* @param {IHttpContext} ctx | ||
*/ | ||
static handleError(ctx) { | ||
http_pipeline_1.HttpPipeline.of(HttpRouter.errorHandlers).$process(ctx); | ||
} | ||
/** | ||
* Register middleware to handle errors that occur during pipeline execution. | ||
* | ||
* **NOTE**: this is going to get deprecated soon. | ||
* | ||
* @param {IHttpMiddlewareLike[]} middleware | ||
*/ | ||
static onError(middleware) { | ||
this._errorHandlers = middleware; | ||
} | ||
/** | ||
* Getter for _errorHandlers. | ||
* | ||
* @returns {IHttpMiddlewareLike[]} | ||
*/ | ||
static get errorHandlers() { | ||
return this._errorHandlers; | ||
} | ||
/** | ||
* Getter for _routeMap. | ||
@@ -116,3 +89,3 @@ */ | ||
* | ||
* @param {string | RegExp} url | ||
* @param {IHttpMatcher<any> | >string | RegExp} url | ||
* @param {Array<keyof typeof HttpMethods>} methods | ||
@@ -130,3 +103,3 @@ * @param {IPipeline<IHttpContext> | IHttpMiddlewareLike[]} middleware | ||
* @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html | ||
* @param {string | RegExp} url | ||
* @param {IHttpMatcher<any> | >string | RegExp} url | ||
* @param {IPipeline<IHttpContext> | IHttpMiddlewareLike[]} middleware | ||
@@ -142,3 +115,3 @@ * @returns {HttpRouteMap} | ||
* @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html | ||
* @param {string | RegExp} url | ||
* @param {IHttpMatcher<any> | >string | RegExp} url | ||
* @param {IPipeline<IHttpContext> | IHttpMiddlewareLike[]} middleware | ||
@@ -154,3 +127,3 @@ * @returns {HttpRouter} | ||
* @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html | ||
* @param {string | RegExp} url | ||
* @param {IHttpMatcher<any> | >string | RegExp} url | ||
* @param {IPipeline<IHttpContext> | IHttpMiddlewareLike[]} middleware | ||
@@ -166,3 +139,3 @@ * @returns {HttpRouter} | ||
* @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html | ||
* @param {string | RegExp} url | ||
* @param {IHttpMatcher<any> | >string | RegExp} url | ||
* @param {IPipeline<IHttpContext> | IHttpMiddlewareLike[]} middleware | ||
@@ -178,3 +151,3 @@ * @returns {HttpRouter} | ||
* @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html | ||
* @param {string | RegExp} url | ||
* @param {IHttpMatcher<any> | >string | RegExp} url | ||
* @param {IPipeline<IHttpContext> | IHttpMiddlewareLike[]} middleware | ||
@@ -190,3 +163,3 @@ * @returns {HttpRouter} | ||
* @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html | ||
* @param {string | RegExp} url | ||
* @param {IHttpMatcher<any> | >string | RegExp} url | ||
* @param {IPipeline<IHttpContext> | IHttpMiddlewareLike[]} middleware | ||
@@ -202,3 +175,3 @@ * @returns {HttpRouter} | ||
* @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html | ||
* @param {string | RegExp} url | ||
* @param {IHttpMatcher<any> | >string | RegExp} url | ||
* @param {IPipeline<IHttpContext> | IHttpMiddlewareLike[]} middleware | ||
@@ -212,8 +185,8 @@ * @returns {HttpRouter} | ||
/** | ||
* Array of error handler middleware. This middleware is used by Router.handleError for processing unhandled errors. | ||
* Static router event bus. | ||
* | ||
* @type {((ctx: IHttpContext) => void)[]} | ||
* @type {module:events.internal.EventEmitter} | ||
*/ | ||
HttpRouter._errorHandlers = []; | ||
HttpRouter.eventEmitter = new events_1.EventEmitter(); | ||
exports.HttpRouter = HttpRouter; | ||
//# sourceMappingURL=http-router.js.map |
export * from './core'; | ||
export * from './enums'; | ||
export * from './errors'; | ||
export * from './guards'; | ||
export * from './helpers'; | ||
@@ -5,0 +6,0 @@ export * from './interfaces'; |
@@ -9,2 +9,3 @@ "use strict"; | ||
__export(require("./errors")); | ||
__export(require("./guards")); | ||
__export(require("./helpers")); | ||
@@ -11,0 +12,0 @@ __export(require("./matchers")); |
@@ -8,2 +8,3 @@ import { IDefaultHttpIntermediate } from './default-http-intermediate.interface'; | ||
* @extends IHttpContext | ||
* @deprecated use IHttpContext<T> instead | ||
*/ | ||
@@ -10,0 +11,0 @@ export interface IGenericHttpContext<TIntermediate> extends IHttpContext { |
@@ -7,6 +7,7 @@ /// <reference types="node" /> | ||
* Http context describes argument passed to each Middleware.process method. | ||
* | ||
* @interface IHttpContext | ||
* @extends IMiddlewareContext | ||
*/ | ||
export interface IHttpContext extends IMiddlewareContext { | ||
export interface IHttpContext<T = {}> extends IMiddlewareContext<T> { | ||
/** | ||
@@ -23,3 +24,3 @@ * Node.js http.IncomingMessage. | ||
*/ | ||
intermediate: IDefaultHttpIntermediate; | ||
intermediate: IDefaultHttpIntermediate & T; | ||
} |
@@ -8,2 +8,2 @@ import { IMiddlewareFunction } from '../../common/interfaces'; | ||
*/ | ||
export declare type HttpMiddlewareFunctionInterface = IMiddlewareFunction<IHttpContext>; | ||
export declare type IHttpMiddlewareFunction = IMiddlewareFunction<IHttpContext>; |
@@ -1,8 +0,8 @@ | ||
import { HttpMiddlewareFunctionInterface } from './http-middleware-function.interface'; | ||
import { HttpMiddlewareInterface } from './http-middleware.interface'; | ||
import { IHttpMiddlewareFunction } from './http-middleware-function.interface'; | ||
import { IHttpMiddleware } from './http-middleware.interface'; | ||
/** | ||
* Descriptor for HTTP Middleware represented as either class-based middleware or function middleware. | ||
* | ||
* @type HttpMiddlewareInterface | HttpMiddlewareFunctionInterface | ||
* @type IHttpMiddleware | IHttpMiddlewareFunction | ||
*/ | ||
export declare type IHttpMiddlewareLike = HttpMiddlewareInterface | HttpMiddlewareFunctionInterface; | ||
export declare type IHttpMiddlewareLike = IHttpMiddleware | IHttpMiddlewareFunction; |
@@ -6,4 +6,5 @@ import { IMiddleware } from '../../common/interfaces'; | ||
* | ||
* @type IMiddleware<IHttpContext> | ||
* @interface IMiddleware<IHttpContext> | ||
*/ | ||
export declare type HttpMiddlewareInterface = IMiddleware<IHttpContext>; | ||
export interface IHttpMiddleware extends IMiddleware<IHttpContext> { | ||
} |
@@ -5,2 +5,3 @@ /// <reference types="node" /> | ||
import { HttpMethods } from '../enums'; | ||
import { IHttpMatcher } from '../interfaces'; | ||
/** | ||
@@ -27,2 +28,9 @@ * RegExp-based route. These are evaluated second. | ||
matches({ url, method }: IncomingMessage): boolean; | ||
/** | ||
* Prepend given prefix to matcher URL. | ||
* | ||
* @param prefix | ||
* @returns {IMatcher<TUrl, TRequest>} | ||
*/ | ||
withPrefix(prefix: string | RegExp): IHttpMatcher<any>; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const core_1 = require("../core"); | ||
const helpers_1 = require("../helpers"); | ||
const string_http_matcher_1 = require("./string-http-matcher"); | ||
/** | ||
@@ -26,4 +28,15 @@ * RegExp-based route. These are evaluated second. | ||
} | ||
/** | ||
* Prepend given prefix to matcher URL. | ||
* | ||
* @param prefix | ||
* @returns {IMatcher<TUrl, TRequest>} | ||
*/ | ||
withPrefix(prefix) { | ||
const url = helpers_1.mergePrefixAndUrl(prefix, this.url); | ||
const method = this._method; | ||
return typeof url === 'string' ? string_http_matcher_1.StringHttpMatcher.of({ url, method }) : RegExpHttpMatcher.of({ url, method }); | ||
} | ||
} | ||
exports.RegExpHttpMatcher = RegExpHttpMatcher; | ||
//# sourceMappingURL=regexp-http-matcher.js.map |
@@ -5,2 +5,3 @@ /// <reference types="node" /> | ||
import { HttpMethods } from '../enums'; | ||
import { IHttpMatcher } from '../interfaces'; | ||
/** | ||
@@ -32,2 +33,9 @@ * String-based route matcher. String-based route matchers should be used at all times when no dynamic content is | ||
matches({ url, method }: IncomingMessage): boolean; | ||
/** | ||
* Prepend given prefix to matcher URL. | ||
* | ||
* @param prefix | ||
* @returns {IMatcher<TUrl, TRequest>} | ||
*/ | ||
withPrefix(prefix: string | RegExp): IHttpMatcher<any>; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const core_1 = require("../core"); | ||
const helpers_1 = require("../helpers"); | ||
const regexp_http_matcher_1 = require("./regexp-http-matcher"); | ||
/** | ||
@@ -31,4 +33,15 @@ * String-based route matcher. String-based route matchers should be used at all times when no dynamic content is | ||
} | ||
/** | ||
* Prepend given prefix to matcher URL. | ||
* | ||
* @param prefix | ||
* @returns {IMatcher<TUrl, TRequest>} | ||
*/ | ||
withPrefix(prefix) { | ||
const url = helpers_1.mergePrefixAndUrl(prefix, this.url); | ||
const method = this._method; | ||
return typeof url === 'string' ? StringHttpMatcher.of({ url, method }) : regexp_http_matcher_1.RegExpHttpMatcher.of({ url, method }); | ||
} | ||
} | ||
exports.StringHttpMatcher = StringHttpMatcher; | ||
//# sourceMappingURL=string-http-matcher.js.map |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
192673
150
1916
379