diff --git a/15/umbraco-cms/reference/webhooks/README.md b/15/umbraco-cms/reference/webhooks/README.md index ef38a44c816..c0eb3cae5e4 100644 --- a/15/umbraco-cms/reference/webhooks/README.md +++ b/15/umbraco-cms/reference/webhooks/README.md @@ -4,10 +4,9 @@ description: Umbraco webhooks enable seamless integration and real-time updates # Webhooks -Webhooks provide real-time, event-driven communication within Umbraco. They enable external services to react to content changes instantly by sending HTTP requests when specific events occur. This allows you to integrate with third-party services, automate workflows, and synchronize data effortlessly. +Webhooks provide real-time, event-driven communication within Umbraco. They enable external services to react to content changes instantly by sending HTTP requests when specific events occur. This allows developers to integrate with third-party services, automate workflows, and synchronize data effortlessly. ## Getting Started - To manage webhooks, navigate to **Settings > Webhooks** in the Umbraco backoffice. ![Webhooks section](images/webhook-section-v14.png) @@ -17,13 +16,10 @@ To create a webhook, click **Create**. This opens the webhook creation screen wh ![Creating a webhook](images/create-webhook-v14.png) ## Configuring a Webhook - ### URL - The `Url` is the endpoint where the webhook will send an HTTP request when the selected event is triggered. Ensure this endpoint is publicly accessible and capable of handling incoming requests. ### Events - Webhooks are triggered by specific events in Umbraco. By default, the following events are available: | Event Name | Description | @@ -35,48 +31,69 @@ Webhooks are triggered by specific events in Umbraco. By default, the following | Media Saved | Fires when a media item is saved. | ### Content Type Filtering - -For **Content** or **Media** events, you can specify whether the webhook should trigger for all content types or only specific ones. This is useful when you only need webhooks for certain document types, such as blog posts or products. +For **Content** or **Media** events, developers can specify whether the webhook should trigger for all content types or only specific ones. This is useful when activating webhooks for certain document types, such as blog posts or products. ### Custom Headers - -You can define custom HTTP headers that will be included in the webhook request. Common use cases include: +Developers can define custom HTTP headers that will be included in the webhook request. Common use cases include: - Specifying request format: `Accept: application/json` - Adding authentication tokens: `Authorization: Bearer ` - Including security headers ## Default Behavior of Umbraco Webhooks - Umbraco webhooks come with predefined settings and behaviors. ### JSON Payload +Each webhook event sends a JSON payload. The following types of payloads are available by default. -Each webhook event sends a JSON payload. For example, the `Content Published` event includes full content details: +#### Legacy +This is the current default but will be removed in a future version. Legacy payloads follow the format used before version 16. They are inconsistent and may include data that should not be exposed or has been superseded (e.g., use of `int` instead of `Guid`). -```json +#### Minimal +This will become the default in version 18 and later. Minimal payloads include only essential information to identify the resource. For most events, this means a unique identifier. Some events may include additional data. For example, a document publish event also includes the list of published cultures. + +#### Extended +Extended payloads include all relevant information for an event, where available. However, sensitive data, such as usernames, member names, or email addresses, is excluded for privacy and security reasons. If an extended payload is not available for an event, the system falls back to the minimal payload. + +### Configuring Payload Types +Payload type can be configured in the following ways: + +- Changing the appsetting `Umbraco:CMS:Webhook:PayloadType`. Be aware that the system that uses this value runs before any composers. If you manipulate the `WebhookEventCollectionBuilder` in any way, then those methods will not automatically pick up this app setting. +- Passing in the PayloadType into the `WebhookEventCollectionBuilderExtensions` methods to control which webhook events are added. + +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.Webhooks; + +namespace Umbraco.Cms.Web.UI.Composers; + +// this composer clears all registered webhooks and then adds all (umbraco provided) webhooks with their extended payloads +public class AllWebhookComposer : IComposer { - "name": "Root", - "createDate": "2023-12-11T12:02:38.9979314", - "updateDate": "2023-12-11T12:02:38.9979314", - "route": { - "path": "/", - "startItem": { - "id": "c1922956-7855-4fa0-8f2c-7af149a92135", - "path": "root" + public void Compose(IUmbracoBuilder builder) + { + builder.WebhookEvents().Clear().AddCms(onlyDefault: false, payloadType: WebhookPayloadType.Extended); } - }, - "id": "c1922956-7855-4fa0-8f2c-7af149a92135", - "contentType": "root", - "properties": {} } + ``` -The `Content Deleted` event sends only the content ID: +- Manually manipulating the `WebhookEventCollectionBuilder`. -```json +```csharp +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.Webhooks.Events; + +namespace Umbraco.Cms.Web.UI.Composers; + +// since legacy is the default, this composer removes the old content published webhookevent and changes it with the new extended version. +public class AllWebhookComposer : IComposer { - "id": "c1922956-7855-4fa0-8f2c-7af149a92135" + public void Compose(IUmbracoBuilder builder) + { + builder.WebhookEvents().Remove(); + builder.WebhookEvents().Add(); + } } ``` @@ -138,50 +155,53 @@ builder.WebhookEvents().Clear().AddCms(false); ### Replacing Webhook Events -You can modify existing webhook events, such as changing the payload format, by creating a custom implementation: +Developers can modify existing webhook events, such as changing the payload format, by creating a custom implementation: ```csharp +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DeliveryApi; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Notifications; +using Umbraco.Cms.Core.PublishedCache; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Sync; +using Umbraco.Cms.Core.Webhooks; + +namespace CommunityDocs.Controllers; + [WebhookEvent("Content Published", Constants.WebhookEvents.Types.Content)] -public class MyCustomContentPublishedWebhookEvent : WebhookEventContentBase +public class MyCustomContentPublishedWebhookEvent( + IWebhookFiringService webhookFiringService, + IWebhookService webhookService, + IOptionsMonitor webhookSettings, + IServerRoleAccessor serverRoleAccessor, + IApiContentBuilder apiContentBuilder, + IPublishedContentCache publishedContentCache): + WebhookEventContentBase(webhookFiringService, webhookService, webhookSettings, serverRoleAccessor) { - private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; - private readonly IApiContentBuilder _apiContentBuilder; - - public MyCustomContentPublishedWebhookEvent( - IWebhookFiringService webhookFiringService, - IWebhookService webhookService, - IOptionsMonitor webhookSettings, - IServerRoleAccessor serverRoleAccessor, - IPublishedSnapshotAccessor publishedSnapshotAccessor, - IApiContentBuilder apiContentBuilder) - : base(webhookFiringService, webhookService, webhookSettings, serverRoleAccessor) - { - _publishedSnapshotAccessor = publishedSnapshotAccessor; - _apiContentBuilder = apiContentBuilder; - } - public override string Alias => "Umbraco.ContentPublish"; protected override IEnumerable GetEntitiesFromNotification(ContentPublishedNotification notification) => notification.PublishedEntities; protected override object? ConvertEntityToRequestPayload(IContent entity) { - if (_publishedSnapshotAccessor.TryGetPublishedSnapshot(out IPublishedSnapshot? publishedSnapshot) is false || publishedSnapshot!.Content is null) - { - return null; - } - - IPublishedContent? publishedContent = publishedSnapshot.Content.GetById(entity.Key); + var cachedPublishedContent = publishedContentCache.GetById(entity.Key); return new { CustomData = "Your data", - PublishedContent = publishedContent is null ? null : _apiContentBuilder.Build(publishedContent) + PublishedContent = cachedPublishedContent is null ? null : apiContentBuilder.Build(cachedPublishedContent) }; } } ``` -To replace the default Umbraco webhook with your custom implementation: +{% hint style="info" %} +Umbraco developers need to inject `IPublishedContentCache`, `IPublishedMediaCache`, `IPublishedMemberCache`, and `IPublishedContentTypeCache` individually, instead of injecting the `IPublishedSnapshotAccessor` as in previous versions. +{% endhint %} + +The code below shows an example that replaces the default Umbraco webhook with a custom implementation: ```csharp public class MyComposer : IComposer @@ -197,19 +217,24 @@ public class MyComposer : IComposer Webhook settings are configured in `appsettings.*.json` under `Umbraco::CMS`: +{% code title="appsettings.json" %} ```json -"Umbraco": { - "CMS": { - "Webhook": { - "Enabled": true, - "MaximumRetries": 5, - "Period": "00:00:10", - "EnableLoggingCleanup": true, - "KeepLogsForDays": 30 +{ + "$schema": "appsettings-schema.json", + "Umbraco": { + "CMS": { + "Webhook": { + "Enabled": true, + "MaximumRetries": 5, + "Period": "00:00:10", + "EnableLoggingCleanup": true, + "KeepLogsForDays": 30 + } + } } - } } ``` +{% endcode %} | Setting | Description | |---------|-------------| @@ -221,4 +246,4 @@ Webhook settings are configured in `appsettings.*.json` under `Umbraco::CMS`: ## Testing Webhooks -Use [Beeceptor](https://beeceptor.com/) or [RequestBin](https://pipedream.com/requestbin) to test your event trigger integrations before deploying them to production. +Use [Beeceptor](https://beeceptor.com/) or [RequestBin](https://pipedream.com/requestbin) to test the event trigger integrations before deploying them to production. diff --git a/15/umbraco-cms/reference/webhooks/expanding-webhook-events.md b/15/umbraco-cms/reference/webhooks/expanding-webhook-events.md index 094c4fe91c1..edc7d5663bf 100644 --- a/15/umbraco-cms/reference/webhooks/expanding-webhook-events.md +++ b/15/umbraco-cms/reference/webhooks/expanding-webhook-events.md @@ -1,22 +1,21 @@ --- description: >- - Explore new webhook event options, detailed setup, specific content triggers, - and improved logging and retry mechanisms + Explore new webhook event options, detailed setup, specific content triggers, and improved logging and retry mechanisms. --- # Expanding Webhook Events ## Introduction -With Umbraco, you can create your own webhook events. +Umbraco developers can create their own webhook events. -This documentation guides you through the process of implementing your webhook events using the `WebhookEventBase` base class. +This article demonstrates the process of implementing custom webhook events using the `WebhookEventBase` base class. ## Creating an Event with the WebhookEventBase The `WebhookEventBase` class serves as the foundation for creating custom webhook events. Here's a brief overview of its key components: -* **Alias**: The property that must be overridden to provide a unique identifier for your webhook event. +* **Alias**: The property that must be overridden to provide a unique identifier for the webhook event. * **EventName**: A property that represents the name of the event. It is automatically set based on the provided alias unless explicitly specified. * **EventType**: A property that categorizes the event type. It defaults to "Others" but can be customized using the `WebhookEventAttribute`. * **WebhookSettings**: The property containing the current webhook settings. @@ -38,14 +37,14 @@ To create a custom webhook event, follow these steps: ``` 2. **Override the Alias Property**: - Provide a unique identifier for your event using the `Alias` property: + Provide a unique identifier for the event using the `Alias` property: ```csharp public override string Alias => "YourUniqueAlias"; ``` 3. **Apply `WebhookEventAttribute` (Optional)**: - You can use the `WebhookEventAttribute` to specify the event name and type. Apply this attribute to your custom event class: + Use the `WebhookEventAttribute` to specify the event name and type. Apply this attribute to the custom event class: ```csharp [WebhookEvent("Your Event Name", "YourEventType")] @@ -55,13 +54,14 @@ To create a custom webhook event, follow these steps: } ``` - Umbraco already has some types as constants, which you can find at `Constants.WebhookEvents.Types`. If you do not specify this attribute, the event name will default to your alias, and the type will default to `Other`. + Umbraco already has some types as constants, which you can find at `Constants.WebhookEvents.Types`. If this attribute is not specified, the event name will default to the alias, and the type will default to `Other`. +4. 4. **Implement Notification Handling**: If needed, customize the handling of the notification in the `HandleAsync` method. 5. **Register Your Webhook Event**: - Ensure that Umbraco is aware of your custom event by registering it in a composer: + Ensure that Umbraco is aware of the custom event by registering it in a composer: ```csharp using Umbraco.Cms.Core.Composing; @@ -74,11 +74,11 @@ To create a custom webhook event, follow these steps: } } ``` -6. **Implement Optional Overrides**: Depending on your requirements, you can override methods such as `ConvertNotificationToRequestPayload` and `ShouldFireWebhookForNotification` to customize the behavior of your webhook event. +6. **Implement Optional Overrides**: Depending on requirements, methods such as `ConvertNotificationToRequestPayload` and `ShouldFireWebhookForNotification` can be overridden to customize the behavior of the webhook event. ### Sample Implementation -Here's a basic example of a custom webhook event: +The code below shows a sample implementation of a custom webhook event. The `YourCustomEvent` class is derived from the `WebhookEventBase` class, and it overrides the `Alias` property to provide a unique identifier for the event. The `WebhookEventAttribute` is applied to the class to specify the event name and type. ```csharp [WebhookEvent("Your Custom Event", "CustomEventType")] @@ -111,7 +111,7 @@ public class YourCustomEvent : WebhookEventBase ## Creating an Event with the WebhookEventContentBase\ -For scenarios where your webhook event is content-specific, Umbraco provides another base class: `WebhookEventContentBase`. This class is an extension of the generic `WebhookEventBase` and introduces content-related functionalities. +For scenarios where the webhook event is content-specific, Umbraco provides another base class: `WebhookEventContentBase`. This class is an extension of the generic `WebhookEventBase` and introduces content-related functionalities. The `WebhookEventContentBase` class is designed for content-specific webhook events, where `TEntity` is expected to be a type that implements the `IContentBase` interface. @@ -131,23 +131,21 @@ To leverage the `WebhookEventContentBase` class, follow * **GetEntitiesFromNotification**: Implement this method to extract content entities from the notification. * **ConvertEntityToRequestPayload**: Implement this method to customize the content entity payload before sending it to webhooks. - If we take a look at the `ContentPublishedWebhookEvent`, we can see how these methods are overridden. - -{% include "../../.gitbook/includes/obsolete-warning-ipublishedsnapshotaccessor.md" %} + The `ContentPublishedWebhookEvent` class demonstrates how these methods are overridden. ```csharp protected override IEnumerable GetEntitiesFromNotification(ContentPublishedNotification notification) => notification.PublishedEntities; protected override object? ConvertEntityToRequestPayload(IContent entity) { - if (_publishedSnapshotAccessor.TryGetPublishedSnapshot(out IPublishedSnapshot? publishedSnapshot) is false || publishedSnapshot!.Content is null) - { - return null; - } + var cachedPublishedContent = publishedContentCache.GetById(entity.Key); - IPublishedContent? publishedContent = publishedSnapshot.Content.GetById(entity.Key); - return publishedContent is null ? null : _apiContentBuilder.Build(publishedContent); - } + return new + { + CustomData = "Your data", + PublishedContent = cachedPublishedContent is null ? null : apiContentBuilder.Build(cachedPublishedContent) + }; +} ``` 3. **ProcessWebhooks Implementation**: diff --git a/16/umbraco-cms/reference/content-delivery-api/custom-property-editors-support.md b/16/umbraco-cms/reference/content-delivery-api/custom-property-editors-support.md index 789bfaf844f..2b7c0bcb159 100644 --- a/16/umbraco-cms/reference/content-delivery-api/custom-property-editors-support.md +++ b/16/umbraco-cms/reference/content-delivery-api/custom-property-editors-support.md @@ -1,26 +1,25 @@ --- description: >- - Discover how to customize the Content Delivery API's response for your custom - property editors. + Discover how to customize the Content Delivery API's response for your custom property editors. --- # Custom property editors support -Out of the box, the Delivery API supports custom property editors, ensuring they are rendered alongside the built-in ones in Umbraco. However, if the output generated by your property editor isn't optimal for a headless context, you have the ability to customize the API response. This customization won't impact the Razor rendering, allowing you to tailor the Content Delivery API response according to your specific requirements. +Out of the box, the Delivery API supports custom property editors, ensuring they are rendered alongside the built-in ones in Umbraco. However, if the output generated by your property editor isn't optimal for a headless context, developers can customize the API response. This customization won't impact the Razor rendering, allowing tailored Content Delivery API responses that meet specific requirements. -In this article, we'll look into how you can work with the `IDeliveryApiPropertyValueConverter` interface and implement custom [property expansion](./property-expansion-and-limiting.md) for your custom property editors. +This article discusses how to work with the `IDeliveryApiPropertyValueConverter` interface and implement custom [property expansion](./property-expansion-and-limiting.md) for custom property editors. ## Prerequisite The examples in this article revolve around the fictional `My.Custom.Picker` property editor. This property editor stores the key of a single content item and is backed by a property value converter. -We will not dive into the details of creating a custom property editor for Umbraco in this article. If you need guidance on that, please refer to the [Creating a Property Editor](../../tutorials/creating-a-property-editor/README.md) and [Property Value Converters](../../customizing/property-editors/property-value-converters.md) articles. +If you need guidance on creating a custom property editor, please refer to the [Creating a Property Editor](../../tutorials/creating-a-property-editor/README.md) and [Property Value Converters](../../customizing/property-editors/property-value-converters.md) articles. ## Implementation -To customize the output of a property value editor in the Delivery API, we need to opt-in by implementing the `IDeliveryApiPropertyValueConverter` interface. +To customize the output of a property value editor in the Delivery API, opt-in by implementing the `IDeliveryApiPropertyValueConverter` interface. -The code example below showcases the implementation of this interface in the property value converter for `My.Custom.Picker`. Our focus will be on the methods provided by the `IDeliveryApiPropertyValueConverter`, as they are responsible for customizing the Delivery API response. +The code example below showcases the implementation of this interface in the property value converter for `My.Custom.Picker`. These code samples focus on the methods provided by the `IDeliveryApiPropertyValueConverter`, which are responsible for customizing the Delivery API response. Towards the end of the example, you will find the response models that we will be using. diff --git a/16/umbraco-cms/reference/webhooks/README.md b/16/umbraco-cms/reference/webhooks/README.md index ea50ad29dd9..c0eb3cae5e4 100644 --- a/16/umbraco-cms/reference/webhooks/README.md +++ b/16/umbraco-cms/reference/webhooks/README.md @@ -4,10 +4,9 @@ description: Umbraco webhooks enable seamless integration and real-time updates # Webhooks -Webhooks provide real-time, event-driven communication within Umbraco. They enable external services to react to content changes instantly by sending HTTP requests when specific events occur. This allows you to integrate with third-party services, automate workflows, and synchronize data effortlessly. +Webhooks provide real-time, event-driven communication within Umbraco. They enable external services to react to content changes instantly by sending HTTP requests when specific events occur. This allows developers to integrate with third-party services, automate workflows, and synchronize data effortlessly. ## Getting Started - To manage webhooks, navigate to **Settings > Webhooks** in the Umbraco backoffice. ![Webhooks section](images/webhook-section-v14.png) @@ -17,13 +16,10 @@ To create a webhook, click **Create**. This opens the webhook creation screen wh ![Creating a webhook](images/create-webhook-v14.png) ## Configuring a Webhook - ### URL - The `Url` is the endpoint where the webhook will send an HTTP request when the selected event is triggered. Ensure this endpoint is publicly accessible and capable of handling incoming requests. ### Events - Webhooks are triggered by specific events in Umbraco. By default, the following events are available: | Event Name | Description | @@ -35,37 +31,31 @@ Webhooks are triggered by specific events in Umbraco. By default, the following | Media Saved | Fires when a media item is saved. | ### Content Type Filtering - -For **Content** or **Media** events, you can specify whether the webhook should trigger for all content types or only specific ones. This is useful when you only need webhooks for certain document types, such as blog posts or products. +For **Content** or **Media** events, developers can specify whether the webhook should trigger for all content types or only specific ones. This is useful when activating webhooks for certain document types, such as blog posts or products. ### Custom Headers - -You can define custom HTTP headers that will be included in the webhook request. Common use cases include: +Developers can define custom HTTP headers that will be included in the webhook request. Common use cases include: - Specifying request format: `Accept: application/json` - Adding authentication tokens: `Authorization: Bearer ` - Including security headers ## Default Behavior of Umbraco Webhooks - Umbraco webhooks come with predefined settings and behaviors. ### JSON Payload - Each webhook event sends a JSON payload. The following types of payloads are available by default. #### Legacy - This is the current default but will be removed in a future version. Legacy payloads follow the format used before version 16. They are inconsistent and may include data that should not be exposed or has been superseded (e.g., use of `int` instead of `Guid`). + #### Minimal +This will become the default in version 18 and later. Minimal payloads include only essential information to identify the resource. For most events, this means a unique identifier. Some events may include additional data. For example, a document publish event also includes the list of published cultures. -This will become the default in version 17 and later. Minimal payloads include only essential information to identify the resource. For most events, this means a unique identifier. Some events may include additional data. For example, a document publish event also includes the list of published cultures. #### Extended - Extended payloads include all relevant information for an event, where available. However, sensitive data, such as usernames, member names, or email addresses, is excluded for privacy and security reasons. If an extended payload is not available for an event, the system falls back to the minimal payload. ### Configuring Payload Types - Payload type can be configured in the following ways: - Changing the appsetting `Umbraco:CMS:Webhook:PayloadType`. Be aware that the system that uses this value runs before any composers. If you manipulate the `WebhookEventCollectionBuilder` in any way, then those methods will not automatically pick up this app setting. @@ -165,50 +155,53 @@ builder.WebhookEvents().Clear().AddCms(false); ### Replacing Webhook Events -You can modify existing webhook events, such as changing the payload format, by creating a custom implementation: +Developers can modify existing webhook events, such as changing the payload format, by creating a custom implementation: ```csharp +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DeliveryApi; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Notifications; +using Umbraco.Cms.Core.PublishedCache; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Sync; +using Umbraco.Cms.Core.Webhooks; + +namespace CommunityDocs.Controllers; + [WebhookEvent("Content Published", Constants.WebhookEvents.Types.Content)] -public class MyCustomContentPublishedWebhookEvent : WebhookEventContentBase +public class MyCustomContentPublishedWebhookEvent( + IWebhookFiringService webhookFiringService, + IWebhookService webhookService, + IOptionsMonitor webhookSettings, + IServerRoleAccessor serverRoleAccessor, + IApiContentBuilder apiContentBuilder, + IPublishedContentCache publishedContentCache): + WebhookEventContentBase(webhookFiringService, webhookService, webhookSettings, serverRoleAccessor) { - private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; - private readonly IApiContentBuilder _apiContentBuilder; - - public MyCustomContentPublishedWebhookEvent( - IWebhookFiringService webhookFiringService, - IWebhookService webhookService, - IOptionsMonitor webhookSettings, - IServerRoleAccessor serverRoleAccessor, - IPublishedSnapshotAccessor publishedSnapshotAccessor, - IApiContentBuilder apiContentBuilder) - : base(webhookFiringService, webhookService, webhookSettings, serverRoleAccessor) - { - _publishedSnapshotAccessor = publishedSnapshotAccessor; - _apiContentBuilder = apiContentBuilder; - } - public override string Alias => "Umbraco.ContentPublish"; protected override IEnumerable GetEntitiesFromNotification(ContentPublishedNotification notification) => notification.PublishedEntities; protected override object? ConvertEntityToRequestPayload(IContent entity) { - if (_publishedSnapshotAccessor.TryGetPublishedSnapshot(out IPublishedSnapshot? publishedSnapshot) is false || publishedSnapshot!.Content is null) - { - return null; - } - - IPublishedContent? publishedContent = publishedSnapshot.Content.GetById(entity.Key); + var cachedPublishedContent = publishedContentCache.GetById(entity.Key); return new { CustomData = "Your data", - PublishedContent = publishedContent is null ? null : _apiContentBuilder.Build(publishedContent) + PublishedContent = cachedPublishedContent is null ? null : apiContentBuilder.Build(cachedPublishedContent) }; } } ``` -To replace the default Umbraco webhook with your custom implementation: +{% hint style="info" %} +Umbraco developers need to inject `IPublishedContentCache`, `IPublishedMediaCache`, `IPublishedMemberCache`, and `IPublishedContentTypeCache` individually, instead of injecting the `IPublishedSnapshotAccessor` as in previous versions. +{% endhint %} + +The code below shows an example that replaces the default Umbraco webhook with a custom implementation: ```csharp public class MyComposer : IComposer @@ -224,19 +217,24 @@ public class MyComposer : IComposer Webhook settings are configured in `appsettings.*.json` under `Umbraco::CMS`: +{% code title="appsettings.json" %} ```json -"Umbraco": { - "CMS": { - "Webhook": { - "Enabled": true, - "MaximumRetries": 5, - "Period": "00:00:10", - "EnableLoggingCleanup": true, - "KeepLogsForDays": 30 +{ + "$schema": "appsettings-schema.json", + "Umbraco": { + "CMS": { + "Webhook": { + "Enabled": true, + "MaximumRetries": 5, + "Period": "00:00:10", + "EnableLoggingCleanup": true, + "KeepLogsForDays": 30 + } + } } - } } ``` +{% endcode %} | Setting | Description | |---------|-------------| @@ -248,4 +246,4 @@ Webhook settings are configured in `appsettings.*.json` under `Umbraco::CMS`: ## Testing Webhooks -Use [Beeceptor](https://beeceptor.com/) or [RequestBin](https://pipedream.com/requestbin) to test your event trigger integrations before deploying them to production. +Use [Beeceptor](https://beeceptor.com/) or [RequestBin](https://pipedream.com/requestbin) to test the event trigger integrations before deploying them to production. diff --git a/16/umbraco-cms/reference/webhooks/expanding-webhook-events.md b/16/umbraco-cms/reference/webhooks/expanding-webhook-events.md index 796353ba746..b29a9fab774 100644 --- a/16/umbraco-cms/reference/webhooks/expanding-webhook-events.md +++ b/16/umbraco-cms/reference/webhooks/expanding-webhook-events.md @@ -1,22 +1,21 @@ --- description: >- - Explore new webhook event options, detailed setup, specific content triggers, - and improved logging and retry mechanisms + Explore new webhook event options, detailed setup, specific content triggers, and improved logging and retry mechanisms. --- # Expanding Webhook Events ## Introduction -With Umbraco, you can create your own webhook events. +Umbraco developers can create their own webhook events. -This documentation guides you through the process of implementing your webhook events using the `WebhookEventBase` base class. +This article demonstrates the process of implementing custom webhook events using the `WebhookEventBase` base class. ## Creating an Event with the WebhookEventBase The `WebhookEventBase` class serves as the foundation for creating custom webhook events. Here's a brief overview of its key components: -* **Alias**: The property that must be overridden to provide a unique identifier for your webhook event. +* **Alias**: The property that must be overridden to provide a unique identifier for the webhook event. * **EventName**: A property that represents the name of the event. It is automatically set based on the provided alias unless explicitly specified. * **EventType**: A property that categorizes the event type. It defaults to "Others" but can be customized using the `WebhookEventAttribute`. * **WebhookSettings**: The property containing the current webhook settings. @@ -38,14 +37,14 @@ To create a custom webhook event, follow these steps: ``` 2. **Override the Alias Property**: - Provide a unique identifier for your event using the `Alias` property: + Provide a unique identifier for the event using the `Alias` property: ```csharp public override string Alias => "YourUniqueAlias"; ``` 3. **Apply `WebhookEventAttribute` (Optional)**: - You can use the `WebhookEventAttribute` to specify the event name and type. Apply this attribute to your custom event class: + Use the `WebhookEventAttribute` to specify the event name and type. Apply this attribute to the custom event class: ```csharp [WebhookEvent("Your Event Name", "YourEventType")] @@ -55,14 +54,14 @@ To create a custom webhook event, follow these steps: } ``` - Umbraco already has some types as constants, which you can find at `Constants.WebhookEvents.Types`.\ - If you do not specify this attribute, the event name will default to your alias, and the type will default to `Other`. + Umbraco already has some types as constants, which you can find at `Constants.WebhookEvents.Types`. If this attribute is not specified, the event name will default to the alias, and the type will default to `Other`. +4. 4. **Implement Notification Handling**: If needed, customize the handling of the notification in the `HandleAsync` method. 5. **Register Your Webhook Event**: - Ensure that Umbraco is aware of your custom event by registering it in a composer: + Ensure that Umbraco is aware of the custom event by registering it in a composer: ```csharp using Umbraco.Cms.Core.Composing; @@ -75,12 +74,11 @@ To create a custom webhook event, follow these steps: } } ``` -6. **Implement Optional Overrides**:\ - Depending on your requirements, you can override methods such as `ConvertNotificationToRequestPayload` and `ShouldFireWebhookForNotification` to customize the behavior of your webhook event. +6. **Implement Optional Overrides**: Depending on requirements, methods such as `ConvertNotificationToRequestPayload` and `ShouldFireWebhookForNotification` can be overridden to customize the behavior of the webhook event. ### Sample Implementation -Here's a basic example of a custom webhook event: +The code below shows a sample implementation of a custom webhook event. The `YourCustomEvent` class is derived from the `WebhookEventBase` class, and it overrides the `Alias` property to provide a unique identifier for the event. The `WebhookEventAttribute` is applied to the class to specify the event name and type. ```csharp [WebhookEvent("Your Custom Event", "CustomEventType")] @@ -113,7 +111,7 @@ public class YourCustomEvent : WebhookEventBase ## Creating an Event with the WebhookEventContentBase\ -For scenarios where your webhook event is content-specific, Umbraco provides another base class: `WebhookEventContentBase`. This class is an extension of the generic `WebhookEventBase` and introduces content-related functionalities. +For scenarios where the webhook event is content-specific, Umbraco provides another base class: `WebhookEventContentBase`. This class is an extension of the generic `WebhookEventBase` and introduces content-related functionalities. The `WebhookEventContentBase` class is designed for content-specific webhook events, where `TEntity` is expected to be a type that implements the `IContentBase` interface. @@ -133,23 +131,21 @@ To leverage the `WebhookEventContentBase` class, follow * **GetEntitiesFromNotification**: Implement this method to extract content entities from the notification. * **ConvertEntityToRequestPayload**: Implement this method to customize the content entity payload before sending it to webhooks. - If we take a look at the `ContentPublishedWebhookEvent`, we can see how these methods are overridden. - -{% include "../../.gitbook/includes/obsolete-warning-ipublishedsnapshotaccessor.md" %} + The `ContentPublishedWebhookEvent` class demonstrates how these methods are overridden. ```csharp protected override IEnumerable GetEntitiesFromNotification(ContentPublishedNotification notification) => notification.PublishedEntities; protected override object? ConvertEntityToRequestPayload(IContent entity) { - if (_publishedSnapshotAccessor.TryGetPublishedSnapshot(out IPublishedSnapshot? publishedSnapshot) is false || publishedSnapshot!.Content is null) - { - return null; - } + var cachedPublishedContent = publishedContentCache.GetById(entity.Key); - IPublishedContent? publishedContent = publishedSnapshot.Content.GetById(entity.Key); - return publishedContent is null ? null : _apiContentBuilder.Build(publishedContent); - } + return new + { + CustomData = "Your data", + PublishedContent = cachedPublishedContent is null ? null : apiContentBuilder.Build(cachedPublishedContent) + }; +} ``` 3. **ProcessWebhooks Implementation**: diff --git a/17/umbraco-cms/reference/webhooks/README.md b/17/umbraco-cms/reference/webhooks/README.md index ea50ad29dd9..c0eb3cae5e4 100644 --- a/17/umbraco-cms/reference/webhooks/README.md +++ b/17/umbraco-cms/reference/webhooks/README.md @@ -4,10 +4,9 @@ description: Umbraco webhooks enable seamless integration and real-time updates # Webhooks -Webhooks provide real-time, event-driven communication within Umbraco. They enable external services to react to content changes instantly by sending HTTP requests when specific events occur. This allows you to integrate with third-party services, automate workflows, and synchronize data effortlessly. +Webhooks provide real-time, event-driven communication within Umbraco. They enable external services to react to content changes instantly by sending HTTP requests when specific events occur. This allows developers to integrate with third-party services, automate workflows, and synchronize data effortlessly. ## Getting Started - To manage webhooks, navigate to **Settings > Webhooks** in the Umbraco backoffice. ![Webhooks section](images/webhook-section-v14.png) @@ -17,13 +16,10 @@ To create a webhook, click **Create**. This opens the webhook creation screen wh ![Creating a webhook](images/create-webhook-v14.png) ## Configuring a Webhook - ### URL - The `Url` is the endpoint where the webhook will send an HTTP request when the selected event is triggered. Ensure this endpoint is publicly accessible and capable of handling incoming requests. ### Events - Webhooks are triggered by specific events in Umbraco. By default, the following events are available: | Event Name | Description | @@ -35,37 +31,31 @@ Webhooks are triggered by specific events in Umbraco. By default, the following | Media Saved | Fires when a media item is saved. | ### Content Type Filtering - -For **Content** or **Media** events, you can specify whether the webhook should trigger for all content types or only specific ones. This is useful when you only need webhooks for certain document types, such as blog posts or products. +For **Content** or **Media** events, developers can specify whether the webhook should trigger for all content types or only specific ones. This is useful when activating webhooks for certain document types, such as blog posts or products. ### Custom Headers - -You can define custom HTTP headers that will be included in the webhook request. Common use cases include: +Developers can define custom HTTP headers that will be included in the webhook request. Common use cases include: - Specifying request format: `Accept: application/json` - Adding authentication tokens: `Authorization: Bearer ` - Including security headers ## Default Behavior of Umbraco Webhooks - Umbraco webhooks come with predefined settings and behaviors. ### JSON Payload - Each webhook event sends a JSON payload. The following types of payloads are available by default. #### Legacy - This is the current default but will be removed in a future version. Legacy payloads follow the format used before version 16. They are inconsistent and may include data that should not be exposed or has been superseded (e.g., use of `int` instead of `Guid`). + #### Minimal +This will become the default in version 18 and later. Minimal payloads include only essential information to identify the resource. For most events, this means a unique identifier. Some events may include additional data. For example, a document publish event also includes the list of published cultures. -This will become the default in version 17 and later. Minimal payloads include only essential information to identify the resource. For most events, this means a unique identifier. Some events may include additional data. For example, a document publish event also includes the list of published cultures. #### Extended - Extended payloads include all relevant information for an event, where available. However, sensitive data, such as usernames, member names, or email addresses, is excluded for privacy and security reasons. If an extended payload is not available for an event, the system falls back to the minimal payload. ### Configuring Payload Types - Payload type can be configured in the following ways: - Changing the appsetting `Umbraco:CMS:Webhook:PayloadType`. Be aware that the system that uses this value runs before any composers. If you manipulate the `WebhookEventCollectionBuilder` in any way, then those methods will not automatically pick up this app setting. @@ -165,50 +155,53 @@ builder.WebhookEvents().Clear().AddCms(false); ### Replacing Webhook Events -You can modify existing webhook events, such as changing the payload format, by creating a custom implementation: +Developers can modify existing webhook events, such as changing the payload format, by creating a custom implementation: ```csharp +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DeliveryApi; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Notifications; +using Umbraco.Cms.Core.PublishedCache; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Sync; +using Umbraco.Cms.Core.Webhooks; + +namespace CommunityDocs.Controllers; + [WebhookEvent("Content Published", Constants.WebhookEvents.Types.Content)] -public class MyCustomContentPublishedWebhookEvent : WebhookEventContentBase +public class MyCustomContentPublishedWebhookEvent( + IWebhookFiringService webhookFiringService, + IWebhookService webhookService, + IOptionsMonitor webhookSettings, + IServerRoleAccessor serverRoleAccessor, + IApiContentBuilder apiContentBuilder, + IPublishedContentCache publishedContentCache): + WebhookEventContentBase(webhookFiringService, webhookService, webhookSettings, serverRoleAccessor) { - private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; - private readonly IApiContentBuilder _apiContentBuilder; - - public MyCustomContentPublishedWebhookEvent( - IWebhookFiringService webhookFiringService, - IWebhookService webhookService, - IOptionsMonitor webhookSettings, - IServerRoleAccessor serverRoleAccessor, - IPublishedSnapshotAccessor publishedSnapshotAccessor, - IApiContentBuilder apiContentBuilder) - : base(webhookFiringService, webhookService, webhookSettings, serverRoleAccessor) - { - _publishedSnapshotAccessor = publishedSnapshotAccessor; - _apiContentBuilder = apiContentBuilder; - } - public override string Alias => "Umbraco.ContentPublish"; protected override IEnumerable GetEntitiesFromNotification(ContentPublishedNotification notification) => notification.PublishedEntities; protected override object? ConvertEntityToRequestPayload(IContent entity) { - if (_publishedSnapshotAccessor.TryGetPublishedSnapshot(out IPublishedSnapshot? publishedSnapshot) is false || publishedSnapshot!.Content is null) - { - return null; - } - - IPublishedContent? publishedContent = publishedSnapshot.Content.GetById(entity.Key); + var cachedPublishedContent = publishedContentCache.GetById(entity.Key); return new { CustomData = "Your data", - PublishedContent = publishedContent is null ? null : _apiContentBuilder.Build(publishedContent) + PublishedContent = cachedPublishedContent is null ? null : apiContentBuilder.Build(cachedPublishedContent) }; } } ``` -To replace the default Umbraco webhook with your custom implementation: +{% hint style="info" %} +Umbraco developers need to inject `IPublishedContentCache`, `IPublishedMediaCache`, `IPublishedMemberCache`, and `IPublishedContentTypeCache` individually, instead of injecting the `IPublishedSnapshotAccessor` as in previous versions. +{% endhint %} + +The code below shows an example that replaces the default Umbraco webhook with a custom implementation: ```csharp public class MyComposer : IComposer @@ -224,19 +217,24 @@ public class MyComposer : IComposer Webhook settings are configured in `appsettings.*.json` under `Umbraco::CMS`: +{% code title="appsettings.json" %} ```json -"Umbraco": { - "CMS": { - "Webhook": { - "Enabled": true, - "MaximumRetries": 5, - "Period": "00:00:10", - "EnableLoggingCleanup": true, - "KeepLogsForDays": 30 +{ + "$schema": "appsettings-schema.json", + "Umbraco": { + "CMS": { + "Webhook": { + "Enabled": true, + "MaximumRetries": 5, + "Period": "00:00:10", + "EnableLoggingCleanup": true, + "KeepLogsForDays": 30 + } + } } - } } ``` +{% endcode %} | Setting | Description | |---------|-------------| @@ -248,4 +246,4 @@ Webhook settings are configured in `appsettings.*.json` under `Umbraco::CMS`: ## Testing Webhooks -Use [Beeceptor](https://beeceptor.com/) or [RequestBin](https://pipedream.com/requestbin) to test your event trigger integrations before deploying them to production. +Use [Beeceptor](https://beeceptor.com/) or [RequestBin](https://pipedream.com/requestbin) to test the event trigger integrations before deploying them to production. diff --git a/17/umbraco-cms/reference/webhooks/expanding-webhook-events.md b/17/umbraco-cms/reference/webhooks/expanding-webhook-events.md index 796353ba746..b29a9fab774 100644 --- a/17/umbraco-cms/reference/webhooks/expanding-webhook-events.md +++ b/17/umbraco-cms/reference/webhooks/expanding-webhook-events.md @@ -1,22 +1,21 @@ --- description: >- - Explore new webhook event options, detailed setup, specific content triggers, - and improved logging and retry mechanisms + Explore new webhook event options, detailed setup, specific content triggers, and improved logging and retry mechanisms. --- # Expanding Webhook Events ## Introduction -With Umbraco, you can create your own webhook events. +Umbraco developers can create their own webhook events. -This documentation guides you through the process of implementing your webhook events using the `WebhookEventBase` base class. +This article demonstrates the process of implementing custom webhook events using the `WebhookEventBase` base class. ## Creating an Event with the WebhookEventBase The `WebhookEventBase` class serves as the foundation for creating custom webhook events. Here's a brief overview of its key components: -* **Alias**: The property that must be overridden to provide a unique identifier for your webhook event. +* **Alias**: The property that must be overridden to provide a unique identifier for the webhook event. * **EventName**: A property that represents the name of the event. It is automatically set based on the provided alias unless explicitly specified. * **EventType**: A property that categorizes the event type. It defaults to "Others" but can be customized using the `WebhookEventAttribute`. * **WebhookSettings**: The property containing the current webhook settings. @@ -38,14 +37,14 @@ To create a custom webhook event, follow these steps: ``` 2. **Override the Alias Property**: - Provide a unique identifier for your event using the `Alias` property: + Provide a unique identifier for the event using the `Alias` property: ```csharp public override string Alias => "YourUniqueAlias"; ``` 3. **Apply `WebhookEventAttribute` (Optional)**: - You can use the `WebhookEventAttribute` to specify the event name and type. Apply this attribute to your custom event class: + Use the `WebhookEventAttribute` to specify the event name and type. Apply this attribute to the custom event class: ```csharp [WebhookEvent("Your Event Name", "YourEventType")] @@ -55,14 +54,14 @@ To create a custom webhook event, follow these steps: } ``` - Umbraco already has some types as constants, which you can find at `Constants.WebhookEvents.Types`.\ - If you do not specify this attribute, the event name will default to your alias, and the type will default to `Other`. + Umbraco already has some types as constants, which you can find at `Constants.WebhookEvents.Types`. If this attribute is not specified, the event name will default to the alias, and the type will default to `Other`. +4. 4. **Implement Notification Handling**: If needed, customize the handling of the notification in the `HandleAsync` method. 5. **Register Your Webhook Event**: - Ensure that Umbraco is aware of your custom event by registering it in a composer: + Ensure that Umbraco is aware of the custom event by registering it in a composer: ```csharp using Umbraco.Cms.Core.Composing; @@ -75,12 +74,11 @@ To create a custom webhook event, follow these steps: } } ``` -6. **Implement Optional Overrides**:\ - Depending on your requirements, you can override methods such as `ConvertNotificationToRequestPayload` and `ShouldFireWebhookForNotification` to customize the behavior of your webhook event. +6. **Implement Optional Overrides**: Depending on requirements, methods such as `ConvertNotificationToRequestPayload` and `ShouldFireWebhookForNotification` can be overridden to customize the behavior of the webhook event. ### Sample Implementation -Here's a basic example of a custom webhook event: +The code below shows a sample implementation of a custom webhook event. The `YourCustomEvent` class is derived from the `WebhookEventBase` class, and it overrides the `Alias` property to provide a unique identifier for the event. The `WebhookEventAttribute` is applied to the class to specify the event name and type. ```csharp [WebhookEvent("Your Custom Event", "CustomEventType")] @@ -113,7 +111,7 @@ public class YourCustomEvent : WebhookEventBase ## Creating an Event with the WebhookEventContentBase\ -For scenarios where your webhook event is content-specific, Umbraco provides another base class: `WebhookEventContentBase`. This class is an extension of the generic `WebhookEventBase` and introduces content-related functionalities. +For scenarios where the webhook event is content-specific, Umbraco provides another base class: `WebhookEventContentBase`. This class is an extension of the generic `WebhookEventBase` and introduces content-related functionalities. The `WebhookEventContentBase` class is designed for content-specific webhook events, where `TEntity` is expected to be a type that implements the `IContentBase` interface. @@ -133,23 +131,21 @@ To leverage the `WebhookEventContentBase` class, follow * **GetEntitiesFromNotification**: Implement this method to extract content entities from the notification. * **ConvertEntityToRequestPayload**: Implement this method to customize the content entity payload before sending it to webhooks. - If we take a look at the `ContentPublishedWebhookEvent`, we can see how these methods are overridden. - -{% include "../../.gitbook/includes/obsolete-warning-ipublishedsnapshotaccessor.md" %} + The `ContentPublishedWebhookEvent` class demonstrates how these methods are overridden. ```csharp protected override IEnumerable GetEntitiesFromNotification(ContentPublishedNotification notification) => notification.PublishedEntities; protected override object? ConvertEntityToRequestPayload(IContent entity) { - if (_publishedSnapshotAccessor.TryGetPublishedSnapshot(out IPublishedSnapshot? publishedSnapshot) is false || publishedSnapshot!.Content is null) - { - return null; - } + var cachedPublishedContent = publishedContentCache.GetById(entity.Key); - IPublishedContent? publishedContent = publishedSnapshot.Content.GetById(entity.Key); - return publishedContent is null ? null : _apiContentBuilder.Build(publishedContent); - } + return new + { + CustomData = "Your data", + PublishedContent = cachedPublishedContent is null ? null : apiContentBuilder.Build(cachedPublishedContent) + }; +} ``` 3. **ProcessWebhooks Implementation**: