mirror of
https://github.com/nestjs/nest.git
synced 2026-02-21 23:11:44 +00:00
feat(): add response passthrough configuration property
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/core",
|
||||
"version": "7.4.0",
|
||||
"version": "7.5.3",
|
||||
"description": "Modern, fast, powerful node.js web framework",
|
||||
"homepage": "https://nestjs.com",
|
||||
"repository": {
|
||||
|
||||
@@ -26,4 +26,5 @@ export const HTTP_CODE_METADATA = '__httpCode__';
|
||||
export const MODULE_PATH = '__module_path__';
|
||||
export const HEADERS_METADATA = '__headers__';
|
||||
export const REDIRECT_METADATA = '__redirect__';
|
||||
export const RESPONSE_PASSTHROUGH_METADATA = '__responsePassthrough__';
|
||||
export const SSE_METADATA = '__sse__';
|
||||
|
||||
@@ -1,9 +1,26 @@
|
||||
import { ROUTE_ARGS_METADATA } from '../../constants';
|
||||
import {
|
||||
RESPONSE_PASSTHROUGH_METADATA,
|
||||
ROUTE_ARGS_METADATA,
|
||||
} from '../../constants';
|
||||
import { RouteParamtypes } from '../../enums/route-paramtypes.enum';
|
||||
import { PipeTransform } from '../../index';
|
||||
import { Type } from '../../interfaces';
|
||||
import { isNil, isString } from '../../utils/shared.utils';
|
||||
|
||||
/**
|
||||
* The `@Response()`/`@Res` parameter decorator options.
|
||||
*/
|
||||
export interface ResponseDecoratorOptions {
|
||||
/**
|
||||
* Determines whether the response will be sent manually within the route handler,
|
||||
* with the use of native response handling methods exposed by the platform-specific response object,
|
||||
* or if it should passthrough Nest response processing pipeline.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
passthrough: boolean;
|
||||
}
|
||||
|
||||
export type ParamData = object | string | number;
|
||||
export interface RouteParamMetadata {
|
||||
index: number;
|
||||
@@ -85,21 +102,35 @@ export const Request: () => ParameterDecorator = createRouteParamDecorator(
|
||||
*
|
||||
* Example: `logout(@Response() res)`
|
||||
*
|
||||
* @see [Request object](https://docs.nestjs.com/controllers#request-object)
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
export const Response: () => ParameterDecorator = createRouteParamDecorator(
|
||||
RouteParamtypes.RESPONSE,
|
||||
);
|
||||
export const Response: (
|
||||
options?: ResponseDecoratorOptions,
|
||||
) => ParameterDecorator = (options?: ResponseDecoratorOptions) => (
|
||||
target,
|
||||
key,
|
||||
index,
|
||||
) => {
|
||||
if (options?.passthrough) {
|
||||
Reflect.defineMetadata(
|
||||
RESPONSE_PASSTHROUGH_METADATA,
|
||||
options?.passthrough,
|
||||
target.constructor,
|
||||
key,
|
||||
);
|
||||
}
|
||||
return createRouteParamDecorator(RouteParamtypes.RESPONSE)()(
|
||||
target,
|
||||
key,
|
||||
index,
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Route handler parameter decorator. Extracts reference to the `Next` function
|
||||
* from the underlying platform and populates the decorated
|
||||
* parameter with the value of `Next`.
|
||||
*
|
||||
* @see [Request object](https://docs.nestjs.com/controllers#request-object)
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
export const Next: () => ParameterDecorator = createRouteParamDecorator(
|
||||
|
||||
@@ -21,7 +21,7 @@ export interface DynamicModule extends ModuleMetadata {
|
||||
* in all modules. Thereafter, modules that wish to inject a service exported
|
||||
* from a global module do not need to import the provider module.
|
||||
*
|
||||
* Default: false
|
||||
* @default false
|
||||
*/
|
||||
global?: boolean;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { ParamData } from '@nestjs/common';
|
||||
import { PARAMTYPES_METADATA } from '@nestjs/common/constants';
|
||||
import {
|
||||
PARAMTYPES_METADATA,
|
||||
RESPONSE_PASSTHROUGH_METADATA,
|
||||
} from '@nestjs/common/constants';
|
||||
import {
|
||||
ContextType,
|
||||
Controller,
|
||||
@@ -38,6 +41,14 @@ export class ContextUtils {
|
||||
return Reflect.getMetadata(metadataKey, instance.constructor, methodName);
|
||||
}
|
||||
|
||||
public reflectPassthrough(instance: Controller, methodName: string): boolean {
|
||||
return Reflect.getMetadata(
|
||||
RESPONSE_PASSTHROUGH_METADATA,
|
||||
instance.constructor,
|
||||
methodName,
|
||||
);
|
||||
}
|
||||
|
||||
public getArgumentsLength<T>(keys: string[], metadata: T): number {
|
||||
return Math.max(...keys.map(key => metadata[key].index)) + 1;
|
||||
}
|
||||
|
||||
@@ -215,9 +215,10 @@ export class RouterExecutionContext {
|
||||
);
|
||||
|
||||
const paramsMetadata = getParamsMetadata(moduleKey);
|
||||
const isResponseHandled = paramsMetadata.some(
|
||||
({ type }) =>
|
||||
type === RouteParamtypes.RESPONSE || type === RouteParamtypes.NEXT,
|
||||
const isResponseHandled = this.isResponseHandled(
|
||||
instance,
|
||||
methodName,
|
||||
paramsMetadata,
|
||||
);
|
||||
|
||||
const httpRedirectResponse = this.reflectRedirect(callback);
|
||||
@@ -444,4 +445,20 @@ export class RouterExecutionContext {
|
||||
(await this.responseController.apply(result, res, httpStatusCode));
|
||||
};
|
||||
}
|
||||
|
||||
private isResponseHandled(
|
||||
instance: Controller,
|
||||
methodName: string,
|
||||
paramsMetadata: ParamProperties[],
|
||||
): boolean {
|
||||
const hasResponseOrNextDecorator = paramsMetadata.some(
|
||||
({ type }) =>
|
||||
type === RouteParamtypes.RESPONSE || type === RouteParamtypes.NEXT,
|
||||
);
|
||||
const isPassthroughEnabled = this.contextUtils.reflectPassthrough(
|
||||
instance,
|
||||
methodName,
|
||||
);
|
||||
return hasResponseOrNextDecorator && !isPassthroughEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,11 @@ import { map } from 'rxjs/operators';
|
||||
@Controller()
|
||||
export class AppController {
|
||||
@Get()
|
||||
index(@Res() response: Response) {
|
||||
index(@Res({ passthrough: true }) response: Response) {
|
||||
response
|
||||
.type('text/html')
|
||||
.send(readFileSync(join(__dirname, 'index.html')).toString());
|
||||
return 'xddd';
|
||||
}
|
||||
|
||||
@Sse('sse')
|
||||
|
||||
Reference in New Issue
Block a user