Skip to content

Commit ebe8e72

Browse files
authored
feat(stripe): add ability to use custom decorators on controller
* feat: add ability to use custom decorators on StripeWebhookController * test: add a test for the decorator metadata to ensure it is set
1 parent ad7cd39 commit ebe8e72

4 files changed

Lines changed: 46 additions & 2 deletions

File tree

packages/stripe/README.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ Failure to give Stripe access to the raw body will result in nasty runtime error
107107

108108
### Decorate Methods For Processing Webhook Events
109109

110-
Exposing provider/service methods to be used for processing Stripe events is easy! Simply use the provided decorator and indiciate the event type that the handler should receive.
110+
Exposing provider/service methods to be used for processing Stripe events is easy! Simply use the provided decorator and indicate the event type that the handler should receive.
111111

112112
[Review the Stripe documentation](https://stripe.com/docs/api/events/types) for more information about the types of events available.
113113

@@ -121,6 +121,20 @@ class PaymentCreatedService {
121121
}
122122
```
123123

124+
### Webhook Controller Decorators
125+
126+
You can also pass any class decorator to the `decorators` property of the `webhookConfig` object as a part of the module configuration. This could be used in situations like when using the `@nestjs/throttler` package and needing to apply the `@ThrottlerSkip()` decorator, or when you have a global guard but need to skip routes with certain metadata.
127+
128+
````typescript
129+
StripeModule.forRoot(StripeModule, {
130+
apiKey: '123',
131+
webhookConfig: {
132+
stripeWebhookSecret: 'super-secret',
133+
decorators: [ThrottlerSkip()],
134+
},
135+
}),
136+
```
137+
124138
### Configure Webhooks in the Stripe Dashboard
125139

126140
Follow the instructions from the [Stripe Documentation](https://stripe.com/docs/webhooks) for remaining integration steps such as testing your integration with the CLI before you go live and properly configuring the endpoint from the Stripe dashboard so that the correct events are sent to your NestJS app.
@@ -132,3 +146,4 @@ Contributions welcome! Read the [contribution guidelines](../../CONTRIBUTING.md)
132146
## License
133147

134148
[MIT License](../../LICENSE)
149+
````

packages/stripe/src/stripe.interfaces.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ export interface StripeModuleConfig extends Partial<Stripe.StripeConfig> {
2222
*/
2323
controllerPrefix?: string;
2424

25+
/**
26+
* Any metadata specific decorators you want to apply to the webhook handling controller.
27+
*
28+
* Note: these decorators must only set metadata that will be read at request time. Decorators like Nest's `@UsePipes()` or `@UseInterceptors()` wll not work, due to the time at which Nest reads the metadata for those, but something that uses `SetMetadata` will be fine, because that metadata is read at request time.
29+
*/
30+
decorators?: ClassDecorator[];
31+
2532
/**
2633
* Logging configuration
2734
*/

packages/stripe/src/stripe.module.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ export class StripeModule
3737
controllerPrefix,
3838
StripeWebhookController
3939
);
40+
config.webhookConfig?.decorators?.forEach((deco) => {
41+
deco(StripeWebhookController);
42+
});
4043
},
4144
inject: [STRIPE_MODULE_CONFIG_TOKEN],
4245
},

packages/stripe/src/tests/stripe.module.spec.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
import { INestApplication, Injectable } from '@nestjs/common';
1+
import { INestApplication, Injectable, SetMetadata } from '@nestjs/common';
22
import { Test, TestingModule } from '@nestjs/testing';
33
import Stripe from 'stripe';
44
import { InjectStripeClient } from '../stripe.decorators';
5+
import { StripeWebhookController } from '../stripe.webhook.controller';
56
import { StripeModule } from './../stripe.module';
67

78
const testReceiveStripeFn = jest.fn();
89

10+
const TestDecorator = () => SetMetadata('TEST:METADATA', 'metadata');
11+
912
@Injectable()
1013
class TestService {
1114
constructor(@InjectStripeClient() private readonly stripeClient: Stripe) {
@@ -36,4 +39,20 @@ describe('Stripe Module', () => {
3639
const client = testReceiveStripeFn.mock.calls[0][0];
3740
expect(client).toBeInstanceOf(Stripe);
3841
});
42+
it('should apply the decorator to the controller', async () => {
43+
await Test.createTestingModule({
44+
imports: [
45+
StripeModule.forRoot(StripeModule, {
46+
apiKey: '123',
47+
webhookConfig: {
48+
stripeWebhookSecret: 'super-secret',
49+
decorators: [TestDecorator()],
50+
},
51+
}),
52+
],
53+
}).compile();
54+
expect(Reflect.getMetadata('TEST:METADATA', StripeWebhookController)).toBe(
55+
'metadata'
56+
);
57+
});
3958
});

0 commit comments

Comments
 (0)