@loopback/express
Version:
Integrate with Express and expose middleware infrastructure for sequence and interceptors
272 lines (271 loc) • 9.3 kB
TypeScript
import { BindingAddress, Context, GenericInterceptor, GenericInterceptorChain, GenericInterceptorOrKey, InvocationContext, Next, ValueOrPromise } from '@loopback/core';
import { Request, RequestHandler, Response } from 'express';
export { Request, Response, Router, RouterOptions } from 'express';
/**
* An object holding HTTP request, response and other data
* needed to handle an incoming HTTP request.
*/
export interface HandlerContext {
readonly request: Request;
readonly response: Response;
}
/**
* Type alias for Express RequestHandler
*/
export type ExpressRequestHandler = RequestHandler;
/**
* A per-request Context for middleware to combine an IoC container with handler
* context (request, response, etc.).
*/
export declare class MiddlewareContext extends Context implements HandlerContext {
readonly request: Request;
readonly response: Response;
/**
* A flag to tell if the response is finished.
*/
responseFinished: boolean;
/**
* Constructor for `MiddlewareContext`
* @param request - Express request object
* @param response - Express response object
* @param parent - Parent context
* @param name - Name of the middleware context
*/
constructor(request: Request, response: Response, parent?: Context, name?: string);
protected setupBindings(): void;
}
/**
* A helper function to retrieve the MiddlewareContext/RequestContext from the
* request object
* @param request - Express request object
*/
export declare function getMiddlewareContext<T extends MiddlewareContext = MiddlewareContext>(request?: Request): T | undefined;
/**
* Interface LoopBack 4 middleware to be executed within sequence of actions.
* A middleware for LoopBack is basically a generic interceptor that uses
* `MiddlewareContext`.
*
* @remarks
*
* The middleware function is responsible for processing HTTP requests and
* responses. It typically includes the following logic.
*
* 1. Process the request with one of the following outcome
* - Reject the request by throwing an error if request is invalid, such as
* validation or authentication failures
* - Produce a response by itself, such as from the cache
* - Proceed by calling `await next()` to invoke downstream middleware. When
* `await next()` returns, it goes to step 2. If an error thrown from
* `await next()`, step 3 handles the error.
*
* 2. Process the response with one the following outcome
* - Reject the response by throwing an error
* - Replace the response with its own value
* - Return the response to upstream middleware
*
* 3. Catch the error thrown from `await next()`. If the `catch` block does not
* exist, the error will be bubbled up to upstream middleware
*
* The signature of a middleware function is described at
* {@link https://loopback.io/doc/en/lb4/apidocs.express.middleware.html | Middleware}.
* It's very much the same as
* {@link https://github.com/koajs/koa/blob/master/docs/guide.md#writing-middleware | Koa middleware}.
*
* @example
* ```ts
* const log: Middleware = async (requestCtx, next) => {
* const {request} = requestCtx;
* console.log('Request: %s %s', request.method, request.originalUrl);
* try {
* // Proceed with next middleware
* await next();
* console.log('Response received for %s %s', request.method, request.originalUrl);
* } catch(err) {
* console.error('Error received for %s %s', request.method, request.originalUrl);
* throw err;
* }
* }
* ```
*/
export interface Middleware extends GenericInterceptor<MiddlewareContext> {
}
/**
* An interceptor chain of middleware. This represents a list of cascading
* middleware functions to be executed by the order of `group` names.
*/
export declare class MiddlewareChain extends GenericInterceptorChain<MiddlewareContext> {
}
/**
* A middleware function or binding key
*/
export type MiddlewareOrKey = GenericInterceptorOrKey<MiddlewareContext>;
/**
* Default extension point name for middleware
*/
export declare const DEFAULT_MIDDLEWARE_CHAIN = "middlewareChain.default";
/**
* Options for `InvokeMiddleware`
*/
export interface InvokeMiddlewareOptions {
/**
* Name of the extension point. Default to the `extensionPoint` tag value
* from the binding
*/
chain?: string;
/**
* An array of group names to denote the order of execution, such as
* `['cors', 'caching', 'rate-limiting']`.
*/
orderedGroups?: string[];
/**
* An optional function to validate the sorted groups before invoking the
* middleware chain
*/
validate?: (groups: string[]) => void;
/**
* Pre-built middleware list. If set, the list will be used to create the
* middleware chain without discovering again within the context.
*/
middlewareList?: MiddlewareOrKey[];
/**
* Optional next handler
*/
next?: Next;
}
/**
* Interface for the invoker of middleware registered under the an extension
* point name.
*/
export interface InvokeMiddleware {
/**
* Invoke the request interceptors in the chain.
* @param middlewareCtx - Middleware Context
* @param options - Options for the invocation
*/
(middlewareCtx: MiddlewareContext, options?: InvokeMiddlewareOptions): ValueOrPromise<boolean>;
/**
* Invoke a list of Express middleware handler functions
*
* @example
* ```ts
* import cors from 'cors';
* import helmet from 'helmet';
* import morgan from 'morgan';
*
*
* const finished = await this.invokeMiddleware(
* middlewareCtx, [
* cors(),
* helmet(),
* morgan('combined'),
* ]);
*
* if (finished) {
* // Http response is sent by one of the middleware
* } else {
* // Http response is yet to be produced
* }
* ```
* @param middlewareCtx - Middleware context
* @param handlers - A list of Express middleware handler functions
*/
(middlewareCtx: MiddlewareContext, handlers: ExpressRequestHandler[]): ValueOrPromise<boolean>;
}
/**
* Options for defining a middleware
*/
export interface MiddlewareCreationOptions {
/**
* A flag to control if configuration for the middleware can be injected
* lazily.
*
* - `true` (default): creates a provider class with `@config`
* - `false`: No configuration injection is supported
* - 'watch': creates a provider class with `@config.view`
*/
injectConfiguration?: boolean | 'watch';
/**
* Class name for the created provider class. It's only used if
* `injectConfiguration` is not set to `false`.
*/
providerClassName?: string;
}
/**
* Options to create a middleware binding for the sequence action or interceptor.
* @typeParam CTX - Context class
*/
export interface BaseMiddlewareBindingOptions<CTX extends Context> extends MiddlewareCreationOptions {
/**
* Binding key for the middleware.
*/
key?: BindingAddress<GenericInterceptor<CTX>>;
/**
* An optional `group` name to be used for order of executions
*/
group?: string;
}
/**
* Options to bind a middleware as an interceptor to the context
*/
export interface MiddlewareInterceptorBindingOptions extends BaseMiddlewareBindingOptions<InvocationContext> {
/**
* A flag to control if the interceptor should be global. Default to `true`.
*/
global?: boolean;
}
/**
* Options to bind middleware as a request context based interceptor within an
* `InvokeMiddleware` action of the sequence.
*/
export interface MiddlewareBindingOptions extends BaseMiddlewareBindingOptions<MiddlewareContext> {
/**
* Name of the middleware extension point. Default to `DEFAULT_MIDDLEWARE_CHAIN`.
*/
chain?: string;
/**
* An array of group names for upstream middleware in the cascading order.
*
* For example, the `invokeMethod` depends on `parseParams` for request
* processing. The `upstreamGroups` for `invokeMethod` should be
* `['parseParams']`. The order of groups in the array does not matter.
*/
upstreamGroups?: string | string[];
/**
* An array of group names for downstream middleware in the cascading order.
*
* For example, the `sendResponse` depends on `invokeMethod` for response
* processing. The `downstreamGroups` for `sendResponse` should be
* `['invokeMethod']`. The order of groups in the array does not matter.
*/
downstreamGroups?: string | string[];
}
/**
* Interface for an express middleware factory
* @typeParam C - Configuration type
*/
export interface ExpressMiddlewareFactory<C> {
(middlewareConfig?: C): ExpressRequestHandler;
}
/**
* A symbol to store `MiddlewareContext` on the request object. This symbol
* can be referenced by name, before it is created.
*/
export declare const MIDDLEWARE_CONTEXT: unique symbol;
/**
* Constants for middleware groups
*/
export declare namespace MiddlewareGroups {
/**
* Enforce CORS
*/
const CORS = "cors";
/**
* Server OpenAPI specs
*/
const API_SPEC = "apiSpec";
/**
* Default middleware group
*/
const MIDDLEWARE = "middleware";
const DEFAULT = "middleware";
}