-
Notifications
You must be signed in to change notification settings - Fork 388
Add EventNotificationHandler example #2129
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| package com.stripe.examples; | ||
|
|
||
| import com.stripe.StripeClient; | ||
| import com.stripe.StripeEventNotificationHandler; | ||
| import com.stripe.StripeEventNotificationHandler.UnhandledNotificationDetails; | ||
| import com.stripe.events.V1BillingMeterErrorReportTriggeredEventNotification; | ||
| import com.stripe.exception.StripeException; | ||
| import com.stripe.model.billing.Meter; | ||
| import com.stripe.model.v2.core.EventNotification; | ||
| import com.sun.net.httpserver.HttpExchange; | ||
| import com.sun.net.httpserver.HttpHandler; | ||
| import com.sun.net.httpserver.HttpServer; | ||
| import java.io.ByteArrayOutputStream; | ||
| import java.io.IOException; | ||
| import java.io.InputStream; | ||
| import java.net.InetSocketAddress; | ||
| import java.nio.charset.StandardCharsets; | ||
|
|
||
| /** | ||
| * Receive and process event notifications (AKA thin events) like | ||
| * "v1.billing.meter.error_report_triggered" using EventNotificationHandler. | ||
| * | ||
| * <p>In this example, we: | ||
| * | ||
| * <ul> | ||
| * <li>write a fallback callback to handle unrecognized event notifications | ||
| * <li>create a StripeClient called client | ||
| * <li>Initialize an EventNotificationHandler with the client, webhook secret, and fallback | ||
| * callback | ||
| * <li>register a specific handler for the "v1.billing.meter.error_report_triggered" event | ||
| * notification type | ||
| * <li>use handler.handle() to process the received notification webhook body | ||
| * </ul> | ||
| */ | ||
| public class EventNotificationHandlerEndpoint { | ||
| private static final String API_KEY = System.getenv("STRIPE_API_KEY"); | ||
| private static final String WEBHOOK_SECRET = System.getenv("WEBHOOK_SECRET"); | ||
|
|
||
| private static final StripeClient client = new StripeClient(API_KEY); | ||
| private static final StripeEventNotificationHandler handler = | ||
| client.notificationHandler( | ||
| WEBHOOK_SECRET, EventNotificationHandlerEndpoint::fallbackCallback); | ||
|
|
||
| public static void main(String[] args) throws IOException { | ||
| handler.onV1BillingMeterErrorReportTriggered( | ||
| EventNotificationHandlerEndpoint::handleMeterErrors); | ||
|
|
||
| HttpServer server = HttpServer.create(new InetSocketAddress(4242), 0); | ||
| server.createContext("/webhook", new WebhookHandler()); | ||
| server.setExecutor(null); | ||
| server.start(); | ||
| } | ||
|
|
||
| private static void fallbackCallback( | ||
| EventNotification notif, StripeClient client, UnhandledNotificationDetails details) { | ||
| System.out.println("Received unhandled event notification type: " + notif.getType()); | ||
| } | ||
|
|
||
| private static void handleMeterErrors( | ||
| V1BillingMeterErrorReportTriggeredEventNotification notif, StripeClient client) { | ||
| Meter meter; | ||
| try { | ||
| meter = notif.fetchRelatedObject(); | ||
| } catch (StripeException e) { | ||
| // TODO Auto-generated catch block | ||
| e.printStackTrace(); | ||
| return; | ||
| } | ||
|
Comment on lines
+64
to
+68
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is interesting. I hadn't thought about this before, but perhaps they want to throw here so their webhook handler can return a non-200 response. Can you throw a checked exception here, or does that no longer compile?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I played with that, but then Java complains that the Given that it's just an example, I think i'm fine with either:
do you have strong feelings?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's the thing with checked exceptions--they are considered part of the signature of the function. I think before we go to GA, we should see if we can make a checked
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, but I'm not sure how we communicate to java that calling But yeah, it's a good thing to dig into before GA! |
||
| System.out.println("Handling meter error for meter: " + meter.getDisplayName()); | ||
| } | ||
|
|
||
| static class WebhookHandler implements HttpHandler { | ||
| // For Java 1.8 compatibility | ||
| public static byte[] readAllBytes(InputStream inputStream) throws IOException { | ||
| final int bufLen = 1024; | ||
| byte[] buf = new byte[bufLen]; | ||
| int readLen; | ||
|
|
||
| ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); | ||
|
|
||
| while ((readLen = inputStream.read(buf, 0, bufLen)) != -1) | ||
| outputStream.write(buf, 0, readLen); | ||
|
|
||
| return outputStream.toByteArray(); | ||
| } | ||
|
|
||
| @Override | ||
| public void handle(HttpExchange exchange) throws IOException { | ||
| if ("POST".equals(exchange.getRequestMethod())) { | ||
| InputStream requestBody = exchange.getRequestBody(); | ||
| String webhookBody = new String(readAllBytes(requestBody), StandardCharsets.UTF_8); | ||
| String sigHeader = exchange.getRequestHeaders().getFirst("Stripe-Signature"); | ||
|
|
||
| try { | ||
| handler.handle(webhookBody, sigHeader); | ||
|
|
||
| exchange.sendResponseHeaders(200, -1); | ||
| } catch (StripeException e) { | ||
| exchange.sendResponseHeaders(400, -1); | ||
| } | ||
| } else { | ||
| exchange.sendResponseHeaders(405, -1); | ||
| } | ||
| exchange.close(); | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit:
private static finalvariables are generally done inALL_CAPS. I thinkprivate finalwould make more sense here anywayUh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's fair! though, since we're calling it from
public static void main, the compiler complainsCannot make a static reference to the non-static field. I think for the purposes of the example, it's fine as is.