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

Example or documentation on how Webhook works #38

Open
confact opened this issue Aug 6, 2021 · 4 comments
Open

Example or documentation on how Webhook works #38

confact opened this issue Aug 6, 2021 · 4 comments

Comments

@confact
Copy link
Owner

confact commented Aug 6, 2021

It is possible to understand how to set up the webhook through the API docs or the ruby version of it.

But maybe add an example in the readme to make it easier to understand?

@vectorselector
Copy link
Contributor

vectorselector commented Aug 6, 2021

I can help up to the point of using the instantiated event
(After that point I've ended up with strange things like:
subscription_id = event.data.object.as(Stripe::Invoice).lines.as(Stripe::List(Stripe::Invoice::LineItem)).data.first.as(Stripe::Invoice::LineItem).subscription.to_s that I'm not sure about and feel fragile)

The issue is that we need to emphasize the need for a RAW request body, not a parsed one nor with any bit out of place. It's used in the HMAC. This will implicate a middleware/router/framework. I can provide a Kemal example.

Would I merely edit the README.md and add it near the bottom before the list of modules?

Here's an example, which I would explain as much as possible

post "/webhooks_stripe/invoice_payment_succeeded" do |env|
  if(Kemal.config.env == "production")
    stripe_webhook_secret = "your_stripe_webhook_secret"
  else#must be development or test. this is the CLI command webhook
    stripe_webhook_secret = CLI_WEBHOOK_SECRET
  end

  headers = env.request.headers
  stripe_signature = headers["Stripe-Signature"].to_s
  payload = env.request.body.not_nil!.gets_to_end

  event = Stripe::Webhook.construct_event(payload, stripe_signature, stripe_webhook_secret, 99999)

  if event && event.data && event.data.object
    cust = event.data.object.as(Stripe::Invoice).customer.to_s
    subscription_id = event.data.object.as(Stripe::Invoice).lines.as(Stripe::List(Stripe::Invoice::LineItem)).data.first.as(Stripe::Invoice::LineItem).subscription.to_s
   #Do stuff...
  end

  #Stripe will eventually disable your webhook if it doesn't return a 2xx. Returning a 200 to non-stripe-entities trying to send you a fake-webhook is probably an ok response, a bit like "username or password incorrect"
  200
end

@rmarronnier
Copy link
Contributor

I was thinking about this : maybe make a webhook.md and link to it from the readme.md ? (the readme.md is very long as it is, it'll shrink when all objects/methods are implemented but still)

I can add a Lucky example like this one (@stephendolan lucky' skills might bring something better :-p ) :

class StripeEvents::Webhook < ApiAction
  include Api::Auth::SkipRequireAuthToken
  accepted_formats [:json, :xml], default: :json
  post "/stripe/webhook" do
    # You can use webhooks to receive information about asynchronous payment events.
    # For more about our webhook events check out https://stripe.com/docs/webhooks.
    webhook_secret = Application.settings.stripe_webhook_secret
    signature_header = request.headers["Stripe-Signature"]
    begin
      event = Stripe::Webhook.construct_event(payload: request.body.not_nil!.gets_to_end, sig_header: signature_header, secret: webhook_secret)
    rescue e : JSON::SerializableError
      Log.error { e.message }
      json({status: "error", error: e.message}, 500)
    rescue e2 : SignatureVerificationError
      Log.error { "⚠️  Webhook signature verification failed." }
      json({status: "error", error: e2}, 404)
    else
      event_handler(event.not_nil!)
      json({status: "success"})
    end
  end

@confact
Copy link
Owner Author

confact commented Aug 23, 2021

@vectorselector @rmarronnier Sounds good. As simple as possible is good; we can add it as a wiki page, maybe? We should probably have for at least the 2-3 biggest frameworks, in other words, for Kemal, Lucky, and Amber.

I will try to set it up during this week.

You should not need to set as on all objects on the whole chain. Then we should fix that, @vectorselector. It will be hard to fix the return type as it is a bit dynamic. But it should be possible to help out a bit, at least. Or at least fix an understandable tutorial/documentation about it.

@confact
Copy link
Owner Author

confact commented Nov 4, 2021

I haven't got time to do this yet. If you guys (@rmarronnier and @vectorselector) have tested it, we can use those for some wiki page for it, at least. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants