Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added typescript webhook example #749

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions examples/webhook-signing/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.env
express-ts.js
89 changes: 89 additions & 0 deletions examples/webhook-signing/express-ts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import Stripe from 'stripe';
import express from 'express';
import bodyParser from 'body-parser';
import dotenv from 'dotenv';

dotenv.config();

const stripe: Stripe = new Stripe(process.env.STRIPE_API_KEY!, {
apiVersion: '2019-12-03',
typescript: true,
});

/**
* You'll need to make sure this is externally accessible. ngrok (https://ngrok.com/)
* makes this really easy.
*
* Alternatively, you could use the stripe-cli in forward mode: https://github.com/stripe/stripe-cli
*
* To run this file, just provide your Secret API Key and Webhook Secret in a .env file in this directory like so:
*
* STRIPE_API_KEY=sk_test_XXX
* WEBHOOK_SECRET=whsec_XXX
*
* Then run "npm run tsc", which will convert this TypeScript file to JS and then run it.
*
* For use with the stripe-cli, run the following:
*
* 1. "stripe listen --forward-to localhost:3000/webhooks"
* 2. Copy the provided webhook signing secret to your .env file
* 3. In a new terminal window: "npm run tsc"
* 4. In yet another new terminal window: "stripe trigger payment_intents.succeeded"
*/

const webhookSecret: string = process.env.WEBHOOK_SECRET!;
const app: express.Application = express();

// Only use the raw body parser for webhooks
app.use(
(
req: express.Request,
res: express.Response,
next: express.NextFunction
): void => {
if (req.originalUrl === '/webhooks') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this our best-practice? Does line 55 not work here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 55 does work, but I've seen people get tripped up by how express' middleware works. Having this block here will hopefully nip that confusion in the bud (and makes it so all other routes use the json body parser).

next();
} else {
bodyParser.json()(req, res, next);
}
}
);

// Stripe requires the raw body to construct the event
app.post(
'/webhooks',
bodyParser.raw({type: 'application/json'}),
(req: express.Request, res: express.Response): express.Response | void => {
const sig: string = req.headers['stripe-signature'] as string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is fixed; you no longer need to cast!


let event: Stripe.Event;

try {
event = stripe.webhooks.constructEvent(req.body, sig, webhookSecret);
} catch (err) {
// On error, return the error message
return res.status(400).send(`Webhook Error: ${err.message}`);
}

// Do something with event
console.log('Success:', event.id);

// Cast event data to Stripe object
switch (event.type) {
case 'payment_intent.succeeded':
const pi = event.data.object as Stripe.PaymentIntent;
console.log(`PaymentIntent status: ${pi.status}`);
break;
}

// Return a response to acknowledge receipt of the event
return res.json({received: true});
}
);

app.listen(
3000,
(): void => {
console.log('Example app listening on port 3000!');
}
);
Loading