Author:
Lesley Dean
Changed on:
7 July 2024
`devrel.provider.rest`
Monitoring any key business system is key to ensuring the optimal and smooth running of the business itself.
Connecting many different systems is a fundamental need for order management systems, which are part of an enterprise architecture. If communication between these systems breaks down, this can cause costly impacts, such as delays in fulfilling customer orders, inaccurate data across systems, and more.
The Fluent OMX Workflow Framework supports Webhooks, which are sent via a Rule in a Workflow and tracked within the Orchestration Audit Events.
What if we could provide Support & Operations personnel with the observability of these Webhooks quickly inside a Fluent OMX web app?
This article will guide you through configuring a Webhooks Dashboard inside the Fluent OMS web app.
Webhooks are used to send information from Fluent products to external systems. These are implemented using the `SendWebhook`
Every Webhook action produced is logged in the Orchestration Audit Events, accessible via the Events screen in the Fluent OMS web app or through the Event API.
Webhooks are often an important part of an entity's lifecycle, and as such, it is important to monitor Webhooks sent by the Fluent Platform regularly to ensure that no issues occur and cause significant delays in fulfilling your customer's orders.
While you could use Events screen in the Fluent OMS web app, or even add a new page using the default
`fc.events.search`
Ideally, we configure a new Webhooks Dashboard that displays only relevant Webhook information, making it quick and simple to see if everything is working as expected.
A Webhooks Dashboard for monitoring Webhooks in Fluent OMS (Zoom Image)
Since Webhook audit information is available through the Event API, we need to be able to query the Webhook Orchestration Audit Events and present them on the screen.
In a previous article, we implemented a handy custom component that can make REST API calls and provide the results to the data property of any child components.
Let’s use this to configure a new Webhooks Dashboard.
Let’s use the existing Insights section in the Fluent OMS web app, and add a new page to build our Webhooks Dashboard.
Inside the
`fc.manifest.fragment.oms.insights.json`
`pages`
1{
2 "type": "page",
3 "path": "/devrel-webhooks-dashboard",
4 "nav": {
5 "label": "DevRel Webhooks Dashboard",
6 "icon": "MdEvent"
7 },
8 "component": "fc.page",
9 "props": {
10 "title": "DevRel Webhooks Dashboard - Updated on: {{dateStringFormatter (dateAdd)}}"
11 },
12 "descendants": [
13 {
14 "component": "fc.page.section.header",
15 "props": {
16 "title": "Webhooks - Last 24 Hours"
17 }
18 }
19 ]
20}
Language: json
Name: Webhooks Dashboard Page Config
Description:
Manifest Configuration for the Webhooks Dashboard page
The snippet above defines a new page on path
`devrel-webhooks-dashboard`
`fc.page`
Additionally, it sets the
`nav`
We’ll use a custom provider component to query the Event API for Webhook Action Audit Events.
Inside the
`descendants`
`fc.page`
1{
2 "component": "devrel.provider.rest",
3 "props": {
4 "endpoint": "api/v4.1/event",
5 "props": {
6 "name": "Send Webhook",
7 "category": "ACTION",
8 "from": "{{dateStringFormatter (dateSubtract hours=24) 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' true}}"
9 }
10 },
11 "descendants": [
12 /* Children */
13 ]
14}
Language: json
Name: Configure the REST Data Provider Component
Description:
Adding the REST Data Provider Component manifest configuration to the Webhooks Dashboard page
In this snippet, we’ve configured the
`devrel.provider.rest`
`props`
To retrieve the Audit events for Webhooks, we query the Event API for Events with a name of “Send Webhook”, and a category of “ACTION”. Additionally, we’ll query the last 24 hours by setting the
`from`
Let’s start with something simple, and display a Dashboard Threshold tile to display the total number of Webhooks sent in the last 24 hours.
Add the following snippet to the descendants of the
`devrel.provider.rest`
1{
2 "component": "fc.dashboard.threshold",
3 "props": {
4 "label": "Sent",
5 "value": "{{results.length}}"
6 }
7}
Language: json
Name: Dashboard Threshold Tile configuration
Description:
Configuring the first Dashboard Threshold Tile with REST based data
To display the count, we simply set the value to the results array length.
A Standard Dashboard Threshold Tile Component showing the total Webhooks sent in the last 24 hours
Now, let’s make it more interesting, and add a list. Since we are displaying Webhook Action events only, we can configure this list to display the standard Webhook Event Attributes, which gives us access to details about the Webhook Request, Response, and any Exceptions that may have occurred.
Here is an example of a Webhook Action Audit Event:
1{
2 "id": "80341b8d-66cc-4619-8e6f-dc458d5a4758",
3 "name": "Send Webhook",
4 "type": "ORCHESTRATION_AUDIT",
5 "accountId": "FCTRAINAU1251",
6 "retailerId": "1",
7 "category": "ACTION",
8 "context": {
9 "sourceEvents": [
10 "a5f02716-eb0f-11ee-946a-dbc474cefc67"
11 ],
12 "entityType": "ORDER",
13 "entityId": "980",
14 "entityRef": "HD_7323",
15 "rootEntityType": "ORDER",
16 "rootEntityId": "980",
17 "rootEntityRef": "HD_7323"
18 },
19 "eventStatus": "SUCCESS",
20 "attributes": [
21 {
22 "name": "Request Endpoint",
23 "value": "https://39e52e0a-eef8-4349-aafa-a9ec213c1d5a.mock.pstmn.io/OrderStatusUpdateNotification",
24 "type": "STRING"
25 },
26 {
27 "name": "Request Headers",
28 "value": "flex.signature=[CahPe2zhT/jNCHuIW0urQyWCNXogdcEQQPdMD6bvD5I4CQHAQbqRWRgyzJaLtPYANVodGrtgiTcS0/0PJb5jLxuRDuXrWrBVRTmHqQ8iFIIYnKNgwm2utjLWIuK3aBnz7hhIugdgMjEKLsakeIT5n+3fOttV1n/f2nQomxXokJs=]&fluent-signature=[Owv+GbBHMGt2txPtmzOAT7xfudvg5bgZsRlUV0aDTCLFmNrxDPZKejE1rWKbW7FCJ8FNrAeO5/6tnpFLQJWg6ggCAo+9DfguSoJ8sgP25JvlJgcp4P5I+qzxHVTQdvIJ33NKT7Xei1PDFgZdH6IA9P6C3hnztzRgvX0qxnaFcVQ=]&Content-Type=[application/json]",
29 "type": "STRING"
30 },
31 {
32 "name": "Response Body",
33 "value": "{ \"message\": \"Notify: I'm a Tea Pot\" }",
34 "type": "STRING"
35 },
36 {
37 "name": "Response Headers",
38 "value": "Access-Control-Allow-Origin=[*]&Connection=[keep-alive]&X-RateLimit-Reset=[1711416354]&Date=[Tue, 26 Mar 2024 01:25:06 GMT]&X-RateLimit-Remaining=[117]&ETag=[W/\"26-b/Z+NSe+HrEYTJHVYWLGXtxbT5I\"]&Vary=[Accept-Encoding]&X-RateLimit-Limit=[120]&x-srv-span=[v=1;s=893426db16f1d71d]&x-srv-trace=[v=1;t=542a937ae712a09a]&Content-Length=[38]&Content-Type=[text/html; charset=utf-8]",
39 "type": "STRING"
40 },
41 {
42 "name": "Response code",
43 "value": 418,
44 "type": "INTEGER"
45 },
46 {
47 "name": "Response reason",
48 "value": "I'm a Teapot",
49 "type": "STRING"
50 },
51 {
52 "name": "startTimer",
53 "value": 1711416305945,
54 "type": "STRING"
55 },
56 {
57 "name": "stopTimer",
58 "value": 1711416306667,
59 "type": "STRING"
60 }
61 ],
62 "source": "-626199502.FulfilmentAssigned",
63 "generatedBy": "Rubix User",
64 "generatedOn": "2024-03-26T01:25:06.667+00:00"
65}
Language: json
Name: Sample Webhook Action Audit Event JSON
Description:
Example of the Webhook Action Orchestration Audit Event
There is lots of useful information here. As with any Orchestration Audit Event, we can see the Retailer Id, the Entity information, which tells use which specific entity the Webhook was for, the timestamp of when the event was generated, and the start and stop timer Event Attributes which tell us how long the Action ran for. We can use the latter 2 attributes to display the duration of time that the webhook request took to execute.
We also see the Webhook specific Request and Response Event attributes. Let’s first add the basic context fields to a list:
1{
2 "component": "fc.list",
3 "props": {
4 "title": "Webhooks",
5 "dataSource": "results",
6 "responsiveness": "card",
7 "attributes": [
8 {
9 "label": "Timestamp",
10 "value": "{{dateStringFormatter generatedOn 'YYYY-MM-DD HH:mm:ss.SSS' true}}"
11 },
12 {
13 "label": "Entity Info",
14 "value": "{{context.rootEntityType}}: {{context.rootEntityRef}} - {{context.entityType}}: {{context.entityRef}}"
15 },
16 {
17 "label": "Response Time",
18 "value": "{{subtract attributes.byName.stopTimer attributes.byName.startTimer}}ms"
19 },
20 {
21 "label": "Retailer Id",
22 "value": "{{retailerId}}"
23 }
24 ]
25 }
26}
Language: json
Name: Webhooks list manifest configuration
Description:
Configure the Webhooks Dashboard List
Notice how we’re formatting the
`generatedOn`
We’re printing the Root Entity and Entity information in a single column.
Next, we’re using a Template helper function to calculated the Response Time, and finally, we’re displaying the Retailer Id, which is helpful for differentiating which Retailer context is being used in multi-retailer accounts.
Initial Webhooks list configured with Event Context (Zoom Image)
Now let’s add some of the Webhook specific attributes to display in the list. The most useful attributes to display in the list might be “Request Endpoint”, the “Response code”, and the “Response reason“.
We can use the
`byName`
`byName`
Thankfully, the Component SDK
`decorateQueryResult`
`byName`
1// To access an attribute with a space in the name using the 'byName' accessor,
2// simply remove the space.
3
4// For example: For an attribute named 'Request Endpoint':
5
6{{attributes.byName.ResponseEndpoint}}
Language: json
Name: Syntax for `byName` accessor for Attributes with spaces in the name
Description:
[Warning: empty required content area]The
`devrel.provider.rest`
`decorateQueryResult`
Let’s add a column for the endpoint:
1{
2 "label": "Request Endpoint",
3 "value": "{{attributes.byName.RequestEndpoint}}"
4}
Language: json
Name: Endpoint Column config
Description:
Configuration for the Webhook Endpoint column in the List
And then let’s put the Response code and reason in one column like this:
1{
2 "label": "Response Code - Reason",
3 "template": "{{attributes.byName.Responsecode}} - {{attributes.byName.Responsereason}}"
4}
Language: json
Name: Response Code - Reason column
Description:
Configuration for the Webhook Response Code and Reason column in the List
The list component configuration should now look like this:
1{
2 "component": "fc.list",
3 "props": {
4 "title": "Webhooks",
5 "dataSource": "results",
6 "responsiveness": "card",
7 "attributes": [
8 {
9 "label": "Timestamp",
10 "value": "{{dateStringFormatter generatedOn 'YYYY-MM-DD HH:mm:ss.SSS' true}}"
11 },
12 {
13 "label": "Entity Info",
14 "value": "{{context.rootEntityType}}: {{context.rootEntityRef}} - {{context.entityType}}: {{context.entityRef}}"
15 },
16 {
17 "label": "Request Endpoint",
18 "value": "{{attributes.byName.RequestEndpoint}}"
19 },
20 {
21 "label": "Response Code - Reason",
22 "template": "{{attributes.byName.Responsecode}} - {{attributes.byName.Responsereason}}"
23 },
24 {
25 "label": "Response Time",
26 "value": "{{subtract attributes.byName.stopTimer attributes.byName.startTimer}}ms"
27 },
28 {
29 "label": "Retailer Id",
30 "value": "{{retailerId}}"
31 }
32 ]
33 }
34}
Language: json
Name: Webhooks List Configuration
Description:
Webhooks List Configuration
Webhooks List with Webhook specific Attributes (Zoom Link)
Our list is now displaying some valuable information about the webhooks that have occurred in the last 24 hours. This is great… but we could make it even easier to identify problems by using some styling on the Response Code - Reason column.
To do this, we can use the options object of the list attribute and use the styles array to set conditional styling based on the values of the Response code.
Each style declaration can take a value and a matches property, which allows us to configure the conditions. Now instead of setting a style for each and every error response, we can make the default colour red, and just add a matches for the success response codes (200, 202, and 204).
1"options": {
2 "styles": [
3 {
4 "value": "{{attributes.byName.Responsecode}}",
5 "matches": ["200", "202", "204"],
6 "icon": { "name": "MdCheckCircle", "colour": "success" },
7 "text": { "color": "success" }
8 },
9 {
10 "value": "{{attributes.byName.Responsecode}}",
11 "icon": { "name": "MdError", "colour": "error" },
12 "text": { "color": "error" }
13 }
14 ]
15}
Language: json
Name: Styling the Response Code - Reason column
Description:
Configure Conditional Styling on the Response Code - Reason column
Notice that we can use the standard Material Icons by prefixing with the “Md” and then the icon name. You can search Material Symbols and Icons available here.
This makes it really easy to see the errors stand out at a glance:
Webhooks List with conditional styling on Response Code - Reason column (Zoom Image)
When there are errors, it is useful to be able to see more information quickly. To handle this, let’s add a right drawer component to show more details from the Webhook Action event.
The Component Library comes with a
`fc.drawer.button`
So to complete our Webhooks Dashboard page, let’s use 3 standard attribute cards to display the Request details, Response details, and Exception details in the drawer respectively.
Add the following snippet as the last column in the Webhooks list:
1{
2 "label": "Webhook Details",
3 "type": "component",
4 "options": {
5 "component": "fc.drawer.button",
6 "props": {
7 "label": "Details",
8 "title": "Webhook Details",
9 "descendants": [
10 {
11 "component": "fc.card.attribute",
12 "props": {
13 "title": "Request Details",
14 "attributes": [
15 {
16 "label": "Request Endpoint",
17 "value": "{{attributes.byName.RequestEndpoint}}"
18 },
19 {
20 "label": "Request Headers",
21 "value": "{{attributes.byName.RequestHeaders}}"
22 },
23 {
24 "label": "Request Body",
25 "value": "{{attributes.byName.RequestBody}}"
26 }
27 ]
28 }
29 },
30 {
31 "component": "fc.card.attribute",
32 "props": {
33 "title": "Response Details",
34 "attributes": [
35 {
36 "label": "Response Code",
37 "value": "{{attributes.byName.Responsecode}}"
38 },
39 {
40 "label": "Response Reason",
41 "value": "{{attributes.byName.Responsereason}}"
42 },
43 {
44 "label": "Response Headers",
45 "value": "{{attributes.byName.ResponseHeaders}}"
46 },
47 {
48 "label": "Response Body",
49 "value": "{{attributes.byName.ResponseBody}}"
50 }
51 ]
52 }
53 },
54 {
55 "component": "fc.card.attribute",
56 "props": {
57 "title": "Exception Details",
58 "attributes": [
59 {
60 "label": "Exception",
61 "value": "{{attributes.byName.Exception}}"
62 },
63 {
64 "label": "Stacktrace",
65 "type": "component",
66 "options": {
67 "component": "fc.attribute.json",
68 "dataSource": "attributes.byName.Stacktrace"
69 }
70 }
71 ]
72 }
73 }
74 ]
75 }
76 }
77}
Language: json
Name: Webhook Details Drawer configuration
Description:
Configuration for the Webhook Details Drawer
Here is the result:
Webhook Details Drawer with 503 Error Response (Zoom Image)
Webhook Details Drawer with Stacktrace Error (Zoom Image)
This tutorial will end here, but there are many more things you can do should you need to:
Additionally, you can use this same technique to display webhooks information contextually to specific entities. For example, you may want to enable a Webhooks list on the Order details screen:
Example of showing Webhook Audit information on the Order Details screen (Zoom Image)
You could follow this through to sub-entities too, such as fulfilments, articles, consignments, etc. Each time, you simply refine the query parameters to be passed to the Event API query in the
`devrel.provider.rest`
In this article, you learned how to use the
`devrel.provider.rest`
There are plenty of other useful things you can do with the
`devrel.provider.rest`
Copyright © 2024 Fluent Retail Pty Ltd (trading as Fluent Commerce). All rights reserved. No materials on this docs.fluentcommerce.com site may be used in any way and/or for any purpose without prior written authorisation from Fluent Commerce. Current customers and partners shall use these materials strictly in accordance with the terms and conditions of their written agreements with Fluent Commerce or its affiliates.