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

Feature: add API for gateway webhook events #7664

Open
wants to merge 31 commits into
base: develop
Choose a base branch
from

Conversation

glaubersilva
Copy link
Contributor

@glaubersilva glaubersilva commented Jan 2, 2025

Sample using this API in a practical way: impress-org/givewp-addon-boilerplate#67

Description

This PR implements a new webhook events API and attaches it to the GiveWP gateways API, the main goal here is to facilitate the process of handling webhook notifications sent by external payment gateways to GiveWP gateway integrations.

Before we needed to create an async job through our Action Scheduler facade class explicitly, so the code for a webhook notification related to the transaction status change would be something like this:

AsBackgroundJobs::enqueueAsyncAction(
	'givewp_' . TestGateway::id() . '_event_donation_completed',
	[$webhookNotification->gatewayPaymentId],
	'CUSTOM_ACTION_SCHEDULER_GROUP'
);

However, the code above didn't make everything work automatically. We also needed to attach an event handler class to the hook created in the code above.

So in the service provider, we need to add something like this:

/**
 * We are using the DonationCompleted event handler class provided by Give Core to process the
 * async background event which is created on the OffSiteGatewayWebhookNotificationHandler class.
 *
 * A full list of event handler classes can be found on the following link:
 * @see https://github.com/impress-org/givewp/tree/develop/src/Framework/PaymentGateways/Webhooks/EventHandlers
 */
Hooks::addAction('givewp_' . TestGateway::id() . '_event_donation_completed', DonationCompleted::class);

This approach is ok, but when you have a bunch of different types of notifications/events to handle you need to pay attention to creating a lot of hooks with certain naming standards.

Also, it's a common thing to implement a custom function to prevent repeating the custom action scheduler group string on each place you need to create an async background job.

This raises the question...

Why a 3rd party developer integrating a a gateway with GiveWP be concerned about it?

In fact, they even need to know (if they don't want to) that GiveWP is using Action Scheduler under the hood.

So, the new gateway webhook events API allows developers to handle the webhook notifications/events easily, just doing something like this:

TestGateway::webhook()->events->paymentCompleted($webhookNotification->gatewayPaymentId);

Inside the gateway class, you can do it like this:

$this->webhook->events->paymentCompleted($webhookNotification->gatewayPaymentId);

Is just that! They don't need to more spend time naming hooks and enqueueing them with the proper event handler class attached to it, they even need to know anything about Action Scheduler.

Bonus feature:

Another repetitive task related to the gateway webhook is related to the notification URL and the listening notifications method.

In each integration we need to set a route, a method to retrieve the webhook notification URL and then create a method with the same name of the route as in this sample:

public $routeMethods = [
        'webhookNotificationsListener',
];

public static function getWebhookNotificationUrl(): string
{
   $instance = new static();
   
   return $instance->generateGatewayRouteUrl('webhookNotificationsListener');
}

public function webhookNotificationsListener()
{ 
   // Your logic goes here...
}

Now, all you need to do is this:

class TestGateway extends PaymentGateway implements WebhookNotificationsListener
{
    public function webhookNotificationsListener()
    {
        // Your logic goes here...
    }
    
    // Other class methods go here...
}

And, if you wish to retrieve the webhook notification URL in any place you can use it:

TestGateway::webhook()->getNotificationUrl();

Inside the gateway class, you can do it like this:

$this->webhook->getNotificationUrl();

If your gateway class doesn't implement the implements WebhookNotificationsListener interface the following error will be thrown when you try to use the getNotificationUrl() method:

Gateway does not support listening to webhook notifications.

Affects

It will make the new gateway integrations easier.

Visuals

image

image

image

Testing Instructions

  1. Run the composer test -- --filter WebhookEvents command in your terminal;
  2. To see it working in the sample gateway, check the instructions of this related PR: Refactor: add support to the gateway webhook events API givewp-addon-boilerplate#67

Pre-review Checklist

  • Acceptance criteria satisfied and marked in related issue
  • Relevant @unreleased tags included in DocBlocks
  • Includes unit tests
  • Reviewed by the designer (if follows a design)
  • Self Review of code and UX completed

@glaubersilva glaubersilva self-assigned this Jan 2, 2025
@glaubersilva glaubersilva marked this pull request as ready for review January 15, 2025 20:14
@jonwaldstein jonwaldstein self-requested a review January 17, 2025 17:24
@glaubersilva
Copy link
Contributor Author

@jonwaldstein Your last comment inspired me to refactor it and now we have the following approach for methods related to webhook events:

TestGateway::webhook()->events->paymentCompleted($webhookNotification->gatewayPaymentId);

// or...

$this->webhook->events->paymentCompleted($webhookNotification->gatewayPaymentId);

For general methods related to webhooks, we have this:

TestGateway::webhook()->getNotificationUrl();

// or...

$this->webhook->getNotificationUrl();

This is ready for re-review.

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

Successfully merging this pull request may close these issues.

2 participants