Skip to content

Commit a7e7573

Browse files
committed
ADR 1: Create a dedicated gem for conditional GraphQL content loading
to document the decision.
1 parent c3e6b88 commit a7e7573

File tree

1 file changed

+73
-0
lines changed

1 file changed

+73
-0
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# ADR 1: Create a dedicated gem for conditional GraphQL content loading
2+
Status: Accepted
3+
Date: 2026-02-17
4+
5+
## Context
6+
As part of the migration to GraphQL-backed content retrieval [RFC-172](https://github.com/alphagov/govuk-rfcs/blob/main/rfc-172-graphql-for-govuk.md), we are introducing a temporary (medium-term) ConditionalContentItemLoader that determines whether a request should load content from:
7+
* The Content Store (REST), or
8+
* The Publishing API via GraphQL
9+
10+
This decision is made at request time and depends on:
11+
* Request parameters
12+
* Environment state (e.g. draft host)
13+
* Allow-list configuration
14+
* Probabilistic traffic splitting
15+
16+
It includes Prometheus metrics labelling for monitoring and alerting.
17+
18+
The loader is required across seven frontend applications.
19+
20+
## Problem
21+
We need a centralised implementation to:
22+
* Avoid duplication and divergence across multiple apps
23+
* Maintain clear architectural boundaries
24+
* Keep configuration and routing logic co-located
25+
26+
## Decision
27+
We will create a Ruby gem to encapsulate the conditional content loader and its configuration, with minimal dependencies.
28+
29+
## Rationale
30+
1. Shared across multiple applications
31+
One gem ensures consistent behaviour and easier rollout coordination.
32+
33+
1. Maintenance burden is acceptable
34+
The gem is small, with few dependencies.
35+
36+
1. Not a good fit for `gds-api-adapters`
37+
`gds-api-adapters` is designed around a clear architectural pattern:
38+
* Each adapter corresponds to a single external API
39+
* Adapter methods map directly to HTTP endpoints
40+
* Namespaces reflect a 1:1 relationship with APIs
41+
42+
The conditional loader does not fit this model as it's a higher-level orchestration layer, not a client abstraction. Adding it to gds-api-adapters would:
43+
* Blur architectural boundaries
44+
* Violate separation of concerns
45+
* Break the established software design pattern of the gem
46+
47+
1. Not a good fit for `govuk_app_config`
48+
That library is intended for generic application configuration, not behaviour orchestration used by a subset of apps.
49+
50+
1. Explicitly not using `govuk_ab_testing`
51+
`govuk_ab_testing` was considered. This is not a generic A/B test or experiment framework use case. Embedding this logic in govuk_ab_testing would conflate experimentation infrastructure with migration routing logic.
52+
53+
1. Co-location with configuration
54+
The loader depends on configuration established via GovukGraphqlTrafficRates.configure which would fit in govuk_app_config. However, keeping it in the same gem reduces complexity and risk of misconfiguration.
55+
56+
## Alternatives considered
57+
- Duplicate in each app – rejected due to divergence risk.
58+
- Add to `gds-api-adapters` – rejected; violates separation of concerns.
59+
- Add to `govuk_app_config` – rejected; not just application configuration.
60+
- Add to `govuk_ab_testing` – rejected; not experimentation logic.
61+
62+
## Consequences
63+
64+
### Positive
65+
* Consistent behaviour across multiple applications
66+
* Clean architectural separation
67+
* Centralised rollout
68+
* Clear ownership of GraphQL migration logic
69+
* Versioned upgrades
70+
71+
### Negative
72+
* One additional gem to maintain
73+
* Increase in dependency management overhead

0 commit comments

Comments
 (0)