File size: 6,608 Bytes
cfbbc1a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RoutesResolver = void 0;
const common_1 = require("@nestjs/common");
const constants_1 = require("@nestjs/common/constants");
const logger_service_1 = require("@nestjs/common/services/logger.service");
const messages_1 = require("../helpers/messages");
const metadata_scanner_1 = require("../metadata-scanner");
const route_path_factory_1 = require("./route-path-factory");
const router_exception_filters_1 = require("./router-exception-filters");
const router_explorer_1 = require("./router-explorer");
const router_proxy_1 = require("./router-proxy");
class RoutesResolver {
    constructor(container, applicationConfig, injector, graphInspector) {
        this.container = container;
        this.applicationConfig = applicationConfig;
        this.injector = injector;
        this.logger = new logger_service_1.Logger(RoutesResolver.name, {
            timestamp: true,
        });
        this.routerProxy = new router_proxy_1.RouterProxy();
        const httpAdapterRef = container.getHttpAdapterRef();
        this.routerExceptionsFilter = new router_exception_filters_1.RouterExceptionFilters(container, applicationConfig, httpAdapterRef);
        this.routePathFactory = new route_path_factory_1.RoutePathFactory(this.applicationConfig);
        const metadataScanner = new metadata_scanner_1.MetadataScanner();
        this.routerExplorer = new router_explorer_1.RouterExplorer(metadataScanner, this.container, this.injector, this.routerProxy, this.routerExceptionsFilter, this.applicationConfig, this.routePathFactory, graphInspector);
    }
    resolve(applicationRef, globalPrefix) {
        const modules = this.container.getModules();
        modules.forEach(({ controllers, metatype }, moduleName) => {
            const modulePath = this.getModulePathMetadata(metatype);
            this.registerRouters(controllers, moduleName, globalPrefix, modulePath, applicationRef);
        });
    }
    registerRouters(routes, moduleName, globalPrefix, modulePath, applicationRef) {
        routes.forEach(instanceWrapper => {
            const { metatype } = instanceWrapper;
            const host = this.getHostMetadata(metatype);
            const routerPaths = this.routerExplorer.extractRouterPath(metatype);
            const controllerVersion = this.getVersionMetadata(metatype);
            const controllerName = metatype.name;
            routerPaths.forEach(path => {
                const pathsToLog = this.routePathFactory.create({
                    ctrlPath: path,
                    modulePath,
                    globalPrefix,
                });
                if (!controllerVersion) {
                    pathsToLog.forEach(path => {
                        const logMessage = (0, messages_1.CONTROLLER_MAPPING_MESSAGE)(controllerName, path);
                        this.logger.log(logMessage);
                    });
                }
                else {
                    pathsToLog.forEach(path => {
                        const logMessage = (0, messages_1.VERSIONED_CONTROLLER_MAPPING_MESSAGE)(controllerName, path, controllerVersion);
                        this.logger.log(logMessage);
                    });
                }
                const versioningOptions = this.applicationConfig.getVersioning();
                const routePathMetadata = {
                    ctrlPath: path,
                    modulePath,
                    globalPrefix,
                    controllerVersion,
                    versioningOptions,
                };
                this.routerExplorer.explore(instanceWrapper, moduleName, applicationRef, host, routePathMetadata);
            });
        });
    }
    registerNotFoundHandler() {
        const applicationRef = this.container.getHttpAdapterRef();
        const callback = (req, res) => {
            const method = applicationRef.getRequestMethod(req);
            const url = applicationRef.getRequestUrl(req);
            throw new common_1.NotFoundException(`Cannot ${method} ${url}`);
        };
        const handler = this.routerExceptionsFilter.create({}, callback, undefined);
        const proxy = this.routerProxy.createProxy(callback, handler);
        applicationRef.setNotFoundHandler &&
            applicationRef.setNotFoundHandler(proxy, this.applicationConfig.getGlobalPrefix());
    }
    registerExceptionHandler() {
        const callback = (err, req, res, next) => {
            throw this.mapExternalException(err);
        };
        const handler = this.routerExceptionsFilter.create({}, callback, undefined);
        const proxy = this.routerProxy.createExceptionLayerProxy(callback, handler);
        const applicationRef = this.container.getHttpAdapterRef();
        applicationRef.setErrorHandler &&
            applicationRef.setErrorHandler(proxy, this.applicationConfig.getGlobalPrefix());
    }
    mapExternalException(err) {
        switch (true) {
            // SyntaxError is thrown by Express body-parser when given invalid JSON (#422, #430)
            // URIError is thrown by Express when given a path parameter with an invalid percentage
            // encoding, e.g. '%FF' (#8915)
            case err instanceof SyntaxError || err instanceof URIError:
                return new common_1.BadRequestException(err.message);
            case this.isHttpFastifyError(err):
                return new common_1.HttpException(err.message, err.statusCode);
            default:
                return err;
        }
    }
    isHttpFastifyError(error) {
        // condition based on this code - https://github.com/fastify/fastify-error/blob/d669b150a82968322f9f7be992b2f6b463272de3/index.js#L22
        return (error.statusCode !== undefined &&
            error instanceof Error &&
            error.name === 'FastifyError');
    }
    getModulePathMetadata(metatype) {
        const modulesContainer = this.container.getModules();
        const modulePath = Reflect.getMetadata(constants_1.MODULE_PATH + modulesContainer.applicationId, metatype);
        return modulePath ?? Reflect.getMetadata(constants_1.MODULE_PATH, metatype);
    }
    getHostMetadata(metatype) {
        return Reflect.getMetadata(constants_1.HOST_METADATA, metatype);
    }
    getVersionMetadata(metatype) {
        const versioningConfig = this.applicationConfig.getVersioning();
        if (versioningConfig) {
            return (Reflect.getMetadata(constants_1.VERSION_METADATA, metatype) ??
                versioningConfig.defaultVersion);
        }
    }
}
exports.RoutesResolver = RoutesResolver;