API Interface Strategy — REST, gRPC, GraphQL
Ref: suitability-engine-arch-2 · Capability: SUITABILITY-ENGINE · Status: draft Repo: suitability-engine
Three interface definitions now exist for the Suitability Engine’s export operation, same capability, three wire protocols:
- REST / OpenAPI 3.1 —
openapi.yaml(source in repo) - gRPC —
suitability.proto(source in repo) - GraphQL —
schema.graphql(source in repo)
Status: interface definitions only. The only one with a real server
behind it today is REST (src/server/app.ts, plain Node http). gRPC and
GraphQL are contracts to implement against once a concrete internal
consumer needs them — not built speculatively ahead of a real one. Building
an unused server is real maintenance cost (dependency surface, a second
auth path to secure, a second thing to keep in sync with SuitabilityData
as it evolves) for zero benefit until something actually calls it.
One correction made while writing this
Section titled “One correction made while writing this”The original ask assumed Swagger 2.0. Swagger 2.0 was superseded by
OpenAPI 3.0 in 2017, and OpenAPI 3.1 (2021) is current — it merged the
schema format with JSON Schema, so $ref/nullable/etc. work the way any
modern JSON Schema tooling expects. api/openapi.yaml is written against
3.1. No reason to target the older spec for new work.
Decision — which protocol for which consumer
Section titled “Decision — which protocol for which consumer”| Consumer | Protocol | Why |
|---|---|---|
| Origo (external, loosely-coupled partner) | REST / OpenAPI | External partners integrate fastest against REST — every language has an HTTP client, no codegen toolchain required on their side, human-readable payloads for debugging a partner integration over email/support tickets. This is also the only protocol with per-request scoped-API-key auth designed for it (docs/external/origo-suitability-and-adviser-api-design.md §5.1 in client-onboarding) — gRPC/GraphQL auth for an external partner would need separate design work, not done here. |
data-backbone, other tightly-integrated internal WTP services | gRPC (default recommendation) | Codegen’d, strongly-typed clients; binary framing is real overhead-reduction for high-volume internal calls; a single point-to-point call per client record (fetch one report) is gRPC’s actual sweet spot, not GraphQL’s. |
| An internal dashboard/aggregation surface needing several reports with flexible field selection in one round trip | GraphQL (situational, not default) | Only reach for this if the actual access pattern is genuinely multi-report/flexible-field (schema.graphql’s suitabilityReports batch query exists for exactly this). If a consumer just wants one report per call, gRPC is simpler and doesn’t need a resolver layer. |
Do not build all three defensively. Pick the protocol the actual consumer’s access pattern calls for, using the table above, and implement that one. The two unbuilt schemas exist so the shape is already decided and reviewable — not so all three get built regardless of whether anything calls them.
Keeping three schemas in sync
Section titled “Keeping three schemas in sync”Right now: by hand. All three were authored together on 2026-08-16 against
the same source of truth (suitability-template/contract.ts,
suitability-rules/types.ts). This will drift the first time
SuitabilityData changes and only one schema gets updated — a known,
accepted risk for now, not solved here. If a second protocol actually gets
implemented (per the decision above), that’s the moment to invest in
codegen (e.g. generate .proto/.graphql from the Zod schema, or a
shared IDL all three generate from) rather than three hand-maintained
copies indefinitely.
What CRM-bridge’s interface strategy should be
Section titled “What CRM-bridge’s interface strategy should be”Not defined here — SPEC-153 (the CRM/Adviser API) has no external shape
yet beyond an inbound-only pipeline for one platform (Plannr). Defining
REST/gRPC/GraphQL contracts for an API that doesn’t have a stable
bidirectional design yet would be designing against a moving target. Once
that design stabilises (see the CRM-bridge separation decision), the same
three-protocol pattern established here is the template to repeat, not a
new approach to invent.
