diff --git a/docs/webhook.md b/docs/webhook.md index 984919fa..038940e0 100644 --- a/docs/webhook.md +++ b/docs/webhook.md @@ -20,6 +20,7 @@ constructs: authorizer: handler: myAuthorizer.main path: /my-webhook-endpoint + method: POST plugins: - serverless-lift @@ -162,6 +163,23 @@ constructs: Always favor dynamic path selector to ensure the minimum amount of compute is executed downstream. The list of available dynamic selector is available in [API Gateway documentation](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-aws-services.html#http-api-develop-integrations-aws-services-parameter-mapping). +### Method + +_Optional_ +Defaults to `POST` + +This is the HTTP method the webhook will accept. It can be any of the following: +- `POST` +- `PUT` +- `PATCH` + +```yaml +constructs: + stripe: + # ... + method: POST +``` + ## Extensions You can specify an `extensions` property on the webhook construct to extend the underlying CloudFormation resources. In the exemple below, the EventBridge Bus CloudFormation resource generated by the `stripe` webhook construct will be extended with the new `Name: StripeBus` CloudFormation property. diff --git a/src/constructs/aws/Webhook.ts b/src/constructs/aws/Webhook.ts index 3e0c2f20..4759f2c8 100644 --- a/src/constructs/aws/Webhook.ts +++ b/src/constructs/aws/Webhook.ts @@ -28,12 +28,14 @@ const WEBHOOK_DEFINITION = { insecure: { type: "boolean" }, path: { type: "string" }, eventType: { type: "string" }, + method: { enum: ["POST", "PUT", "PATCH"] }, }, required: ["path"], additionalProperties: false, } as const; const WEBHOOK_DEFAULTS = { insecure: false, + method: "POST", }; type Configuration = FromSchema; @@ -46,6 +48,7 @@ export class Webhook extends AwsConstruct { private readonly bus: EventBus; private readonly apiEndpointOutput: CfnOutput; private readonly endpointPathOutput: CfnOutput; + private readonly method: string; constructor( scope: CdkConstruct, @@ -108,9 +111,10 @@ export class Webhook extends AwsConstruct { EventBusName: this.bus.eventBusName, }, }); + this.method = resolvedConfiguration.method; const route = new CfnRoute(this, "Route", { apiId: this.api.apiId, - routeKey: `POST ${resolvedConfiguration.path}`, + routeKey: `${this.method} ${resolvedConfiguration.path}`, target: Fn.join("/", ["integrations", eventBridgeIntegration.ref]), authorizationType: "NONE", }); diff --git a/test/fixtures/webhooks/serverless.yml b/test/fixtures/webhooks/serverless.yml index f585d0e9..cbd4b72f 100644 --- a/test/fixtures/webhooks/serverless.yml +++ b/test/fixtures/webhooks/serverless.yml @@ -24,3 +24,21 @@ constructs: bus: Properties: Name: myBus + post: + type: webhook + authorizer: + handler: authorizer.main + path: /post + method: POST + put: + type: webhook + authorizer: + handler: authorizer.main + path: /put + method: PUT + patch: + type: webhook + authorizer: + handler: authorizer.main + path: /patch + method: PATCH diff --git a/test/unit/webhooks.test.ts b/test/unit/webhooks.test.ts index aefc140f..2e357d44 100644 --- a/test/unit/webhooks.test.ts +++ b/test/unit/webhooks.test.ts @@ -21,6 +21,16 @@ describe("webhooks", () => { }); }); + test.each([ + ["post", "POST"], + ["put", "PUT"], + ["patch", "PATCH"], + ])("%p webhook should have method %p", (useCase, expectedMethod) => { + expect(cfTemplate.Resources[computeLogicalId(useCase, "Route")]["Properties"]).toMatchObject({ + RouteKey: expectedMethod + " /" + expectedMethod.toLowerCase(), + }); + }); + it("allows overriding webhook properties", () => { expect(cfTemplate.Resources[computeLogicalId("extendedWebhook", "Bus")].Properties).toMatchObject({ Name: "myBus",