Skip to content

Proposal: New loading controllers/interceptors/middlewares API #255

@MichalLytek

Description

@MichalLytek

Ref. #202 (comment)

Introduction

Right now, RoutingControllersOptions has following signatures for controllers/interceptors/middlewares -
Function[] | string[] - which allows to register in the framework list of classes or directories from where to import.

The array syntax is great because it let's you define the order of middlewares explicitly:

createExpressServer({
    middlewares: [
        MorganMiddleware,
        JwtMiddleware, 
        AuthMiddleware, 
        CompressionMiddleware, 
        LoggingMiddleware, 
        ErrorMiddleware,
    ],
});

So there's no need to jump through middlewares files and looking for priority option.

However, in big apps it might be not comfortable to list all of 58 controllers explicitly in array, so we have support for glob string and loading from directories:

createExpressServer({
    controllers: [__dirname + "/controllers/**/*.js"],
})

The cons are that you can't disable one middleware for dev/debug purpose and you have to use priority option in middleware decorator to declare the order of calling them which is very hard in maintaining.

In TypeScript and ES6 we can export and import from modules, so it's a common case to have index files. The directory structure looks like this:

middlewares
- auth-middleware.ts
- index.ts
- jwt-middleware.ts
- logging-middleware.ts
// etc.

And the index.ts file looks like this:

export * from "./jwt-middleware";
export * from "./auth-middleware";
export * from "./logging-middleware";

And in app.ts:

import * as middlewares from "./middlewares";

Because all object properties are traversed "in the order in which they were added to the object", we can use index.ts to manipulate the explicit order of middlewares. It doesn't have to be placed as index file, it might be placed in app configuration folder with modified paths.

Main proposal

Right now we can't pass object to routing-controllers option. So we need dirty hacks like:

createExpressServer(
    middlewares: Object.keys(middlewares).map(key => (<any>middlewares)[key]),
});

I propose to add support for objects containing middlewares/controllers/interceptors. We could then just do:

import * as middlewares from "./middlewares";
createExpressServer(
    middlewares: middlewares,
});

or with ES6 shorthand syntax:

import * as middlewares from "./middlewares";
import * as controllers from "./controllers";
import * as interceptors from "./interceptors";

createExpressServer({
    middlewares,
    controllers,
    interceptors,
});

Also I think that importing all from directories by glob string is an antipattern and this proposal reduce a lot of boilerplate of explicit array option. If users get used to this feature I would even deprecate loading from directories feature.

Adding @NoNameProvided @pleerock for discussion.

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: awaiting answerAwaiting answer from the author of issue or PR.type: discussionIssues discussing any topic.type: featureIssues related to new features.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions