Skip to content

Commit

Permalink
GITBOOK-6: change request with no subject merged in GitBook
Browse files Browse the repository at this point in the history
  • Loading branch information
tsutomi authored and gitbook-bot committed Oct 30, 2023
1 parent e459131 commit edfb6ae
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 9 deletions.
2 changes: 1 addition & 1 deletion docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* [Data Layers](notifications/webhook-subscriptions-management/webhook\_subscription\_data\_layers/README.md)
* [Entity Framework Layer](notifications/webhook-subscriptions-management/webhook\_subscription\_data\_layers/webhook\_subscription\_ef.md)
* [The WebhookNotifier Service](notifications/webhook\_notifier.md)
* [Producing Custom Data Factories](notifications/custom\_datafactory.md)
* [Webhook Factories](notifications/webhook-factories.md)
* [Filtering Webhook Subscriptions](notifications/webhook\_subscription\_filters.md)
* [Receivers](receivers/README.md)
* [Webhook Receivers](receivers/custom\_receiver.md)
Expand Down
107 changes: 107 additions & 0 deletions docs/notifications/webhook-factories.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Webhook Factories

In notification scenarios triggered by an event, the webhooks to be notified must be built and delivered to subscribers, and this construction process might need to _transform_ the original data carried by those triggering events into a new object.

In fact, sometimes events don't carry all the information that has to be transmitted to the receivers, for several reasons (eg. _privacy_, _design_, _external context_, etc.), and this requires an additional intervention for the integration of that information (eg. _resolving an entity from the database_, _appending the environment variables of the notifier_, etc.).

_Note_: This is not a mandatory passage in the notification process, and can be skipped if the data carried by the event represents the information to be transferred to the receivers.

### Event Information

The overall contract of an event as recognized by the system is defined by the `EventInfo` structure, that is composed of the following fields:

<table data-full-width="true"><thead><tr><th>Field</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>Id</code></td><td><code>string</code></td><td>The identifier of the event</td></tr><tr><td><code>Source</code></td><td><code>string</code></td><td>The source of the event (eg. <code>github</code>)</td></tr><tr><td><code>Subject</code></td><td><code>string</code></td><td>The subject of the event (eg. <code>issue</code>)</td></tr><tr><td><code>Type</code></td><td><code>string</code></td><td>The type of the event (eg. <code>created</code>)</td></tr><tr><td><code>TimeStamp</code></td><td><code>DateTimeOffset</code></td><td>The exact time the event has occurred in the source system</td></tr><tr><td><code>Data</code></td><td><code>object</code></td><td>The payload that contains the actual data of the event</td></tr></tbody></table>

This design respects a general contract of the domain-driven design, informing of the event's nature and the payload that contains the actual data.

#### Cloud Events

An example of the implementation of this contract is the [Cloud Events](https://cloudevents.io/) specification, that defines a standard for the representation of events in a cloud-native environment.

Anyway, despite the adherence to the overall design, the Deveel Webhooks framework is not tied to this specification, but it can be used to implement it, an it requires the EventInfo structure to be provided in order to be able to send notifications.

### Event Data

As mentioned before, the event data is not always in the format that is expected by the target system that will be notified, and the resons to implement a further passage of transformation are various:

* The event data might contain sensitive information, that should not be exposed to the target system
* The event data might contain information that is not relevant to the target system
* The event data might contain information that is not available in the event, but must be retrieved from external sources (eg._database entries_, _environment variables_, etc.)

### Transforming the EventInfo to a Webhook: the `IWebhookFactory<TWebhook>` interface

The notifier service uses instances of the `IWebhookFactory<TWebhook>` interface to transform a triggering event, into a webhook object that is expected by the subscribing applications, using a subscription-scoped transformation logic.

Transformations are specific to your use cases and they can be specific to a given event condition (eg. _only a specific type of event with a given value in its 'data' component triggers the transformation_).

To implement this logic in the application, you must first create a new class that inherits from the `IWebhookFactory<TWebhook>` contract.

```csharp
public class MyWebhookFactory : IWebhookFactory<MyWebhook> {
private readonly IUserResolver resolver;

public MyWebhookFactory(IUserResolver resolver) {
this.resolver = resolver;
}

public Task<MyWebhook> CreateAsync(IWebhookSubscription subscription, EventInfo eventInfo, CancellationToken cancellationToken) {
// Resolve the event data
var userId = eventInfo.Data.GetString("userId");
var user = await resolver.GetUserAsync(userId, cancellationToken);

var webhookType = $"user.{eventInfo.Type}";

// Transform the event data
return new MyWebhook {
Type = webhookType,
User = new UserInfo {
Id = user.Id,
Email = user.Email,
FirstName = user.FirstName,
LastName = user.LastName
}
};
}
}
```

### Registering the Webhook Factory

To enable the implementation by your custom Webhook Factory, you can register it during the configuration of the application.

```csharp
using System;

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

using Deveel.Webhooks;

namespace Example {
public class Startup {
public Startup(IConfiguration config) {
Configuration = config;
}

public IConfiguration Configuration { get; }

public void Configure(IServiceCollection services) {
// ... add any other service you need ...
// this call adds the basic services for sending of webhooks
services.AddWebhookNotifier(webhooks => {
// This call registers your custom webhook factory as a
// singleton service by default, but other overloads
// allow controlling the lifetime
webhooks.UseWebhookFactory<MyWebhookFctory>();
});
}
}
}
```

### The Default WebhookFactory

When registering the Webhook Notifier service, by default the framework will register a default implementation of the `IWebhookFactory<TWebhook>` interface, if the type of `TWebhook` is derived from the `Webhook` class: this factory will attempt to create instances of the webhook type using the default constructor, and then it will try to map the properties of the webhook object to the properties of the event data and the subscription data.

This approach is useful when the webhook object is a simple POCO that can be easily mapped to the event data, and it doesn't require any further transformation logic, but it's not suitable for more complex scenarios.
11 changes: 3 additions & 8 deletions docs/notifications/webhook_notifier.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# The WebhookNotifier Service

As described in the [previous chapter](README.md), when registering the Webhook Notifier service, a number of services are registered in the container, that are used to manage the subscriptions and to deliver the webhooks to the receiving end-point.
As described in the [previous chapter](./), when registering the Webhook Notifier service, a number of services are registered in the container, that are used to manage the subscriptions and to deliver the webhooks to the receiving end-point.

An default implementation of the `IWebhookNotifier<TWebhook>` service is also registered by the framework, which is the `WebhookNotifier<TWebhook>` class.

Expand All @@ -14,12 +14,7 @@ This implementation executes the following steps:

### Service Dependencies

| Service | Description |
|---------|-------------|
| `IWebhookSubscriptionResolver<TWebhook>` | Resolves the subscriptions to an event. It is generally provided externally, since it's generally tied to the Webhook Subscription service. Anyway, a default implementation of this service is registered, that is a wrapper around any registered `IWebhookSubscriptionRepository<TSubscription>` in the container. |
| `IWebhookFactory<TWebhook>` | Transforms the event into a webhook object of the type supported by the service, and that will be then notified. |
| `IWebhookFilterEvaluator<TWebhook>` | The service used to evaluate the filters of the subscriptions. When none is provided at the registration, and webhook subscriptions define any filter, the notification to those subscribers will fail. See [this chapter](webhook_subscription_filters.md) for more information |
| `IWebhookDeliveryResultLogger<TWebhook>` | When available in the context of the application, logs the results of the delivery of the webhooks |
<table data-full-width="true"><thead><tr><th width="421.5">Service</th><th>Description</th></tr></thead><tbody><tr><td><code>IWebhookSubscriptionResolver&#x3C;TWebhook></code></td><td>Resolves the subscriptions to an event. It is generally provided externally, since it's generally tied to the Webhook Subscription service. Anyway, a default implementation of this service is registered, that is a wrapper around any registered <code>IWebhookSubscriptionRepository&#x3C;TSubscription></code> in the container.</td></tr><tr><td><code>IWebhookFactory&#x3C;TWebhook></code></td><td>Transforms the event into a webhook object of the type supported by the service, and that will be then notified.</td></tr><tr><td><code>IWebhookFilterEvaluator&#x3C;TWebhook></code></td><td>The service used to evaluate the filters of the subscriptions. When none is provided at the registration, and webhook subscriptions define any filter, the notification to those subscribers will fail. See <a href="webhook_subscription_filters.md">this chapter</a> for more information</td></tr><tr><td><code>IWebhookDeliveryResultLogger&#x3C;TWebhook></code></td><td>When available in the context of the application, logs the results of the delivery of the webhooks</td></tr></tbody></table>

## Custom Webhook Notifiers

Expand All @@ -34,4 +29,4 @@ services.AddWebhookNotifier<MyWebhook>()
.UseNotifier<MyNotifier>();
```

All other default services will still be registered, and you can still use them in your custom implementation, by injecting them in the constructor of your class.
All other default services will still be registered, and you can still use them in your custom implementation, by injecting them in the constructor of your class.

0 comments on commit edfb6ae

Please sign in to comment.