diff --git a/packages/microservices/interfaces/message-handler.interface.ts b/packages/microservices/interfaces/message-handler.interface.ts index aa201e93262..5215e81ba87 100644 --- a/packages/microservices/interfaces/message-handler.interface.ts +++ b/packages/microservices/interfaces/message-handler.interface.ts @@ -4,3 +4,8 @@ export interface MessageHandler { (data: TInput, ctx?: TContext): Promise>; isEventHandler?: boolean; } + +export interface RegExpMessageHandler { + pattern: RegExp; + messageHandler: MessageHandler; +} diff --git a/packages/microservices/server/server-kafka.ts b/packages/microservices/server/server-kafka.ts index 02f2d7d5d1f..b8602edf13e 100644 --- a/packages/microservices/server/server-kafka.ts +++ b/packages/microservices/server/server-kafka.ts @@ -98,8 +98,11 @@ export class ServerKafka extends Server implements CustomTransportStrategy { } public async bindEvents(consumer: Consumer) { - const registeredPatterns = [...this.messageHandlers.keys()]; - const subscribeToPattern = async (pattern: string) => + const registeredPatterns = [ + ...this.messageHandlers.keys(), + ...this.regExpMessageHandlers.map(handler => handler.pattern), + ]; + const subscribeToPattern = async (pattern: string | RegExp) => consumer.subscribe({ topic: pattern, }); diff --git a/packages/microservices/server/server.ts b/packages/microservices/server/server.ts index 13d6830c720..4f2d453a3f6 100644 --- a/packages/microservices/server/server.ts +++ b/packages/microservices/server/server.ts @@ -22,6 +22,7 @@ import { NatsOptions, ReadPacket, RedisOptions, + RegExpMessageHandler, RmqOptions, TcpOptions, WritePacket, @@ -34,6 +35,7 @@ import { NO_EVENT_HANDLER } from '../constants'; export abstract class Server { protected readonly messageHandlers = new Map(); + protected readonly regExpMessageHandlers = new Array(); protected readonly logger = new Logger(Server.name); protected serializer: ConsumerSerializer; protected deserializer: ConsumerDeserializer; @@ -43,9 +45,13 @@ export abstract class Server { callback: MessageHandler, isEventHandler = false, ) { - const route = transformPatternToRoute(pattern); - callback.isEventHandler = isEventHandler; - this.messageHandlers.set(route, callback); + if (pattern.constructor.name === 'RegExp') { + this.regExpMessageHandlers.push({ pattern, messageHandler: callback }); + } else { + const route = transformPatternToRoute(pattern); + callback.isEventHandler = isEventHandler; + this.messageHandlers.set(route, callback); + } } public getHandlers(): Map { @@ -54,9 +60,20 @@ export abstract class Server { public getHandlerByPattern(pattern: string): MessageHandler | null { const route = this.getRouteFromPattern(pattern); - return this.messageHandlers.has(route) - ? this.messageHandlers.get(route) - : null; + let handler = null; + // Try to find the message handler by name + if (this.messageHandlers.has(route)) { + return this.messageHandlers.get(route); + } + + // If it was not found, iterate through the Regular Expression handlers + this.regExpMessageHandlers.forEach(regExpHandler => { + if (regExpHandler.pattern.exec(route) !== null) { + handler = regExpHandler.messageHandler; + } + }); + + return handler; } public send( diff --git a/packages/microservices/test/server/server.spec.ts b/packages/microservices/test/server/server.spec.ts index dfb7cc3a886..4516e69fd4d 100644 --- a/packages/microservices/test/server/server.spec.ts +++ b/packages/microservices/test/server/server.spec.ts @@ -3,6 +3,7 @@ import { Observable, of, throwError as _throw } from 'rxjs'; import * as sinon from 'sinon'; import { Server } from '../../server/server'; import * as Utils from '../../utils'; +import { RegExpMessageHandler } from '../../interfaces'; class TestServer extends Server { public listen(callback: () => void) {} @@ -197,6 +198,27 @@ describe('Server', () => { }); }); + describe('when handler exists and was added with a RegExp', () => { + beforeEach(() => { + sandbox.stub(server as any, 'regExpMessageHandlers').value([ + ({ + pattern: /.*el.*/, + messageHandler: callback, + } as unknown) as RegExpMessageHandler, + ]); + }); + + it('should return expected handler', () => { + messageHandlersHasSpy.returns(false); + + const value = server.getHandlerByPattern(handlerRoute); + + expect(messageHandlersHasSpy.called).to.be.true; + expect(messageHandlersGetSpy.called).to.be.false; + expect(value).to.be.equal(callback); + }); + }); + describe('when handler does not exists', () => { it('should return null', () => { messageHandlersHasSpy.returns(false);