Skip to content

feat(GAT-9591): port the JSON API resource routes - #128

Merged
calmacx merged 3 commits into
feat/GAT-9590-core-libfrom
feat/GAT-9591-api-routes
Sep 23, 2026
Merged

calmacx merged 3 commits into
feat/GAT-9590-core-libfrom
feat/GAT-9591-api-routes

Conversation

@calmacx

@calmacx calmacx commented Sep 17, 2026 •

Copy link
Copy Markdown
Collaborator

What

Ports the twelve JSON API resource routes into app/routes/api/ byte-identical to poc/GAT-XXXX and registers them in app/routes.ts: /translate, /validate, /find, /list/{schemas,templates,translations,datasets}, /get/{schema,map,form_hydration,dataset} and /openapi.json.

Why

These are the live contracts Gateway API, gateway-web-2 and the federation service call today. They land together because all twelve depend only on the ported engine, and because the spec endpoint enumerates its siblings.

Testing

npm run typecheck, npm run lint, npm run build all exit 0; the server bundle jumps from 5 kB to 69 kB, which is the first real exercise of Vite's ssr.external handling for the CJS-only packages. The /openapi.json fix was verified inside a built production image (docker exec … ls /app/app → no such directory, confirming the defect; spec then served with all paths present).

Notes

  • Also fixes /openapi.json in production. The loader globbed app/routes/api/*.ts at runtime, but Dockerfile.prod's final stage does not copy app/, so the glob matched nothing and the spec shipped with zero paths. Local runs and CI could never see it, because there the repo is the working directory. The spec is now compiled at build time; the generator exits non-zero rather than writing an empty spec, so it cannot fail silently again.
  • The @openapi JSDoc annotations are untouched — they are the generator's input, not commentary.
  • Replaying production fixtures against this branch surfaced five contract divergences. They are fixed in the PR stacked directly on this one, so that this stays reviewable as a verbatim port.

@gh-actions-pipelines-app

Copy link
Copy Markdown

🎉 Great job! Your PR title follows the correct format. 🚀

@calmacx
calmacx added this pull request to stack #131 September 17, 2026 09:59
@calmacx
calmacx force-pushed the feat/GAT-9591-api-routes branch from 3bfa760 to c478de7 Compare September 17, 2026 10:06
@calmacx
calmacx removed this pull request from stack #131 September 17, 2026 10:54
@calmacx
calmacx added this pull request to stack #133 September 17, 2026 10:54
@calmacx
calmacx force-pushed the feat/GAT-9591-api-routes branch from c478de7 to 39a726d Compare September 21, 2026 09:36
@calmacx
calmacx force-pushed the feat/GAT-9591-api-routes branch from 39a726d to 6a7a699 Compare September 21, 2026 14:12
@calmacx

calmacx commented Sep 21, 2026

Copy link
Copy Markdown
Collaborator Author

Scope expanded 2026-09-21 — this PR now also carries the API contract fixes that were #129.

#129 existed only because this PR was already open when the divergences were found, and its rationale was the production fixture replay, which has been removed from the repo. It is closed; its single commit is now fix(GAT-9591): restore API contract parity with production on this branch.

That commit restores five behaviours the port had dropped relative to production:

  • GET /status — was missing entirely (404 where production responded); likely a liveness-probe target
  • POST /translate — the express-validator errors[] envelope that gateway-web reads
  • POST /translate — validation of validate_input / validate_output (0/false and 1/true accepted, anything else an error) and the type check on extra
  • GET /get/map — 200 where the port had started returning 400
  • GET /get/map — additive translation_path / translation_maps so a pair with no direct map exposes the chain TRASER would apply

Route count is 11, not the 10 this PR originally landed — /status is the eleventh.

The title still says "port the JSON API resource routes"; gh pr edit is currently failing against this repo with a Projects-classic GraphQL deprecation error, so it needs editing by hand if the wording matters.

@calmacx
calmacx removed this pull request from stack #133 September 22, 2026 08:33
@calmacx
calmacx added this pull request to stack #139 September 22, 2026 09:17
@calmacx
calmacx force-pushed the feat/GAT-9591-api-routes branch from 6a7a699 to e6a816f Compare September 22, 2026 09:24
Ports the twelve JSON API resource routes into app/routes/api/ byte-identical
to poc/GAT-XXXX and registers them in app/routes.ts: /translate, /validate,
/find, /list/{schemas,templates,translations,datasets},
/get/{schema,map,form_hydration,dataset} and /openapi.json.

These are the live contracts Gateway API, gateway-web-2 and the federation
service call today. They land together because all twelve depend only on the
ported module set, and because the spec endpoint enumerates its siblings.

Also fixes /openapi.json for production. openapi.json.ts globbed
app/routes/api/*.ts at runtime, but Dockerfile.prod's final stage copies only
package.json, package-lock.json, node_modules and build/ -- app/ is not in the
image, so the glob matched nothing and the spec shipped with zero paths. Local
runs and CI could never see it because the repo is the working directory.

The swagger definition moves to app/lib/openapi-definition.json so that the
route and a new scripts/build-openapi.mjs share one source, and npm run build
now generates build/openapi.json after react-router build (which clears
build/). The generator exits non-zero rather than writing a spec with no
paths, so the failure can never be silent again. The loader reads that
artefact; outside production it falls back to globbing sources so npm run dev
still works, and in production it throws rather than serving an empty spec.

The @openapi JSDoc annotations are untouched — they are the generator's input,
not commentary. Only when and where the spec is compiled has changed.
/list/datasets and /get/dataset read the dataset file cache, which the
Express service does not have: src/routes/list.js serves only templates,
schemas and translations, and src/routes/get.js only schema, map and
form_hydration. Both endpoints are new surface built for the admin
tooling, so they move to WS4 PR01 with cache.server.ts.

Neither carried an @openapi block, so the generated spec is unchanged by
this commit.

Refs: upgrade-plans/07-strip-admin-surface-from-ws1.md
Fixes the five divergences that replaying the production fixtures against the
ported routes turned up. Kept separate from the port itself so that PR remains
reviewable as a verbatim port and this one is reviewed as behaviour.

- GET /status was missing entirely and answered 404. Express defines it
  (src/routes/index.js:13) and it is the likely liveness-probe target. Restored
  as a four-line resource route that touches no schemas, templates or cache, so
  it cannot fail for reasons unrelated to liveness.

- /translate lost the express-validator error envelope, returning
  {message} instead of {message, errors:[{type,msg,path,location}]}. A consumer
  doing errors[0].msg got a TypeError. /validate had the same defect. Both
  restored, including express-validator's quirk that a missing metadata key
  trips isObject() and notEmpty() separately and so produces two identical
  entries, while a non-object non-empty value produces one.

- /translate stopped validating validate_input / validate_output, silently
  accepting anything that was not "0". Now 1/true are true, 0/false are false,
  and anything else is a 400 carrying production's exact message. Accepting
  true/false is a deliberate widening over production, which took only "1"/"0";
  no fixture sends them and "2" still errors identically. An empty value keeps
  defaulting to true, matching express-validator's .default("1").

- /translate stopped validating that extra is an object, forwarding a string
  into the JSONata binding where templates dereference extra.*.

- /get/map returned 400 where production returned 200 with
  translation_map: null. A consumer branching on res.ok took the error path
  instead of seeing null. Restored to 200, and since most such pairs are still
  reachable by chaining templates, the response additively gains
  translation_path and translation_maps. Every field production returned is
  unchanged in name and type.

Fixture replay goes from 6 exact / 2 status-mismatch to 13 exact / 0.
@calmacx
calmacx merged commit d69db2d into dev Sep 23, 2026
2 checks passed
@calmacx
calmacx deleted the feat/GAT-9591-api-routes branch September 23, 2026 08:55

This branch was successfully deployed

1 active deployment
dev — caf2cce5 Deployed Sep 22, 2026 by calmacx via testing #726
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants