Problem
The DMN XML download is served by two handlers, and the frontend uses the one on the deprecated path.
GET /v1/dmns/:identifier/xml — packages/backend/src/routes/dmn.routes.ts, mounted through routes/registry.ts. The canonical route. GET /v1/dmns already links to it in each DMN's xmlUrl (/v1/dmns/<identifier>/xml, URL-encoded).
GET /api/dmns/:definitionKey/xml — packages/backend/src/routes/dmn-xml.routes.ts, mounted directly on the app in src/index.ts, ahead of the router. Its own counterpart's comment calls it a copy kept "for backward compatibility".
Because dmnRoutes is also mounted at the legacy /api/dmns alias in routes/index.ts, /api/dmns/:x/xml matches both handlers. dmn-xml.routes.ts is mounted first, so it wins, and the alias's Deprecation and Link: rel="successor-version" headers are never sent on this path.
The frontend calls the legacy path. packages/frontend/src/utils/exportService.ts:
const response = await fetch(`${API_BASE_URL}/api/dmns/${definitionKey}/xml`);
The key is interpolated without encodeURIComponent, unlike the backend's own xmlUrl.
Found on 15 September 2026 while designing #129.
Proposal
- Frontend:
fetchDmnXml in exportService.ts calls /v1/dmns/${encodeURIComponent(definitionKey)}/xml. Add or adjust a test that asserts the URL.
- Backend: delete
src/routes/dmn-xml.routes.ts and src/routes/dmn-xml.routes.test.ts, and remove the import and app.use('/api/dmns', dmnXmlRoutes) from src/index.ts, along with its comment.
- The comment's reason for mounting before
express.json() — that the route "streams raw XML" — does not apply: it is a GET with no request body, so the JSON parser never touches it.
- The legacy URL keeps working.
/api/dmns/:identifier/xml is still served by dmn.routes.ts through the /api/dmns alias, now with the deprecation headers. dmn.routes.test.ts already covers GET /api/dmns/:identifier/xml.
- Update the comment on the
/v1 handler in dmn.routes.ts that says it "mirrors the handler in dmn-xml.routes.ts".
Differences to check before deleting
The two handlers are near-duplicates, not identical. The surviving one:
- words its 404 message differently (
DMN definition not found in Operaton: …) and adds a timestamp;
- names the path parameter
identifier rather than definitionKey (the value is passed to Operaton the same way).
Neither difference reaches a client that checks only the status code, but confirm nothing external depends on the old message.
Acceptance criteria
Related
Problem
The DMN XML download is served by two handlers, and the frontend uses the one on the deprecated path.
GET /v1/dmns/:identifier/xml—packages/backend/src/routes/dmn.routes.ts, mounted throughroutes/registry.ts. The canonical route.GET /v1/dmnsalready links to it in each DMN'sxmlUrl(/v1/dmns/<identifier>/xml, URL-encoded).GET /api/dmns/:definitionKey/xml—packages/backend/src/routes/dmn-xml.routes.ts, mounted directly on the app insrc/index.ts, ahead of the router. Its own counterpart's comment calls it a copy kept "for backward compatibility".Because
dmnRoutesis also mounted at the legacy/api/dmnsalias inroutes/index.ts,/api/dmns/:x/xmlmatches both handlers.dmn-xml.routes.tsis mounted first, so it wins, and the alias'sDeprecationandLink: rel="successor-version"headers are never sent on this path.The frontend calls the legacy path.
packages/frontend/src/utils/exportService.ts:The key is interpolated without
encodeURIComponent, unlike the backend's ownxmlUrl.Found on 15 September 2026 while designing #129.
Proposal
fetchDmnXmlinexportService.tscalls/v1/dmns/${encodeURIComponent(definitionKey)}/xml. Add or adjust a test that asserts the URL.src/routes/dmn-xml.routes.tsandsrc/routes/dmn-xml.routes.test.ts, and remove the import andapp.use('/api/dmns', dmnXmlRoutes)fromsrc/index.ts, along with its comment.express.json()— that the route "streams raw XML" — does not apply: it is a GET with no request body, so the JSON parser never touches it./api/dmns/:identifier/xmlis still served bydmn.routes.tsthrough the/api/dmnsalias, now with the deprecation headers.dmn.routes.test.tsalready coversGET /api/dmns/:identifier/xml./v1handler indmn.routes.tsthat says it "mirrors the handler indmn-xml.routes.ts".Differences to check before deleting
The two handlers are near-duplicates, not identical. The surviving one:
DMN definition not found in Operaton: …) and adds atimestamp;identifierrather thandefinitionKey(the value is passed to Operaton the same way).Neither difference reaches a client that checks only the status code, but confirm nothing external depends on the old message.
Acceptance criteria
/v1/dmns/{identifier}/xml, URL-encoded.dmn-xml.routes.ts, its test, and its mount insrc/index.tsare gone.GET /api/dmns/{identifier}/xmlstill returns the XML, and now carriesDeprecation: trueand aLinkto the/v1successor (asserted in a test).Related
/v1only, so this download is covered there through/v1/dmns/{identifier}/xml.