UNPKG

9.46 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const common_1 = require("@nestjs/common");
4const constants_1 = require("@nestjs/common/constants");
5const route_paramtypes_enum_1 = require("@nestjs/common/enums/route-paramtypes.enum");
6const shared_utils_1 = require("@nestjs/common/utils/shared.utils");
7const constants_2 = require("../guards/constants");
8const context_utils_1 = require("../helpers/context-utils");
9const handler_metadata_storage_1 = require("../helpers/handler-metadata-storage");
10const constants_3 = require("../injector/constants");
11const router_response_controller_1 = require("./router-response-controller");
12class RouterExecutionContext {
13 constructor(paramsFactory, pipesContextCreator, pipesConsumer, guardsContextCreator, guardsConsumer, interceptorsContextCreator, interceptorsConsumer, applicationRef) {
14 this.paramsFactory = paramsFactory;
15 this.pipesContextCreator = pipesContextCreator;
16 this.pipesConsumer = pipesConsumer;
17 this.guardsContextCreator = guardsContextCreator;
18 this.guardsConsumer = guardsConsumer;
19 this.interceptorsContextCreator = interceptorsContextCreator;
20 this.interceptorsConsumer = interceptorsConsumer;
21 this.applicationRef = applicationRef;
22 this.handlerMetadataStorage = new handler_metadata_storage_1.HandlerMetadataStorage();
23 this.contextUtils = new context_utils_1.ContextUtils();
24 this.responseController = new router_response_controller_1.RouterResponseController(applicationRef);
25 }
26 create(instance, callback, methodName, module, requestMethod, contextId = constants_3.STATIC_CONTEXT, inquirerId) {
27 const { argsLength, fnHandleResponse, paramtypes, getParamsMetadata, httpStatusCode, responseHeaders, hasCustomHeaders, } = this.getMetadata(instance, callback, methodName, module, requestMethod);
28 const paramsOptions = this.contextUtils.mergeParamsMetatypes(getParamsMetadata(module, contextId, inquirerId), paramtypes);
29 const contextType = 'http';
30 const pipes = this.pipesContextCreator.create(instance, callback, module, contextId, inquirerId);
31 const guards = this.guardsContextCreator.create(instance, callback, module, contextId, inquirerId);
32 const interceptors = this.interceptorsContextCreator.create(instance, callback, module, contextId, inquirerId);
33 const fnCanActivate = this.createGuardsFn(guards, instance, callback, contextType);
34 const fnApplyPipes = this.createPipesFn(pipes, paramsOptions);
35 const handler = (args, req, res, next) => async () => {
36 fnApplyPipes && (await fnApplyPipes(args, req, res, next));
37 return callback.apply(instance, args);
38 };
39 return async (req, res, next) => {
40 const args = this.contextUtils.createNullArray(argsLength);
41 fnCanActivate && (await fnCanActivate([req, res, next]));
42 this.responseController.setStatus(res, httpStatusCode);
43 hasCustomHeaders &&
44 this.responseController.setHeaders(res, responseHeaders);
45 const result = await this.interceptorsConsumer.intercept(interceptors, [req, res, next], instance, callback, handler(args, req, res, next), contextType);
46 await fnHandleResponse(result, res);
47 };
48 }
49 getMetadata(instance, callback, methodName, module, requestMethod) {
50 const cacheMetadata = this.handlerMetadataStorage.get(instance, methodName);
51 if (cacheMetadata) {
52 return cacheMetadata;
53 }
54 const metadata = this.contextUtils.reflectCallbackMetadata(instance, methodName, constants_1.ROUTE_ARGS_METADATA) || {};
55 const keys = Object.keys(metadata);
56 const argsLength = this.contextUtils.getArgumentsLength(keys, metadata);
57 const paramtypes = this.contextUtils.reflectCallbackParamtypes(instance, methodName);
58 const getParamsMetadata = (moduleKey, contextId = constants_3.STATIC_CONTEXT, inquirerId) => this.exchangeKeysForValues(keys, metadata, moduleKey, contextId, inquirerId);
59 const paramsMetadata = getParamsMetadata(module);
60 const isResponseHandled = paramsMetadata.some(({ type }) => type === route_paramtypes_enum_1.RouteParamtypes.RESPONSE || type === route_paramtypes_enum_1.RouteParamtypes.NEXT);
61 const httpRedirectResponse = this.reflectRedirect(callback);
62 const fnHandleResponse = this.createHandleResponseFn(callback, isResponseHandled, httpRedirectResponse);
63 const httpCode = this.reflectHttpStatusCode(callback);
64 const httpStatusCode = httpCode
65 ? httpCode
66 : this.responseController.getStatusByMethod(requestMethod);
67 const responseHeaders = this.reflectResponseHeaders(callback);
68 const hasCustomHeaders = !shared_utils_1.isEmpty(responseHeaders);
69 const handlerMetadata = {
70 argsLength,
71 fnHandleResponse,
72 paramtypes,
73 getParamsMetadata,
74 httpStatusCode,
75 hasCustomHeaders,
76 responseHeaders,
77 };
78 this.handlerMetadataStorage.set(instance, methodName, handlerMetadata);
79 return handlerMetadata;
80 }
81 reflectRedirect(callback) {
82 return Reflect.getMetadata(constants_1.REDIRECT_METADATA, callback);
83 }
84 reflectHttpStatusCode(callback) {
85 return Reflect.getMetadata(constants_1.HTTP_CODE_METADATA, callback);
86 }
87 reflectRenderTemplate(callback) {
88 return Reflect.getMetadata(constants_1.RENDER_METADATA, callback);
89 }
90 reflectResponseHeaders(callback) {
91 return Reflect.getMetadata(constants_1.HEADERS_METADATA, callback) || [];
92 }
93 exchangeKeysForValues(keys, metadata, moduleContext, contextId = constants_3.STATIC_CONTEXT, inquirerId) {
94 this.pipesContextCreator.setModuleContext(moduleContext);
95 return keys.map(key => {
96 const { index, data, pipes: pipesCollection } = metadata[key];
97 const pipes = this.pipesContextCreator.createConcreteContext(pipesCollection, contextId, inquirerId);
98 const type = this.contextUtils.mapParamType(key);
99 if (key.includes(constants_1.CUSTOM_ROUTE_AGRS_METADATA)) {
100 const { factory } = metadata[key];
101 const customExtractValue = this.getCustomFactory(factory, data);
102 return { index, extractValue: customExtractValue, type, data, pipes };
103 }
104 const numericType = Number(type);
105 const extractValue = (req, res, next) => this.paramsFactory.exchangeKeyForValue(numericType, data, {
106 req,
107 res,
108 next,
109 });
110 return { index, extractValue, type: numericType, data, pipes };
111 });
112 }
113 getCustomFactory(factory, data) {
114 return shared_utils_1.isFunction(factory)
115 ? (req, res, next) => factory(data, req)
116 : () => null;
117 }
118 async getParamValue(value, { metatype, type, data, }, pipes) {
119 if (!shared_utils_1.isEmpty(pipes)) {
120 return this.pipesConsumer.apply(value, { metatype, type, data }, pipes);
121 }
122 return value;
123 }
124 isPipeable(type) {
125 return (type === route_paramtypes_enum_1.RouteParamtypes.BODY ||
126 type === route_paramtypes_enum_1.RouteParamtypes.QUERY ||
127 type === route_paramtypes_enum_1.RouteParamtypes.PARAM ||
128 shared_utils_1.isString(type));
129 }
130 createGuardsFn(guards, instance, callback, contextType) {
131 const canActivateFn = async (args) => {
132 const canActivate = await this.guardsConsumer.tryActivate(guards, args, instance, callback, contextType);
133 if (!canActivate) {
134 throw new common_1.ForbiddenException(constants_2.FORBIDDEN_MESSAGE);
135 }
136 };
137 return guards.length ? canActivateFn : null;
138 }
139 createPipesFn(pipes, paramsOptions) {
140 const pipesFn = async (args, req, res, next) => {
141 const resolveParamValue = async (param) => {
142 const { index, extractValue, type, data, metatype, pipes: paramPipes, } = param;
143 const value = extractValue(req, res, next);
144 args[index] = this.isPipeable(type)
145 ? await this.getParamValue(value, { metatype, type, data }, pipes.concat(paramPipes))
146 : value;
147 };
148 await Promise.all(paramsOptions.map(resolveParamValue));
149 };
150 return paramsOptions.length ? pipesFn : null;
151 }
152 createHandleResponseFn(callback, isResponseHandled, redirectResponse, httpStatusCode) {
153 const renderTemplate = this.reflectRenderTemplate(callback);
154 if (renderTemplate) {
155 return async (result, res) => {
156 await this.responseController.render(result, res, renderTemplate);
157 };
158 }
159 if (redirectResponse && redirectResponse.url) {
160 return async (result, res) => {
161 await this.responseController.redirect(result, res, redirectResponse);
162 };
163 }
164 return async (result, res) => {
165 result = await this.responseController.transformToResult(result);
166 !isResponseHandled &&
167 (await this.responseController.apply(result, res, httpStatusCode));
168 };
169 }
170}
171exports.RouterExecutionContext = RouterExecutionContext;