Browse Source

feat(core): Allow middleware to execute before server.listen

gkielwasser 4 years ago
parent
commit
dd89204775

+ 6 - 10
packages/core/src/app.module.ts

@@ -1,7 +1,7 @@
 import { MiddlewareConsumer, Module, NestModule, OnApplicationShutdown } from '@nestjs/common';
-import { Type } from '@vendure/common/lib/shared-types';
 
 import { ApiModule } from './api/api.module';
+import { Middleware, MiddlewareHandler } from './common';
 import { ConfigModule } from './config/config.module';
 import { ConfigService } from './config/config.service';
 import { Logger } from './config/logger/vendure-logger';
@@ -12,9 +12,6 @@ import { PluginModule } from './plugin/plugin.module';
 import { ProcessContextModule } from './process-context/process-context.module';
 import { ServiceModule } from './service/service.module';
 
-// tslint:disable-next-line:ban-types
-type Middleware = Type<any> | Function;
-
 @Module({
     imports: [
         ProcessContextModule,
@@ -32,12 +29,13 @@ export class AppModule implements NestModule, OnApplicationShutdown {
     configure(consumer: MiddlewareConsumer) {
         const { adminApiPath, shopApiPath, middleware } = this.configService.apiOptions;
         const i18nextHandler = this.i18nService.handle();
-        const defaultMiddleware: Array<{ handler: Middleware; route?: string }> = [
+        const defaultMiddleware: Middleware[] = [
             { handler: i18nextHandler, route: adminApiPath },
             { handler: i18nextHandler, route: shopApiPath },
         ];
         const allMiddleware = defaultMiddleware.concat(middleware);
-        const middlewareByRoute = this.groupMiddlewareByRoute(allMiddleware);
+        const consumableMiddlewares = allMiddleware.filter(mid => !mid.beforeListen);
+        const middlewareByRoute = this.groupMiddlewareByRoute(consumableMiddlewares);
         for (const [route, handlers] of Object.entries(middlewareByRoute)) {
             consumer.apply(...handlers).forRoutes(route);
         }
@@ -52,10 +50,8 @@ export class AppModule implements NestModule, OnApplicationShutdown {
     /**
      * Groups middleware handlers together in an object with the route as the key.
      */
-    private groupMiddlewareByRoute(
-        middlewareArray: Array<{ handler: Middleware; route?: string }>,
-    ): { [route: string]: Middleware[] } {
-        const result = {} as { [route: string]: Middleware[] };
+    private groupMiddlewareByRoute(middlewareArray: Middleware[]): { [route: string]: MiddlewareHandler[] } {
+        const result = {} as { [route: string]: MiddlewareHandler[] };
         for (const middleware of middlewareArray) {
             const route = middleware.route || this.configService.apiOptions.adminApiPath;
             if (!result[route]) {

+ 5 - 1
packages/core/src/bootstrap.ts

@@ -47,7 +47,7 @@ export async function bootstrap(userConfig: Partial<VendureConfig>): Promise<INe
     // tslint:disable-next-line:whitespace
     const appModule = await import('./app.module');
     setProcessContext('server');
-    const { hostname, port, cors } = config.apiOptions;
+    const { hostname, port, cors, middleware } = config.apiOptions;
     DefaultLogger.hideNestBoostrapLogs();
     const app = await NestFactory.create(appModule.AppModule, {
         cors,
@@ -59,6 +59,10 @@ export async function bootstrap(userConfig: Partial<VendureConfig>): Promise<INe
         const { cookieOptions } = config.authOptions;
         app.use(cookieSession(cookieOptions));
     }
+    const earlyMiddlewares = middleware.filter(mid => mid.beforeListen);
+    earlyMiddlewares.forEach(mid => {
+        app.use(mid.route, mid.handler);
+    });
     await app.listen(port, hostname || '');
     app.enableShutdownHooks();
     logWelcomeMessage(config);

+ 7 - 0
packages/core/src/common/types/common-types.ts

@@ -1,3 +1,5 @@
+import { Type } from '@vendure/common/lib/shared-types';
+
 import { VendureEntity } from '../../entity/base/base.entity';
 import { Channel } from '../../entity/channel/channel.entity';
 import { Tag } from '../../entity/tag/tag.entity';
@@ -144,3 +146,8 @@ export type PriceCalculationResult = {
     price: number;
     priceIncludesTax: boolean;
 };
+
+// tslint:disable-next-line:ban-types
+export type MiddlewareHandler = Type<any> | Function;
+
+export type Middleware = { handler: MiddlewareHandler; route: string; beforeListen?: boolean };

+ 2 - 1
packages/core/src/config/vendure-config.ts

@@ -6,6 +6,7 @@ import { RequestHandler } from 'express';
 import { ValidationContext } from 'graphql';
 import { ConnectionOptions } from 'typeorm';
 
+import { Middleware } from '../common';
 import { PermissionDefinition } from '../common/permission-definition';
 
 import { AssetNamingStrategy } from './asset-naming-strategy/asset-naming-strategy';
@@ -163,7 +164,7 @@ export interface ApiOptions {
      * @default []
      */
     // tslint:disable-next-line:ban-types
-    middleware?: Array<{ handler: Type<any> | Function; route: string }>;
+    middleware?: Middleware[];
     /**
      * @description
      * Custom [ApolloServerPlugins](https://www.apollographql.com/docs/apollo-server/integrations/plugins/) which