Skip to content

Commit 26e9ed6

Browse files
feat(microservices): add extras param to pattern decorators
Add optional "extras" parameter for MessagePattern and EventPattern decorators. Allow embedding extra params into each message handler method and improve an experience of creating custom microservice transports
1 parent b01afec commit 26e9ed6

11 files changed

Lines changed: 96 additions & 42 deletions

packages/microservices/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export const SUBSCRIBE = 'subscribe';
2020
export const CANCEL_EVENT = 'cancelled';
2121

2222
export const PATTERN_METADATA = 'microservices:pattern';
23+
export const PATTERN_EXTRAS_METADATA = 'microservices:pattern_extras';
2324
export const TRANSPORT_METADATA = 'microservices:transport';
2425
export const CLIENT_CONFIGURATION_METADATA = 'microservices:client';
2526
export const PATTERN_HANDLER_METADATA = 'microservices:handler_type';

packages/microservices/decorators/event-pattern.decorator.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
PATTERN_HANDLER_METADATA,
33
PATTERN_METADATA,
44
TRANSPORT_METADATA,
5+
PATTERN_EXTRAS_METADATA,
56
} from '../constants';
67
import { PatternHandler } from '../enums/pattern-handler.enum';
78
import { Transport } from '../enums';
@@ -12,6 +13,7 @@ import { Transport } from '../enums';
1213
export const EventPattern = <T = string>(
1314
metadata?: T,
1415
transport?: Transport,
16+
extras?: Record<string, any>,
1517
): MethodDecorator => {
1618
return (
1719
target: object,
@@ -25,6 +27,7 @@ export const EventPattern = <T = string>(
2527
descriptor.value,
2628
);
2729
Reflect.defineMetadata(TRANSPORT_METADATA, transport, descriptor.value);
30+
Reflect.defineMetadata(PATTERN_EXTRAS_METADATA, extras, descriptor.value);
2831
return descriptor;
2932
};
3033
};

packages/microservices/decorators/message-pattern.decorator.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
PATTERN_HANDLER_METADATA,
44
PATTERN_METADATA,
55
TRANSPORT_METADATA,
6+
PATTERN_EXTRAS_METADATA,
67
} from '../constants';
78
import { PatternHandler } from '../enums/pattern-handler.enum';
89
import { PatternMetadata } from '../interfaces/pattern-metadata.interface';
@@ -20,6 +21,7 @@ export enum GrpcMethodStreamingType {
2021
export const MessagePattern = <T = PatternMetadata | string>(
2122
metadata?: T,
2223
transport?: Transport,
24+
extras?: Record<string, any>,
2325
): MethodDecorator => {
2426
return (
2527
target: object,
@@ -33,6 +35,7 @@ export const MessagePattern = <T = PatternMetadata | string>(
3335
descriptor.value,
3436
);
3537
Reflect.defineMetadata(TRANSPORT_METADATA, transport, descriptor.value);
38+
Reflect.defineMetadata(PATTERN_EXTRAS_METADATA, extras, descriptor.value);
3639
return descriptor;
3740
};
3841
};

packages/microservices/interfaces/message-handler.interface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ export interface MessageHandler<TInput = any, TContext = any, TResult = any> {
44
(data: TInput, ctx?: TContext): Promise<Observable<TResult>>;
55
next?: (data: TInput, ctx?: TContext) => Promise<Observable<TResult>>;
66
isEventHandler?: boolean;
7+
extras?: Record<string, any>;
78
}

packages/microservices/listener-metadata-explorer.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
PATTERN_HANDLER_METADATA,
88
PATTERN_METADATA,
99
TRANSPORT_METADATA,
10+
PATTERN_EXTRAS_METADATA,
1011
} from './constants';
1112
import { Transport } from './enums';
1213
import { PatternHandler } from './enums/pattern-handler.enum';
@@ -24,6 +25,7 @@ export interface EventOrMessageListenerDefinition {
2425
isEventHandler: boolean;
2526
targetCallback: (...args: any[]) => any;
2627
transport?: Transport;
28+
extras?: Record<string, any>;
2729
}
2830

2931
export interface MessageRequestProperties {
@@ -58,11 +60,13 @@ export class ListenerMetadataExplorer {
5860
}
5961
const pattern = Reflect.getMetadata(PATTERN_METADATA, targetCallback);
6062
const transport = Reflect.getMetadata(TRANSPORT_METADATA, targetCallback);
63+
const extras = Reflect.getMetadata(PATTERN_EXTRAS_METADATA, targetCallback);
6164
return {
6265
methodKey,
6366
targetCallback,
6467
pattern,
6568
transport,
69+
extras,
6670
isEventHandler: handlerType === PatternHandler.EVENT,
6771
};
6872
}

packages/microservices/listeners-controller.ts

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -71,48 +71,55 @@ export class ListenersController {
7171
isUndefined(server.transportId) ||
7272
transport === server.transportId,
7373
)
74-
.forEach(({ pattern, targetCallback, methodKey, isEventHandler }) => {
75-
if (isStatic) {
76-
const proxy = this.contextCreator.create(
77-
instance as object,
78-
targetCallback,
74+
.forEach(
75+
({ pattern, targetCallback, methodKey, extras, isEventHandler }) => {
76+
if (isStatic) {
77+
const proxy = this.contextCreator.create(
78+
instance as object,
79+
targetCallback,
80+
moduleKey,
81+
methodKey,
82+
STATIC_CONTEXT,
83+
undefined,
84+
defaultCallMetadata,
85+
);
86+
if (isEventHandler) {
87+
const eventHandler: MessageHandler = (...args: unknown[]) => {
88+
const originalArgs = args;
89+
const [dataOrContextHost] = originalArgs;
90+
if (dataOrContextHost instanceof RequestContextHost) {
91+
args = args.slice(1, args.length);
92+
}
93+
const originalReturnValue = proxy(...args);
94+
const returnedValueWrapper = eventHandler.next?.(
95+
...(originalArgs as Parameters<MessageHandler>),
96+
);
97+
returnedValueWrapper?.then(returnedValue =>
98+
this.connectIfStream(returnedValue as Observable<unknown>),
99+
);
100+
return originalReturnValue;
101+
};
102+
return server.addHandler(
103+
pattern,
104+
eventHandler,
105+
isEventHandler,
106+
extras,
107+
);
108+
} else {
109+
return server.addHandler(pattern, proxy, isEventHandler, extras);
110+
}
111+
}
112+
const asyncHandler = this.createRequestScopedHandler(
113+
instanceWrapper,
114+
pattern,
115+
moduleRef,
79116
moduleKey,
80117
methodKey,
81-
STATIC_CONTEXT,
82-
undefined,
83118
defaultCallMetadata,
84119
);
85-
if (isEventHandler) {
86-
const eventHandler: MessageHandler = (...args: unknown[]) => {
87-
const originalArgs = args;
88-
const [dataOrContextHost] = originalArgs;
89-
if (dataOrContextHost instanceof RequestContextHost) {
90-
args = args.slice(1, args.length);
91-
}
92-
const originalReturnValue = proxy(...args);
93-
const returnedValueWrapper = eventHandler.next?.(
94-
...(originalArgs as Parameters<MessageHandler>),
95-
);
96-
returnedValueWrapper?.then(returnedValue =>
97-
this.connectIfStream(returnedValue as Observable<unknown>),
98-
);
99-
return originalReturnValue;
100-
};
101-
return server.addHandler(pattern, eventHandler, isEventHandler);
102-
} else {
103-
return server.addHandler(pattern, proxy, isEventHandler);
104-
}
105-
}
106-
const asyncHandler = this.createRequestScopedHandler(
107-
instanceWrapper,
108-
pattern,
109-
moduleRef,
110-
moduleKey,
111-
methodKey,
112-
defaultCallMetadata,
113-
);
114-
server.addHandler(pattern, asyncHandler, isEventHandler);
115-
});
120+
server.addHandler(pattern, asyncHandler, isEventHandler, extras);
121+
},
122+
);
116123
}
117124

118125
public assignClientsToProperties(instance: Controller | Injectable) {

packages/microservices/server/server.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,11 @@ export abstract class Server {
4444
pattern: any,
4545
callback: MessageHandler,
4646
isEventHandler = false,
47+
extras: Record<string, any> = {},
4748
) {
4849
const normalizedPattern = this.normalizePattern(pattern);
4950
callback.isEventHandler = isEventHandler;
51+
callback.extras = extras;
5052

5153
if (this.messageHandlers.has(normalizedPattern) && isEventHandler) {
5254
const headRef = this.messageHandlers.get(normalizedPattern);
Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
import { expect } from 'chai';
2-
import { PATTERN_METADATA } from '../../constants';
2+
import { PATTERN_METADATA, PATTERN_EXTRAS_METADATA } from '../../constants';
33
import { EventPattern } from '../../decorators/event-pattern.decorator';
44

55
describe('@EventPattern', () => {
66
const pattern = { role: 'test' };
7+
const extras = { param: 'value' };
78
class TestComponent {
8-
@EventPattern(pattern)
9+
@EventPattern(pattern, undefined, extras)
910
public static test() {}
1011
}
1112
it(`should enhance method with ${PATTERN_METADATA} metadata`, () => {
1213
const metadata = Reflect.getMetadata(PATTERN_METADATA, TestComponent.test);
1314
expect(metadata).to.be.eql(pattern);
1415
});
16+
it(`should enhance method with ${PATTERN_EXTRAS_METADATA} metadata`, () => {
17+
const metadata = Reflect.getMetadata(
18+
PATTERN_EXTRAS_METADATA,
19+
TestComponent.test,
20+
);
21+
expect(metadata).to.be.deep.equal(extras);
22+
});
1523
});

packages/microservices/test/decorators/message-pattern.decorator.spec.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { expect } from 'chai';
2-
import { PATTERN_METADATA } from '../../constants';
2+
import { PATTERN_METADATA, PATTERN_EXTRAS_METADATA } from '../../constants';
33
import {
44
GrpcMethod,
55
GrpcMethodStreamingType,
@@ -10,14 +10,22 @@ import {
1010

1111
describe('@MessagePattern', () => {
1212
const pattern = { role: 'test' };
13+
const extras = { param: 'value' };
1314
class TestComponent {
14-
@MessagePattern(pattern)
15+
@MessagePattern(pattern, undefined, extras)
1516
public static test() {}
1617
}
1718
it(`should enhance method with ${PATTERN_METADATA} metadata`, () => {
1819
const metadata = Reflect.getMetadata(PATTERN_METADATA, TestComponent.test);
1920
expect(metadata).to.be.eql(pattern);
2021
});
22+
it(`should enhance method with ${PATTERN_EXTRAS_METADATA} metadata`, () => {
23+
const metadata = Reflect.getMetadata(
24+
PATTERN_EXTRAS_METADATA,
25+
TestComponent.test,
26+
);
27+
expect(metadata).to.be.deep.equal(extras);
28+
});
2129
});
2230

2331
describe('@GrpcMethod', () => {

packages/microservices/test/listeners-controller.spec.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,22 @@ describe('ListenersController', () => {
118118
instance.registerPatternHandlers(new InstanceWrapper(), serverTCP, '');
119119
expect(addSpyTCP.calledTwice).to.be.true;
120120
});
121+
it(`should call "addHandler" method of server with extras data`, () => {
122+
const serverHandlers = [
123+
{ pattern: 'test', targetCallback: 'tt', extras: { param: 'value' } },
124+
];
125+
explorer.expects('explore').returns(serverHandlers);
126+
instance.registerPatternHandlers(new InstanceWrapper(), serverTCP, '');
127+
expect(addSpyTCP.calledOnce).to.be.true;
128+
expect(
129+
addSpyTCP.calledWith(
130+
sinon.match.any,
131+
sinon.match.any,
132+
sinon.match.any,
133+
sinon.match({ param: 'value' }),
134+
),
135+
).to.be.true;
136+
});
121137
describe('when request scoped', () => {
122138
it(`should call "addHandler" with deferred proxy`, () => {
123139
explorer.expects('explore').returns(handlers);

0 commit comments

Comments
 (0)