refactor: Improve Stripe webhook code quality and type safety#1
refactor: Improve Stripe webhook code quality and type safety#1DavidASix wants to merge 1 commit into
Conversation
Refactored `src/app/api/purchases/webhook/route.ts` to enhance
readability, type safety, and maintainability:
- Introduced helper functions `determineUserId` and `processPayment` to
encapsulate core logic and reduce nesting in the main POST handler.
- Defined a `CheckoutSessionMetadata` interface for clearer typing of
`session.metadata.userId`.
- Improved type safety by:
- Reducing the use of the `as` keyword.
- Handling potential null values from request headers and Stripe API
responses more explicitly.
- Typing error objects in `try-catch` blocks.
- Streamlined error handling for missing Stripe signature and webhook secret.
- Removed unnecessary comments, focusing on self-documenting code.
- Ensured consistent and safe access to Stripe customer and payment intent IDs,
whether they are strings or expanded objects.
The core logic for `user_id` determination (checking metadata then prior
payments) and payment record insertion remains the same, but is now
organized into a cleaner structure.
There was a problem hiding this comment.
Pull Request Overview
Refactors the Stripe webhook handler for better readability, type safety, and adds a new payments schema to persist checkout sessions.
- Introduces a
paymentstable in the database schema. - Extracts core logic into
determineUserIdandprocessPaymenthelper functions. - Updates environment example to include the Stripe webhook secret.
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/schema/schema.ts | Added a new payments table definition with relevant fields and constraints. |
| src/app/api/purchases/webhook/route.ts | Refactored webhook route to use helper functions, improved typing and errors. |
| .env.example | Added STRIPE_WEBHOOK_SECRET placeholder with instructions. |
Comments suppressed due to low confidence (1)
src/app/api/purchases/webhook/route.ts:15
- Unit tests for the new
determineUserIdandprocessPaymentfunctions are missing. Adding tests will verify metadata lookups, error handling paths, and successful database inserts.
async function determineUserId(session: Stripe.Checkout.Session, dbInstance: typeof db): Promise<string | null> {
| const paymentData = { | ||
| user_id: userId, | ||
| stripe_customer_id: typeof session.customer === 'string' ? session.customer : (session.customer?.id || null), | ||
| stripe_payment_intent_id: typeof session.payment_intent === 'string' ? session.payment_intent : null, |
There was a problem hiding this comment.
When session.payment_intent is an object, the code sets stripe_payment_intent_id to null. It should extract the id property (e.g., typeof session.payment_intent === 'string' ? session.payment_intent : session.payment_intent?.id) to ensure the payment intent ID is always captured.
| stripe_payment_intent_id: typeof session.payment_intent === 'string' ? session.payment_intent : null, | |
| stripe_payment_intent_id: typeof session.payment_intent === 'string' | |
| ? session.payment_intent | |
| : session.payment_intent?.id || null, |
| amount_total: session.amount_total, | ||
| currency: session.currency, | ||
| payment_status: session.payment_status, | ||
| line_items: lineItems ? JSON.parse(JSON.stringify(lineItems)) : null, |
There was a problem hiding this comment.
This persists the entire line_items list object (including metadata like has_more) instead of just the items. Consider storing lineItems.data (e.g., line_items: lineItems?.data ?? null) to save only the actual line item array.
| line_items: lineItems ? JSON.parse(JSON.stringify(lineItems)) : null, | |
| line_items: lineItems?.data ?? null, |
|
TLDR Jules is not very good and this PR sucked. Resolved this in #8 |
Refactored
src/app/api/purchases/webhook/route.tsto enhance readability, type safety, and maintainability:determineUserIdandprocessPaymentto encapsulate core logic and reduce nesting in the main POST handler.CheckoutSessionMetadatainterface for clearer typing ofsession.metadata.userId.askeyword.try-catchblocks.The core logic for
user_iddetermination (checking metadata then prior payments) and payment record insertion remains the same, but is now organized into a cleaner structure.