Skip to content

Commit

Permalink
chore: add POST /api/stripe-webhooks catches and tests (#546)
Browse files Browse the repository at this point in the history
Towards #267 and
#492
  • Loading branch information
iuioiua authored Sep 9, 2023
1 parent dc3ba27 commit 5199c63
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 6 deletions.
56 changes: 56 additions & 0 deletions e2e_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,3 +331,59 @@ Deno.test("[e2e] GET /api/users/[login]/notifications", async () => {
JSON.parse(JSON.stringify(notification)),
]);
});

Deno.test("[e2e] POST /api/stripe-webhooks", async (test) => {
const url = "http://localhost/api/stripe-webhooks";

await test.step("returns HTTP 404 Not Found response if Stripe is disabled", async () => {
Deno.env.delete("STRIPE_SECRET_KEY");
const resp = await handler(new Request(url, { method: "POST" }));

assertFalse(resp.ok);
assertEquals(await resp.text(), "Not Found");
assertEquals(resp.status, Status.NotFound);
});

await test.step("returns HTTP 400 Bad Request response if `Stripe-Signature` header is missing", async () => {
Deno.env.set("STRIPE_SECRET_KEY", crypto.randomUUID());
const resp = await handler(new Request(url, { method: "POST" }));

assertFalse(resp.ok);
assertEquals(await resp.text(), "`Stripe-Signature` header is missing");
assertEquals(resp.status, Status.BadRequest);
});

await test.step("returns HTTP 500 Internal Server Error response if `STRIPE_WEBHOOK_SECRET` environment variable is not set", async () => {
Deno.env.delete("STRIPE_WEBHOOK_SECRET");
const resp = await handler(
new Request(url, {
method: "POST",
headers: { "Stripe-Signature": crypto.randomUUID() },
}),
);

assertFalse(resp.ok);
assertEquals(
await resp.text(),
"`STRIPE_WEBHOOK_SECRET` environment variable is not set",
);
assertEquals(resp.status, Status.InternalServerError);
});

await test.step("returns HTTP 400 Bad Request response if the event payload is invalid", async () => {
Deno.env.set("STRIPE_WEBHOOK_SECRET", crypto.randomUUID());
const resp = await handler(
new Request(url, {
method: "POST",
headers: { "Stripe-Signature": crypto.randomUUID() },
}),
);

assertFalse(resp.ok);
assertEquals(
await resp.text(),
"No webhook payload was provided.",
);
assertEquals(resp.status, Status.BadRequest);
});
});
25 changes: 19 additions & 6 deletions routes/api/stripe-webhooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,32 @@ import { getUserByStripeCustomer, updateUser } from "@/utils/db.ts";
import { createHttpError } from "std/http/http_errors.ts";

const cryptoProvider = Stripe.createSubtleCryptoProvider();

export const handler: Handlers = {
/**
* This handler handles Stripe webhooks for the following events:
* 1. customer.subscription.created (when a user subscribes to the premium plan)
* 2. customer.subscription.deleted (when a user cancels the premium plan)
* Handles Stripe webhooks requests when a user subscribes
* (`customer.subscription.created`) or cancels
* (`customer.subscription.deleted`) the "Premium Plan".
*
* @see {@link https://github.com/stripe-samples/stripe-node-deno-samples/blob/2d571b20cd88f1c1f02185483729a37210484c68/webhook-signing/main.js}
*/
async POST(req) {
if (!isStripeEnabled()) throw createHttpError(Status.NotFound);

/** @see {@link https://stripe.com/docs/webhooks#verify-events} */
const body = await req.text();
const signature = req.headers.get("stripe-signature")!;
const signingSecret = Deno.env.get("STRIPE_WEBHOOK_SECRET")!;
const signature = req.headers.get("stripe-signature");
if (signature === null) {
throw createHttpError(
Status.BadRequest,
"`Stripe-Signature` header is missing",
);
}
const signingSecret = Deno.env.get("STRIPE_WEBHOOK_SECRET");
if (signingSecret === undefined) {
throw new Error(
"`STRIPE_WEBHOOK_SECRET` environment variable is not set",
);
}

let event!: Stripe.Event;
try {
Expand Down

0 comments on commit 5199c63

Please sign in to comment.