eclipse-theia / theia

Eclipse Theia is a cloud & desktop IDE framework implemented in TypeScript.
http://theia-ide.org
Eclipse Public License 2.0
19.86k stars 2.48k forks source link

Cannot use express middleware in `BackendApplicationContribution.configure` #8931

Open bendavis78 opened 3 years ago

bendavis78 commented 3 years ago

The BackendApplicationContribution leads one to believe they can inject custom functionality into the express server. However:

import { injectable, inject } from 'inversify';
import { ILogger } from '@theia/core';
import { BackendApplicationContribution } from '@theia/core/lib/node';
import * as express from 'express';

@injectable()
export class TheiaCorsBackendApplicationContribution implements BackendApplicationContribution {
    @inject(ILogger) private readonly logger: ILogger;

    configure(app: express.Application): void {
        this.logger.info('Setting up Middleware');
        app.use((req: any, res: any, next: any) => {
            this.logger.info('Middleware activated');
            next();
        });
    }
}

The above example will not work. The middleware function never gets called.

debovema commented 2 years ago

Have you added something like that:

    bind(TheiaCorsBackendApplicationContribution).toSelf().inSingletonScope();
    bind(BackendApplicationContribution).toService(TheiaCorsBackendApplicationContribution);

in your backend module ?

I did and it seems to work.

Lythenas commented 1 year ago

I'm running into the same issue. Registering custom endpoints with app.get seems to work. But the app.use middleware is only called for /favicon.ico (presumably because the file does not exist).

I suspect the reason for this is that some other middleware that was registered earlier handles the requests and does not call next.

Is there a way to register a middleware before anything else is configured in the express.Application?

qianyiliushang commented 12 months ago

I'm running into the same issue. Registering custom endpoints with app.get seems to work. But the app.use middleware is only called for /favicon.ico (presumably because the file does not exist).

I suspect the reason for this is that some other middleware that was registered earlier handles the requests and does not call next.

Is there a way to register a middleware before anything else is configured in the express.Application?

I'm running into the same issue,too, any updates?

Lythenas commented 12 months ago

Sorry for not posting here sooner. I actually found a hacky solution a while back:

    configure(app: express.Application): MaybePromise<void> {
        const middleware = this.expressMiddleware.bind(this);
        app.use(middleware);

        // Hacky way to add our middleware at the beginning.
        // This might break if any of the other other BackendApplicationContributions
        // also do something like this.
        const routerStack = app._router.stack as any[];

        const layer = routerStack.splice(routerStack.findIndex(r => r.handler === middleware), 1);
        routerStack.splice(routerStack.findIndex(r => r.name === "expressInit") + 1, 0, ...layer);
    }

This basically puts my middleware after the "expressInit" middleware (which I picked more or less randomly from what worked).

I expect that this can easily break with theia updates.

qianyiliushang commented 12 months ago

Hi, I want to know what expressMiddleware is in your code snipt, is that a shortcut for app.use((req,res,next))? Thank you

Lythenas commented 11 months ago

Yes, it is just a normal middleware function. You could also specify an arrow function there. But my middleware was a bit too big as an arrow function for my taste.