Skip to content

Commit a1dc08f

Browse files
authored
Create ADR for proposed Welsh forms API implementation
1 parent 73baf8d commit a1dc08f

1 file changed

Lines changed: 336 additions & 0 deletions

File tree

Lines changed: 336 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,336 @@
1+
# ADR044: Translate API response at request time
2+
3+
Date: 2025-08-01
4+
5+
## Status
6+
7+
Accepted
8+
## Context
9+
10+
Our current API is based around form documents which contain all the information forms-runner needs to render a form:
11+
12+
```jsonc
13+
{
14+
"form_id": "7",
15+
"name": "A form for testing file upload",
16+
"submission_email": "david.biddle@digital.cabinet-office.gov.uk",
17+
"privacy_policy_url": null,
18+
"form_slug": "a-form-for-testing-file-upload",
19+
"support_email": null,
20+
"support_phone": null,
21+
"support_url": null,
22+
"support_url_text": null,
23+
"declaration_text": null,
24+
"question_section_completed": false,
25+
"declaration_section_completed": false,
26+
"created_at": "2025-03-27T12:05:49.395300Z",
27+
"updated_at": "2025-07-29T14:35:44.423406Z",
28+
"creator_id": 1,
29+
"what_happens_next_markdown": null,
30+
"payment_url": null,
31+
"submission_type": "email",
32+
"share_preview_completed": false,
33+
"s3_bucket_name": null,
34+
"s3_bucket_aws_account_id": null,
35+
"s3_bucket_region": null,
36+
"language": "en",
37+
"start_page": 33,
38+
"steps": [
39+
{
40+
"id": 33,
41+
"position": 1,
42+
"next_step_id": null,
43+
"type": "question_page",
44+
"data": {
45+
"question_text": "Upload your file",
46+
"hint_text": "",
47+
"answer_type": "file",
48+
"is_optional": false,
49+
"answer_settings": null,
50+
"page_heading": "Annual report",
51+
"guidance_markdown": "Some guidance",
52+
"is_repeatable": false
53+
},
54+
"routing_conditions": []
55+
}
56+
]
57+
}
58+
```
59+
60+
A form can have multiple from documents associated with it, depending on its state:
61+
```jsonc
62+
{
63+
"id": "7",
64+
"links": {
65+
"self": "/api/v2/forms/7",
66+
"draft": "/api/v2/forms/7/draft",
67+
"live": "/api/v2/forms/7/live",
68+
// or
69+
"archived": "/api/v2/forms/7/archived"
70+
}
71+
}
72+
```
73+
74+
Currently form documents only contain English language text, but we want to add Welsh translations for form-filler facing text.
75+
76+
There are a few ways we could model this.
77+
### 1. Adding additional fields to the form document
78+
79+
One option is to add extra keys to the existing form document with the new translations. We could do this by renaming the existing field with an `_en` suffix and adding a new key with a `_cy` suffix. This is roughly what the mobility gem does with its database columns:
80+
```jsonc
81+
{
82+
"form_id": "7",
83+
"name_en": "A form for testing file upload",
84+
"name_cy": "Ffurflen ar gyfer profi uwchlwytho ffeiliau",
85+
"submission_email": "david.biddle@digital.cabinet-office.gov.uk",
86+
"privacy_policy_url": null,
87+
"form_slug": "a-form-for-testing-file-upload",
88+
"support_email": null,
89+
"support_phone": null,
90+
"support_url": null,
91+
"support_url_text": null,
92+
"declaration_text": null,
93+
"question_section_completed": false,
94+
"declaration_section_completed": false,
95+
"created_at": "2025-03-27T12:05:49.395300Z",
96+
"updated_at": "2025-07-29T14:35:44.423406Z",
97+
"creator_id": 1,
98+
"what_happens_next_markdown": null,
99+
"payment_url": null,
100+
"submission_type": "email",
101+
"share_preview_completed": false,
102+
"s3_bucket_name": null,
103+
"s3_bucket_aws_account_id": null,
104+
"s3_bucket_region": null,
105+
"language": "en",
106+
"start_page": 33,
107+
"steps": [
108+
{
109+
"id": 33,
110+
"position": 1,
111+
"next_step_id": null,
112+
"type": "question_page",
113+
"data": {
114+
"question_text_en": "Upload your file",
115+
"question_text_cy": "Llwythwch eich ffeil i fyny",
116+
"hint_text": "",
117+
"answer_type": "file",
118+
"is_optional": false,
119+
"answer_settings": null,
120+
"page_heading_en": "Annual report",
121+
"page_heading_cy": "Adroddiad blynyddol",
122+
"guidance_markdown_en": "Some guidance",
123+
"guidance_markdown_cy": "Peth arweiniad",
124+
"is_repeatable": false
125+
},
126+
"routing_conditions": []
127+
}
128+
]
129+
}
130+
```
131+
132+
We could also keep the existing keys as they are, and add a new 'translations' object containing only the Welsh translations for the relevant field:
133+
```jsonc
134+
// or:
135+
{
136+
"form_id": "7",
137+
"name": "A form for testing file upload",
138+
"submission_email": "david.biddle@digital.cabinet-office.gov.uk",
139+
"privacy_policy_url": null,
140+
"form_slug": "a-form-for-testing-file-upload",
141+
"support_email": null,
142+
"support_phone": null,
143+
"support_url": null,
144+
"support_url_text": null,
145+
"declaration_text": null,
146+
"question_section_completed": false,
147+
"declaration_section_completed": false,
148+
"created_at": "2025-03-27T12:05:49.395300Z",
149+
"updated_at": "2025-07-29T14:35:44.423406Z",
150+
"creator_id": 1,
151+
"what_happens_next_markdown": null,
152+
"payment_url": null,
153+
"submission_type": "email",
154+
"share_preview_completed": false,
155+
"s3_bucket_name": null,
156+
"s3_bucket_aws_account_id": null,
157+
"s3_bucket_region": null,
158+
"language": "en",
159+
"start_page": 33,
160+
"translations": {
161+
"cy": {
162+
"name": "Ffurflen ar gyfer profi uwchlwytho ffeiliau",
163+
}
164+
},
165+
"steps": [
166+
{
167+
"id": 33,
168+
"position": 1,
169+
"next_step_id": null,
170+
"type": "question_page",
171+
"data": {
172+
"question_text": "Upload your file",
173+
"hint_text": "",
174+
"answer_type": "file",
175+
"is_optional": false,
176+
"answer_settings": null,
177+
"page_heading": "Annual report",
178+
"guidance_markdown": "Some guidance",
179+
"is_repeatable": false
180+
},
181+
"translations": {
182+
"cy": {
183+
"question_text": "Llwythwch eich ffeil i fyny",
184+
"page_heading": "Adroddiad blynyddol",
185+
"guidance_markdown": "Peth arweiniad",
186+
}
187+
},
188+
"routing_conditions": []
189+
}
190+
]
191+
}
192+
```
193+
194+
Both cases are essentially the same.
195+
Benefits:
196+
- Few admin/api changes required
197+
Disadvantages:
198+
- More runner logic, since we'd have to manage choosing the right translation and fallback behaviour in runner.
199+
- We'd get less benefit from the Mobility gem - we'd be using it for managing the columns and dealing with translations in admin, but we wouldn't be using its querying or fallback features in forms-runner.
200+
- For forms with lots of content (e.g. multiple pages with a large amount of detailed guidance or what happens next text), this would increase the size of the request quite a lot since this information would be present in two different languages. Much of that content wouldn't be used for a given request, since the runner only shows one language at a time.
201+
- Additional languages would make it even more verbose.
202+
203+
### 2. Selecting languages at request time
204+
In this approach, the form snapshot in the database would look the same as in the above approach. But we would allow the runner to request a specific language when requesting the form from the API, and the API would only supply translations for the requested language.
205+
206+
So `/forms/7/live?locale=en` would return:
207+
```jsonc
208+
{
209+
"form_id": "7",
210+
"name": "A form for testing file upload",
211+
"submission_email": "david.biddle@digital.cabinet-office.gov.uk",
212+
"privacy_policy_url": null,
213+
"form_slug": "a-form-for-testing-file-upload",
214+
"support_email": null,
215+
"support_phone": null,
216+
"support_url": null,
217+
"support_url_text": null,
218+
"declaration_text": null,
219+
"question_section_completed": false,
220+
"declaration_section_completed": false,
221+
"created_at": "2025-03-27T12:05:49.395300Z",
222+
"updated_at": "2025-07-29T14:35:44.423406Z",
223+
"creator_id": 1,
224+
"what_happens_next_markdown": null,
225+
"payment_url": null,
226+
"submission_type": "email",
227+
"share_preview_completed": false,
228+
"s3_bucket_name": null,
229+
"s3_bucket_aws_account_id": null,
230+
"s3_bucket_region": null,
231+
"language": "en",
232+
"start_page": 33,
233+
"steps": [
234+
{
235+
"id": 33,
236+
"position": 1,
237+
"next_step_id": null,
238+
"type": "question_page",
239+
"data": {
240+
"question_text": "Upload your file",
241+
"hint_text": "",
242+
"answer_type": "file",
243+
"is_optional": false,
244+
"answer_settings": null,
245+
"page_heading": "Annual report",
246+
"guidance_markdown": "Some guidance",
247+
"is_repeatable": false
248+
},
249+
"routing_conditions": []
250+
}
251+
]
252+
}
253+
```
254+
255+
And `/forms/7/live?locale=cy`, would return the same object with any Welsh translations overwriting the English:
256+
```jsonc
257+
{
258+
"form_id": "7",
259+
"name": "Ffurflen ar gyfer profi uwchlwytho ffeiliau",
260+
"submission_email": "david.biddle@digital.cabinet-office.gov.uk",
261+
"privacy_policy_url": null,
262+
"form_slug": "a-form-for-testing-file-upload",
263+
"support_email": null,
264+
"support_phone": null,
265+
"support_url": null,
266+
"support_url_text": null,
267+
"declaration_text": null,
268+
"question_section_completed": false,
269+
"declaration_section_completed": false,
270+
"created_at": "2025-03-27T12:05:49.395300Z",
271+
"updated_at": "2025-07-29T14:35:44.423406Z",
272+
"creator_id": 1,
273+
"what_happens_next_markdown": null,
274+
"payment_url": null,
275+
"submission_type": "email",
276+
"share_preview_completed": false,
277+
"s3_bucket_name": null,
278+
"s3_bucket_aws_account_id": null,
279+
"s3_bucket_region": null,
280+
"language": "en",
281+
"start_page": 33,
282+
"steps": [
283+
{
284+
"id": 33,
285+
"position": 1,
286+
"next_step_id": null,
287+
"type": "question_page",
288+
"data": {
289+
"question_text": "Llwythwch eich ffeil i fyny",
290+
"hint_text": "",
291+
"answer_type": "file",
292+
"is_optional": false,
293+
"answer_settings": null,
294+
"page_heading": "Adroddiad blynyddol",
295+
"guidance_markdown": "Peth arweiniad",
296+
"is_repeatable": false
297+
},
298+
"routing_conditions": []
299+
}
300+
]
301+
}
302+
```
303+
304+
Advantages:
305+
- Request size doesn't increase
306+
- API structure doesn't change aside from the addition of a query parameter.
307+
- Keeps the translation logic out of runner
308+
Disadvantages:
309+
- Requires more logic in the API to choose the right translation - we already have some conversion logic, but we're currently trying to reduce the amount of logic in this repo.
310+
- API is doing more work at request time, which might slow down its responses for forms with lots of questions.
311+
- Small runner change required to request the correct version
312+
313+
### 3. Creating separate Welsh and English snapshots when making a form live
314+
We could create separate snapshots for Welsh and English when making a form live - so the API would store two separate form documents, one in English and one in Welsh. At request time, the runner would request a form document and request a language, and API would return the relevant version of the form document. The objects returned would be identical to those in the 'Selecting languages at request time' approach.
315+
316+
Advantages:
317+
- API structure doesn't change aside from the addition of a query parameter.
318+
- All translation logic including fallbacks can be handled within admin, API/runner don't have to do any processing on the resulting form documents - just need to serve/request the right version.
319+
- No additional processing or conversion would be required at request time, just returning an existing form document.
320+
Disadvantages:
321+
- More complexity in forms-admin. Probably needs API version increment.
322+
- Potential for overlap with API team's work.
323+
- Small runner change required to request the correct version.
324+
- Having two separate documents might risk the two versions going out of sync unexpectedly.
325+
- Would need to think about how we store the separate form documents - having them in one database column might be hard to query.
326+
327+
## Decision
328+
329+
Go with 'Selecting languages at request time' for now. Consider moving to 'Creating separate Welsh and English snapshots when making a form live' approach later if we add other languages and this this will be useful.
330+
331+
## Consequences
332+
Changes to forms-runner should be minimal, limited to making a request for the correct locale.
333+
334+
If we change to the 'Creating separate Welsh and English snapshots when making a form live' approach later we shouldn't need to make any runner updates.
335+
336+
We'll need to keep an eye on API response times to make sure they aren't having an impact on the performance of our service.

0 commit comments

Comments
 (0)