Skip to content

Commit 39560f0

Browse files
committed
Add page events documentation
1 parent ab81a19 commit 39560f0

5 files changed

Lines changed: 132 additions & 1 deletion

File tree

docs/INDEX.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
- [Plugin registration options](./PLUGIN_OPTIONS.md)
55
- Configuration-based features
66
- [Page templates (dynamic content)](./features/configuration-based/PAGE_TEMPLATES.md)
7+
- [Page events (triggering an action on an event)](./features/configuration-based/PAGE_EVENTS.md)
78
- Code-based features
89
- [Page views (customisable views with Nunjucks)](./features/code-based/PAGE_VIEWS.md)
910
- [Custom Nunjucks/liquid filters](./PLUGIN_OPTIONS.md#custom-filters)

docs/features/code-based/PAGE_VIEWS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,7 @@ The `forms-engine-plugin` path to add can be imported from:
1616
Which can then be appended to the `node_modules` path `node_modules/@defra/forms-engine`.
1717

1818
The main template layout is `govuk-frontend`'s `template.njk` file, this also needs to be added to the `path`s that nunjucks can look in.
19+
20+
## Using page views with data from your own API
21+
22+
Page templates have access to `{{ context.data }}`, which is an attribute made available when a page event is triggered. It represents the entire response body from your API. To learn more about this, [see our guidance on page events](./PAGE_EVENTS.md).
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# Page events
2+
3+
Page events are a configuration-based way of triggering an action on an event trigger. For example, when a page loads, call an API and retrieve the data from it.
4+
5+
DXT's forms engine is a frontend service, which should remain as lightweight as possible with business logic being implemented in a backend/BFF API. Using page events, DXT can call your API and use the tailored response downstream, such a page templates to display the response value.
6+
7+
The downstream API response becomes available under the `{{ context.data }}` view model attribute for view templates, so it can be used when rendering a page. This attribute is directly accessible by our [page templates](./../configuration-based/PAGE_TEMPLATES.md) feature and our Nunjucks-based views.
8+
9+
## Architecture
10+
11+
DXT will call any API of your choosing, so ultimately the architecture is up to you. As long as that API accepts the DXT payload, returns HTTP 200 and returns a valid JSON document as the response body, you will be able to use page events.
12+
13+
Our recommendation is that you create a lightweight backend service called a "BFF" (backend for frontend). This is a common pattern that allows you to decouple your backend service from the frontend implementation, allowing you to tailor your existing backend API to a different frontend. To learn more about this pattern, see [Microsoft's guide](https://learn.microsoft.com/en-us/azure/architecture/patterns/backends-for-frontends).
14+
15+
![Architecture diagram showing the usage of a frontend, a BFF, and a backend API interacting with each other](images/page-events-architecture.png)
16+
17+
If DXT is the only consumer of your API, it may make sense to omit the BFF and have DXT directly call your backend.
18+
19+
## Setting up a page event
20+
21+
A page event is configured by definining the event trigger, then the action configuration. For example, to call an API on page load:
22+
23+
```json
24+
{
25+
"onLoad": {
26+
"type": "http",
27+
"options": {
28+
"url": "https://my-api.defra.gov.uk"
29+
}
30+
}
31+
}
32+
```
33+
34+
See [supported behaviours](#supported-behaviours) to learn more about the supported triggers and actions.
35+
36+
## Supported events
37+
38+
### Supported triggers
39+
40+
Currently supported event types:
41+
42+
- `onLoad`: Called on load of a page (e.g. the initial GET request to load the page)
43+
44+
Planned event types:
45+
46+
- `onSave`: Called on save of a page, after the data has been validated by DXT. For example, when a user presses "Continue", which triggers a POST request.
47+
48+
### Supported actions
49+
50+
- `http`: Makes a HTTP(S) call to a web service. This service must be routable on DXT (e.g. by configuring CDP's squid proxy), must accept DXT's standardised payload, return HTTP 200 and a valid JSON document.
51+
- Options:
52+
- `url`: A fully formed HTTP(S) URL, e.g. "https://my-api.defra.gov.uk` or `https://my-api.prod.cdp-int.defra.cloud`
53+
54+
## Payload
55+
56+
DXT sends a standardised payload to each API configured with page events. The latest version of our payload [can be found in our outputFormatters module by opening the latest version, e.g. `v2.ts`](https://github.com/DEFRA/forms-engine-plugin/tree/main/src/server/plugins/engine/outputFormatters/machine). Our payload contains some metadata about the payload, along with a "data" section that contains the main body of the form as a JSON object, an array of repeatable pages, and a file ID and download link for all files submitted.
57+
58+
As of 2025-03-25, the payload would look something like this:
59+
60+
```json
61+
{
62+
"meta": {
63+
"schemaVersion": "2",
64+
"timestamp": "2025-03-25T10:00:00Z",
65+
"definition": {
66+
"_comment": "This object would be a full copy of the form definition at the time of submission. It is excluded for brevity."
67+
}
68+
},
69+
"data": {
70+
"main": {
71+
"componentName": "componentValue",
72+
"richComponentName": { "foo": "bar", "baz": true }
73+
},
74+
"repeaters": {
75+
"repeaterName": [
76+
{
77+
"textComponentName": "componentValue"
78+
},
79+
{
80+
"richComponentName": { "foo": "bar", "baz": true }
81+
}
82+
]
83+
},
84+
"files": {
85+
"fileComponentName": [
86+
{
87+
"fileId": "123-456-789",
88+
"link": "https://forms-designer/file-download/123-456-789"
89+
}
90+
]
91+
}
92+
}
93+
}
94+
```
95+
96+
## Using the response from your API in DXT
97+
98+
If the API call is successful, the JSON response your API returns will be attached to the page `context` under the `data` attribute. Liquid/Nunjucks can then use this data however it would normally use variables, for example:
99+
100+
Your API response:
101+
102+
```json
103+
{
104+
"awardedGrantValue": "150"
105+
}
106+
```
107+
108+
Page template:
109+
110+
```jinja2
111+
{% if context.data.awardedGrantValue %}
112+
<p class="govuk-body">Congratulations. You are likely to receive up to £{{ context.data.awardedGrantValue }}.</p>
113+
{% endif %}
114+
<p class="govuk-body">You have not been awarded any funding for this application.</p>
115+
{% endif %}
116+
```
117+
118+
Results in:
119+
120+
```jinja2
121+
<p class="govuk-body">You have been awarded £150.</p>
122+
```

docs/features/configuration-based/PAGE_TEMPLATES.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Page templates
22

3-
Page templates are a configuration-way of adding dynamic content to the form UI, such as displaying the answer to a question, or some data from your API. This feature is only used for presentation purposes.
3+
Page templates are a configuration-based way of adding dynamic content to the form UI, such as displaying the answer to a question, or some data from your API. This feature is only used for presentation purposes.
44

55
Certain elements of your form, such as content blocks or page titles, allow for the use of LiquidJS. LiquidJS is a templating engine that runs alongside Nunjucks to dynamically insert data into the rendered page.
66

@@ -148,3 +148,7 @@ Full example of the minified and escaped component, which can be appended to [th
148148
## Providing your own filters
149149

150150
Whilst DXT offers some out of the box filters, teams using the plugin have the capability to provide their own. See [PLUGIN_OPTIONS.md](../../PLUGIN_OPTIONS.md#custom-filters) for more information.
151+
152+
## Using page templates with data from your own API
153+
154+
Page templates have access to `{{ context.data }}`, which is an attribute made available when a page event is triggered. It represents the entire response body from your API. To learn more about this, [see our guidance on page events](./PAGE_EVENTS.md).
21.6 KB
Loading

0 commit comments

Comments
 (0)