firebase functions 와 stripe webhook연결
Now lets head over to our terminal and create a new directory for our project.
$ mkdir stripe-webhooks
$ cd stripe-webhooks
We then need to install the firebase-tools package globally using NPM.
(아래는 firebase-tool설치)
$ npm install -g firebase-tools
Now we have firebase-tools installed, we should login to our firebase account and initiate a new project in our project directory. You will get a choice of which services you would like to use — you only need to select ‘Functions’ here for now.
(아래는 firebase 사용전 초기 작업)
$ firebase login
$ firebase init
Let’s move into the functions folder (created with firebase init) and make sure we have the latest version of firebase-functions and firebase-admin installed. firebase-functions is used for running the actual cloud functions and firebase-admin is used to access the Realtime Database.
$ cd functions/
$ npm install firebase-functions@latest firebase-admin@latest --save
Let’s create a new function called events to handle our endpoint. We’ll start off simple with a basic function that returns a string to let us generate the URL we need to supply our Stripe account with.
const functions = require('firebase-functions');exports.events = functions.https.onRequest((request, response) => {
response.send("Endpoint for Stripe Webhooks!");
});
We can then deploy our function and get our endpoint (Function URL in output in screenshot).
firebase deploy --only functions
(아래는 stripe에 webhook 만드는 과정)
Now we have our Cloud Function URL, we can head over to the webhooks section of the Stripe dashboard. We then want to + Add Endpoint, and enter our URL into the URL field. You can select the types of events to be sent, but for now we will just stick to all event types.
Once you create the endpoint, take note of your ‘Signing secret’ — we’ll need that to verify the request send to our function.
While we’re in our Stripe Dashboard, let’s head over to the API Keys section to generate and take not of the API key we’re going to use.
You should create a restricted API key and only assign permissions you’re going to need in your firebase project. For example, if you’re only going to read customer objects, you can specify only Customers when creating the key.
Now we have our signing secret and our API key, let’s add them to our Firebase project as environment variables so we don’t need to check them in to any source control.
$ firebase functions:config:set
keys.webhooks="your_restricted_key"
keys.signing="your_signing_key"
That’s our setup complete — We’re now ready to write some code! I’m going to be using examples from Firebase and Stripe, so if there’s anything you would like to dive deeper into, you can use the following links:
To start with, we’re going to need the Stripe NPM package, so let’s go ahead and install that:
(stripe 라이브러리 설치)
$ npm install --save stripe
We added our API keys to our Firebase config, so we can access them using functions.config() (For example: functions.config().keys.webhooks will return our keys.webhooks string we added).
We will then require the Stripe package in our functions index.js. We will also bring in our Signing key to our application (endpointSecret).
const functions = require(‘firebase-functions’);
const stripe = require(‘stripe’)(functions.config().keys.webhooks);
const endpointSecret = functions.config().keys.signing;exports.events = functions.https.onRequest((request, response) => {
response.send(“Endpoint for Stripe Webhooks!”);
});
Note: Stripe marks a webhook as successful only when your function returns a success (2xx) response. If it receives anything else, such as a 400 or 500, then it marks it as failed, and will try again.
We can use our signing key to verify that a request has actually come from Stripe, and not an unauthorized attacker. The stripe package has a method (stripe.webhooks.constructEvent) which we can use to verify the request. We can also use a Try Catch to return an error if the request fails verification.
// Get the signature from the request header
let sig = request.headers["stripe-signature"];// Verify the request against our endpointSecret
let event = stripe.webhooks.constructEvent(request.rawBody, sig, endpointSecret);
Note: We need to use the original request body otherwise the verification will fail, so we must use Firebase Function’s request.rawBody, instead of the usual request.body.
As mentioned, we can wrap this in a Try Catch to catch any failed requests.
let sig = request.headers["stripe-signature"];try {
let event = stripe.webhooks.constructEvent(request.rawBody, sig, endpointSecret);
} catch (err) {
return response.status(400).end();
}
Now we have our valid events, let’s save them to our Firebase Realtime Database.
We can do this by using the firebase-admin database methods. We’re going to be using the .push() method to create a new entry in our database.
const admin = require('firebase-admin');
admin.initializeApp();...return admin.database().ref('/events').push(event)
.then((snapshot) => {
return response.json({ received: true, ref: snapshot.ref.toString() });
})
.catch((err) => {
console.error(err);
return response.status(500).end();
});
Let’s break this code down a bit.
- Ref is the path in the database we would like to save our new entry to. This can be whatever you like — i’ve chosen so save my events in the /events ref.
- Push(event)- event is the variable we’re saving the response from the constructEvent method we called. This is an object with all of our event info
- Response.json — We respond with a valid json object — this tells Stripe that the webhook event was received and we’re happy we’ve processed it, so mark it as complete.
- Catch — In case something goes wrong while we’re saving the event to the database, we return an error 500 to tell Stripe that something went wrong. Stripe will then retry sending the event. There are ways you could incorporate this into the Try Catch we have, although I like having the differentiation of errors.
Now we should deploy our function again, then we can test it out.
$ firebase deploy --only functions
Let’s head back over to the Stripe Dashboard Webhooks area, select our endpoint where we can now ‘Send test webhook’.
Select an event type and hit ‘Send test webhook’ — all going well, we get a successful response, and our event is now saved in our database!
That’s it in terms of saving. Now you have endless possibilities of cool things to do with your data. For further reading, you could explore the different triggers Cloud Functions can use. You can run another function whenever anything is added to your database. The example below would run any time a new event is saved to our database. We could now check the event type, and if it’s a successful charge, update our Realtime database to increase our daily revenue on our live dashboard…
You can read more about database events here: https://firebase.google.com/docs/functions/database-events
I hope this was useful. Please leave any feedback or questions – I’m always learning and really appreciate any comments you may have.
You can find the completed code over on Github — https://github.com/GaryH21/Stripe-Webhooks-Tutorial
Happy building!