Import A Nest.js App As A Simple Express Middleware
Solution 1:
While I don't condone the use of Nest as a middleware itself, it is possible. Using a basic set up from a nest new express-server -p npm
to create the new NestJS application, and setting up a small express server with src/server.ts
I was able to get the following code working.
app.middleware.ts
import { Injectable, NestMiddleware } from'@nestjs/common';
import { NestFactory } from'@nestjs/core';
import { ExpressAdapter } from'@nestjs/platform-express';
import { AppModule } from'./app.module';
const bootstrap = async (express: Express.Application) => {
const app = awaitNestFactory.create(AppModule, newExpressAdapter(express));
await app.init();
return app;
}
@Injectable()
exportclassAppMiddleware implements NestMiddleware {
constructor(private expressInstance: Express.Application) {}
use(req: any, res: any, next: () => void) {
console.log('In Nest middleware');
returnbootstrap(this.expressInstance);
}
}
app.controller.ts
import { Controller, Get } from'@nestjs/common';
import { AppService } from'./app.service';
@Controller()
exportclassAppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
returnthis.appService.getHello();
}
}
app.service.ts
import { Injectable } from'@nestjs/common';
@Injectable()
exportclassAppService {
getHello(): string {
return'Hello World!';
}
}
app.module.ts
import { Module } from'@nestjs/common';
import { AppController } from'./app.controller';
import { AppService } from'./app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
exportclassAppModule {}
server.ts
import * as express from'express';
import { AppMiddleware } from'./app.middleware';
const app = express();
app.use((req, res, next) => {
const nest = newAppMiddleware(app).use(req, res, next);
nest.then(() => {
next();
}).catch(err => {
console.log(JSON.stringify(err));
next();
});
});
app.listen(3000, () => {
console.log('Listening on port 3000');
});
Build command
npm run build
# mapped to nest build
Start command
node dist/server.js
Test command
▶ curl http://localhost:3000
Hello World!
Console Log
Listening on port 3000
In Nest middleware
[Nest] 24235 - 02/18/2020, 8:05:44 PM [NestFactory] Starting Nest application...
[Nest] 24235 - 02/18/2020, 8:05:44 PM [InstanceLoader] AppModule dependencies initialized +15ms
[Nest] 24235 - 02/18/2020, 8:05:44 PM [RoutesResolver] AppController {/}: +3ms
[Nest] 24235 - 02/18/2020, 8:05:44 PM [RouterExplorer] Mapped {/, GET} route +2ms
[Nest] 24235 - 02/18/2020, 8:05:44 PM [NestApplication] Nest application successfully started +2ms
Keep in mind a few things:
1) with this approach, unless you cache your Nest server, you will build a new Nest server on each request, which will only slow your project down more as you grow with the Nest side of things.
2) You could instead pass your existing express server to the ExpressAdapter
as you are partially doing in your existing code and start the server from the Nest app.listen()
function instead. Just make sure to remove any error handling middleware as it will start to conflict with how Nest handles responses. You should instead move those functions to ExceptionFilters.
3) One of the errors in your app.middleware
is that you are creating not only a new Nest instance on each call, but a new express instance too, which could really be confusing the node server.
4) The error that was coming in as [Object object]
in case you were wondering, was a standard Express error Cannot GET /
. Dunno why it was serialized strangely, but a JSON.stringify()
in the catch helped resolve it.
Overall, I would not recommend this approach but it is possible to do.
Solution 2:
I know it’s not exactly the answer to the question, but I’d just like to leave an example using this middleware.
For my context, I thought it was okay to put everything in the nest, instead of putting the nest in the express. I needed to put all my standard express application, working with the node, with no special conditions, just join the 2, this was my scenario.
I just took the global settings, like body-parser and dotenv and put it in my main file.
src/main.ts
import dotenv from'dotenv'import bodyParser from'body-parser'import { useExpress } from'./workspaces/poc/server'import { TodoModule } from'./workspaces/todo/todo.module'import { NestFactory } from'@nestjs/core';
// was in src/workspaces/my-legacy-app/server.ts
dotenv.config()
asyncfunctionbootstrap() {
const app = awaitNestFactory.create(TodoModule);
app.use(bodyParser.json());
// was in src/workspaces/my-legacy-app/server.ts// also did not know how to resolve the issue of types, so use "any"useExpress(app.getHttpAdapter() as any)
await app.listen(3000,() => {
console.info(`App runnning on port: ${3000}`)
});
}
bootstrap();
My old legacy main file
src/workspaces/legacy-app/server.ts
import { validatorMiddleware } from'./middlewares/validator.middleware'import { logMiddleware } from'./middlewares/log.middleware'import { userRouter } from'./routes/user.route'import { Express } from'express'exportfunctionuseExpress(server: Express){
server.use(validatorMiddleware)
server.use(logMiddleware)
server.use('/user', userRouter)
// commented because the server will go up here more, but just to show that it was the same way as in express// server.listen(// process.env.PORT,// () => console.log(`Server is running on port ${process.env.PORT ?? 3000}`)// )
}
Post a Comment for "Import A Nest.js App As A Simple Express Middleware"