* return 200 asap to paddle and queue webhook received

* paddle ids to int
This commit is contained in:
m5r
2021-10-01 23:04:12 +02:00
parent 188c028667
commit 771fea4d7b
15 changed files with 370 additions and 496 deletions

View File

@ -1,47 +1,39 @@
import type { BlitzApiHandler, BlitzApiRequest, BlitzApiResponse } from "blitz";
import { getConfig } from "blitz";
import { PaddleSdk, stringifyMetadata } from "@devoxa/paddle-sdk";
import type { BlitzApiHandler } from "blitz";
import type { Queue } from "quirrel/blitz";
import type {
PaddleSdkSubscriptionCancelledEvent,
PaddleSdkSubscriptionCreatedEvent,
PaddleSdkSubscriptionPaymentSucceededEvent,
PaddleSdkSubscriptionUpdatedEvent,
} from "@devoxa/paddle-sdk";
import { PaddleSdkWebhookEventType } from "@devoxa/paddle-sdk";
import type { ApiError } from "../../../core/types";
import { subscriptionCreatedHandler } from "../../webhook-handlers/subscription-created";
import { subscriptionPaymentSucceededHandler } from "../../webhook-handlers/subscription-payment-succeeded";
import { subscriptionCancelled } from "../../webhook-handlers/subscription-cancelled";
import { subscriptionUpdated } from "../../webhook-handlers/subscription-updated";
import appLogger from "../../../../integrations/logger";
import type { ApiError } from "app/core/types";
import subscriptionCreatedQueue from "../queue/subscription-created";
import subscriptionPaymentSucceededQueue from "../queue/subscription-payment-succeeded";
import subscriptionCancelledQueue from "../queue/subscription-cancelled";
import subscriptionUpdatedQueue from "../queue/subscription-updated";
import appLogger from "integrations/logger";
import { paddleSdk } from "integrations/paddle";
type SupportedWebhook =
| "subscription_created"
| "subscription_cancelled"
| "subscription_payment_succeeded"
| "subscription_updated";
const supportedWebhooks: SupportedWebhook[] = [
"subscription_created",
"subscription_cancelled",
"subscription_payment_succeeded",
"subscription_updated",
];
type Events<TMetadata = { organizationId: string }> =
| PaddleSdkSubscriptionCreatedEvent<TMetadata>
| PaddleSdkSubscriptionUpdatedEvent<TMetadata>
| PaddleSdkSubscriptionCancelledEvent<TMetadata>
| PaddleSdkSubscriptionPaymentSucceededEvent<TMetadata>;
const handlers: Record<SupportedWebhook, BlitzApiHandler> = {
subscription_created: subscriptionCreatedHandler,
subscription_payment_succeeded: subscriptionPaymentSucceededHandler,
subscription_cancelled: subscriptionCancelled,
subscription_updated: subscriptionUpdated,
type SupportedEventType = Events["eventType"];
const queues: Record<SupportedEventType, Queue<{ event: Events }>> = {
[PaddleSdkWebhookEventType.SUBSCRIPTION_CREATED]: subscriptionCreatedQueue,
[PaddleSdkWebhookEventType.SUBSCRIPTION_PAYMENT_SUCCEEDED]: subscriptionPaymentSucceededQueue,
[PaddleSdkWebhookEventType.SUBSCRIPTION_CANCELLED]: subscriptionCancelledQueue,
[PaddleSdkWebhookEventType.SUBSCRIPTION_UPDATED]: subscriptionUpdatedQueue,
};
function isSupportedWebhook(webhook: any): webhook is SupportedWebhook {
return supportedWebhooks.includes(webhook);
}
const logger = appLogger.child({ route: "/api/subscription/webhook" });
const { publicRuntimeConfig, serverRuntimeConfig } = getConfig();
const paddleSdk = new PaddleSdk({
publicKey: serverRuntimeConfig.paddle.publicKey,
vendorId: publicRuntimeConfig.paddle.vendorId,
vendorAuthCode: serverRuntimeConfig.paddle.apiKey,
metadataCodec: stringifyMetadata(),
});
export default async function webhook(req: BlitzApiRequest, res: BlitzApiResponse) {
const webhook: BlitzApiHandler = async (req, res) => {
if (req.method !== "POST") {
const statusCode = 405;
const apiError: ApiError = {
@ -55,23 +47,21 @@ export default async function webhook(req: BlitzApiRequest, res: BlitzApiRespons
return;
}
if (!paddleSdk.verifyWebhookEvent(req.body)) {
const statusCode = 500;
const apiError: ApiError = {
statusCode,
errorMessage: "Webhook event is invalid",
};
logger.error(apiError);
return res.status(statusCode).send(apiError);
}
const alertName = req.body.alert_name;
const event = paddleSdk.parseWebhookEvent(req.body);
const alertName = event.eventType;
logger.info(`Received ${alertName} webhook`);
logger.info(req.body);
logger.info(event);
if (isSupportedWebhook(alertName)) {
return handlers[alertName](req, res);
await queues[alertName].enqueue({ event: event as Events }, { id: event.eventId.toString() });
return res.status(200).end();
}
return res.status(400).end();
};
export default webhook;
function isSupportedWebhook(eventType: PaddleSdkWebhookEventType): eventType is SupportedEventType {
return Object.keys(queues).includes(eventType);
}