refactor(api): migrate batch 10 endpoints to relayGet

This commit is contained in:
2026-03-24 10:08:51 +00:00
parent e8d4e8563e
commit 0f4b8005ba
4 changed files with 78 additions and 85 deletions
+31
View File
@@ -1006,3 +1006,34 @@ Validation:
Follow-ups: Follow-ups:
- Continue P2-S2 with next bounded batch from remaining legacy relay GET endpoints (`createwatchedcases_api`, `deletewatchedcasesproxy_api`, `getadvancedsearch_api`, `getadvancedsearchpaged_api`, `getbasicsearch_by_address_api`, `getbasicsearch_by_lparref_api`, `getdnscoords_api`, `getmylpacases_api`, `getportallogin_api`). - Continue P2-S2 with next bounded batch from remaining legacy relay GET endpoints (`createwatchedcases_api`, `deletewatchedcasesproxy_api`, `getadvancedsearch_api`, `getadvancedsearchpaged_api`, `getbasicsearch_by_address_api`, `getbasicsearch_by_lparref_api`, `getdnscoords_api`, `getmylpacases_api`, `getportallogin_api`).
---
### CL-027: TASK22229 P2-S2 Batch 10 (portal login + my LPA cases relay GET pair)
date: 2026-03-24
author: Cline
scope: `pages/api/endpoint/{getportallogin_api,getmylpacases_api}.js`, `tests/phase21/endpoint-handler-contract.test.cjs`
type: change
rationale: Continue bounded relay migration by moving two remaining high-use portal retrieval endpoints to shared `relayGet` while preserving existing hash/lookup guards and response contracts.
impact: Further relay boilerplate reduction and consistent forwarding behavior in portal login/LPA case retrieval flows; no intended API contract changes.
status: completed
Summary:
- Migrated Batch 10 endpoints to shared `relayGet`:
- `getportallogin_api.js` (preserved hash validation guard and error contract)
- `getmylpacases_api.js` (preserved LPA lookup/404 guard and title transform)
- Preserved endpoint-specific behavior:
- `getportallogin_api`: raw + encoded hash candidate validation before relay call
- `getmylpacases_api`: JSONPath LPA lookup with `LPA_NOT_FOUND` handling and `pinswg_title` enrichment transform
- Updated phase21 endpoint contract tests to inject `relayGet` mocks for migrated handlers in validation/catch/success paths.
Validation:
- `node tests/phase21/endpoint-handler-contract.test.cjs` -> pass (152/152)
- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps`; no new lint errors)
Follow-ups:
- Continue P2-S2 with the remaining legacy relay GET candidates (`createwatchedcases_api`, `deletewatchedcasesproxy_api`, `getadvancedsearch_api`, `getadvancedsearchpaged_api`, `getbasicsearch_by_address_api`, `getbasicsearch_by_lparref_api`, `getdnscoords_api`).
+17 -20
View File
@@ -17,18 +17,11 @@
* description: Success * description: Success
*/ */
import axios from "axios";
import { JSONPath as jsonpath } from "jsonpath-plus"; import { JSONPath as jsonpath } from "jsonpath-plus";
import { getLPA } from "../../../actions/services/referenceDataService"; import { getLPA } from "../../../actions/services/referenceDataService";
import { azureHeaders } from "../../../actions/core/headers"; import { azureHeaders } from "../../../actions/core/headers";
import { consoleLogger } from "../../../actions/core/logger"; import { respondError } from "../middleware/apiResponse";
import { getToken } from "../../../actions/core/token"; import { relayGet } from "../middleware/relayForwarding";
import { hashAPIPath } from "../../../actions/core/hash";
import { respondError, respondSuccess } from "../middleware/apiResponse";
const WEBAPI_URL =
process.env.RELAY_ROOT ||
"https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/";
export default async function ApiProxy(req, res) { export default async function ApiProxy(req, res) {
const lpaid = req.query.lpaid; const lpaid = req.query.lpaid;
@@ -42,7 +35,6 @@ export default async function ApiProxy(req, res) {
} }
try { try {
const token = await getToken();
const lpaList = await getLPA(); const lpaList = await getLPA();
const lpaGUID = jsonpath({ const lpaGUID = jsonpath({
@@ -74,18 +66,23 @@ export default async function ApiProxy(req, res) {
//console.log("///////////\nPortal query: ", queryUrl, "<<<<end query"); //console.log("///////////\nPortal query: ", queryUrl, "<<<<end query");
const { data } = await axios.get( return relayGet({
WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), queryUrl,
azureHeaders(token.access_token) res,
); requestOptionsBuilder: (accessToken) => azureHeaders(accessToken),
transformData: (data) => {
data.value.forEach(function (element) { data.value.forEach(function (element) {
element.pinswg_title = element.title; element.pinswg_title = element.title;
});
return data;
},
errorResponse: {
status: 400,
code: "MY_LPA_CASES_FETCH_FAILED",
message: "Failed to fetch my LPA cases"
}
}); });
return respondSuccess(res, data);
} catch (error) { } catch (error) {
consoleLogger(error);
return respondError(res, { return respondError(res, {
status: 400, status: 400,
code: "MY_LPA_CASES_FETCH_FAILED", code: "MY_LPA_CASES_FETCH_FAILED",
+13 -24
View File
@@ -16,16 +16,10 @@
* description: hello world * description: hello world
*/ */
import axios from "axios";
import { azureHeadersPaged } from "../../../actions/core/headers"; import { azureHeadersPaged } from "../../../actions/core/headers";
import { consoleLogger } from "../../../actions/core/logger";
import { getToken } from "../../../actions/core/token";
import { hashAPIPath } from "../../../actions/core/hash"; import { hashAPIPath } from "../../../actions/core/hash";
import { respondError, respondSuccess } from "../middleware/apiResponse"; import { respondError } from "../middleware/apiResponse";
import { relayGet } from "../middleware/relayForwarding";
const WEBAPI_URL =
process.env.RELAY_ROOT ||
"https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/";
export default async function ApiProxy(req, res) { export default async function ApiProxy(req, res) {
const emailAddress = req.query.emailAddress; const emailAddress = req.query.emailAddress;
@@ -66,24 +60,19 @@ export default async function ApiProxy(req, res) {
}); });
} }
try { const queryUrl =
const token = await getToken(); "contacts?$filter=emailaddress1 eq '" +
const queryUrl = emailAddress +
"contacts?$filter=emailaddress1 eq '" + "' and statuscode eq 1&$count=true&$select=emailaddress1,contactid,yomifullname,firstname,lastname";
emailAddress +
"' and statuscode eq 1&$count=true&$select=emailaddress1,contactid,yomifullname,firstname,lastname";
const { data } = await axios.get(
WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
azureHeadersPaged(token.access_token)
);
return respondSuccess(res, data); return relayGet({
} catch (error) { queryUrl,
consoleLogger(error); res,
return respondError(res, { requestOptionsBuilder: (accessToken) => azureHeadersPaged(accessToken),
errorResponse: {
status: 400, status: 400,
code: "PORTAL_LOGIN_FETCH_FAILED", code: "PORTAL_LOGIN_FETCH_FAILED",
message: "Failed to fetch portal login" message: "Failed to fetch portal login"
}); }
} });
} }
@@ -274,14 +274,12 @@ test("getportallogin returns HASH_REQUIRED when hash missing", async () => {
const mod = loadModule("pages/api/endpoint/getportallogin_api.js", { const mod = loadModule("pages/api/endpoint/getportallogin_api.js", {
respondError: respondErrorMock, respondError: respondErrorMock,
respondSuccess: respondSuccessMock, respondSuccess: respondSuccessMock,
getToken: async () => ({ access_token: "token" }), relayGet: async () => ({}),
hashAPIPath: (input) => hashAPIPath: (input) =>
input && input.startsWith("/api/endpoint/getportallogin_api") input && input.startsWith("/api/endpoint/getportallogin_api")
? "&hash=expected" ? "&hash=expected"
: "&hash=relay", : "&hash=relay",
azureHeadersPaged: () => ({}), azureHeadersPaged: () => ({})
axios: { get: async () => ({ data: { value: [] } }) },
consoleLogger: () => {}
}); });
const req = { query: { emailAddress: "user@test.local" } }; const req = { query: { emailAddress: "user@test.local" } };
@@ -296,14 +294,12 @@ test("getportallogin returns INVALID_HASH when hash mismatch", async () => {
const mod = loadModule("pages/api/endpoint/getportallogin_api.js", { const mod = loadModule("pages/api/endpoint/getportallogin_api.js", {
respondError: respondErrorMock, respondError: respondErrorMock,
respondSuccess: respondSuccessMock, respondSuccess: respondSuccessMock,
getToken: async () => ({ access_token: "token" }), relayGet: async () => ({}),
hashAPIPath: (input) => hashAPIPath: (input) =>
input && input.startsWith("/api/endpoint/getportallogin_api") input && input.startsWith("/api/endpoint/getportallogin_api")
? "&hash=expected" ? "&hash=expected"
: "&hash=relay", : "&hash=relay",
azureHeadersPaged: () => ({}), azureHeadersPaged: () => ({})
axios: { get: async () => ({ data: { value: [] } }) },
consoleLogger: () => {}
}); });
const req = { query: { emailAddress: "user@test.local", hash: "wrong" } }; const req = { query: { emailAddress: "user@test.local", hash: "wrong" } };
@@ -318,18 +314,13 @@ test("getportallogin catch path returns PORTAL_LOGIN_FETCH_FAILED", async () =>
const mod = loadModule("pages/api/endpoint/getportallogin_api.js", { const mod = loadModule("pages/api/endpoint/getportallogin_api.js", {
respondError: respondErrorMock, respondError: respondErrorMock,
respondSuccess: respondSuccessMock, respondSuccess: respondSuccessMock,
getToken: async () => ({ access_token: "token" }), relayGet: async ({ res, errorResponse }) =>
respondErrorMock(res, errorResponse),
hashAPIPath: (input) => hashAPIPath: (input) =>
input && input.startsWith("/api/endpoint/getportallogin_api") input && input.startsWith("/api/endpoint/getportallogin_api")
? "&hash=expected" ? "&hash=expected"
: "&hash=relay", : "&hash=relay",
azureHeadersPaged: () => ({}), azureHeadersPaged: () => ({})
axios: {
get: async () => {
throw new Error("relay failed");
}
},
consoleLogger: () => {}
}); });
const req = { const req = {
@@ -349,16 +340,13 @@ test("getportallogin accepts encoded email hash variant", async () => {
const mod = loadModule("pages/api/endpoint/getportallogin_api.js", { const mod = loadModule("pages/api/endpoint/getportallogin_api.js", {
respondError: respondErrorMock, respondError: respondErrorMock,
respondSuccess: respondSuccessMock, respondSuccess: respondSuccessMock,
getToken: async () => ({ access_token: "token" }), relayGet: async ({ res }) =>
respondSuccessMock(res, { value: [{ contactid: "c1" }] }),
hashAPIPath: (input) => hashAPIPath: (input) =>
input && input.includes("emailAddress=user%2Btest%40local") input && input.includes("emailAddress=user%2Btest%40local")
? "&hash=expected" ? "&hash=expected"
: "&hash=other", : "&hash=other",
azureHeadersPaged: () => ({}), azureHeadersPaged: () => ({})
axios: {
get: async () => ({ data: { value: [{ contactid: "c1" }] } })
},
consoleLogger: () => {}
}); });
const req = { const req = {
@@ -2421,13 +2409,10 @@ test("getmylpacases returns LPA_ID_REQUIRED when lpaid missing", async () => {
const mod = loadModule("pages/api/endpoint/getmylpacases_api.js", { const mod = loadModule("pages/api/endpoint/getmylpacases_api.js", {
respondError: respondErrorMock, respondError: respondErrorMock,
respondSuccess: respondSuccessMock, respondSuccess: respondSuccessMock,
getToken: async () => ({ access_token: "token" }), relayGet: async () => ({}),
getLPA: async () => [{ name: "Test LPA", accountid: "acc1" }], getLPA: async () => [{ name: "Test LPA", accountid: "acc1" }],
jsonpath: () => [{ accountid: "acc1" }], jsonpath: () => [{ accountid: "acc1" }],
hashAPIPath: () => "&hash=expected", azureHeaders: () => ({})
azureHeaders: () => ({}),
axios: { get: async () => ({ data: { value: [] } }) },
consoleLogger: () => {}
}); });
const req = { query: {} }; const req = { query: {} };
@@ -2442,13 +2427,10 @@ test("getmylpacases returns LPA_NOT_FOUND when lpaid lookup misses", async () =>
const mod = loadModule("pages/api/endpoint/getmylpacases_api.js", { const mod = loadModule("pages/api/endpoint/getmylpacases_api.js", {
respondError: respondErrorMock, respondError: respondErrorMock,
respondSuccess: respondSuccessMock, respondSuccess: respondSuccessMock,
getToken: async () => ({ access_token: "token" }), relayGet: async () => ({}),
getLPA: async () => [{ name: "Another LPA", accountid: "acc1" }], getLPA: async () => [{ name: "Another LPA", accountid: "acc1" }],
jsonpath: () => [], jsonpath: () => [],
hashAPIPath: () => "&hash=expected", azureHeaders: () => ({})
azureHeaders: () => ({}),
axios: { get: async () => ({ data: { value: [] } }) },
consoleLogger: () => {}
}); });
const req = { query: { lpaid: "Missing LPA" } }; const req = { query: { lpaid: "Missing LPA" } };
@@ -2463,17 +2445,11 @@ test("getmylpacases catch path returns MY_LPA_CASES_FETCH_FAILED", async () => {
const mod = loadModule("pages/api/endpoint/getmylpacases_api.js", { const mod = loadModule("pages/api/endpoint/getmylpacases_api.js", {
respondError: respondErrorMock, respondError: respondErrorMock,
respondSuccess: respondSuccessMock, respondSuccess: respondSuccessMock,
getToken: async () => ({ access_token: "token" }), relayGet: async ({ res, errorResponse }) =>
respondErrorMock(res, errorResponse),
getLPA: async () => [{ name: "Test LPA", accountid: "acc1" }], getLPA: async () => [{ name: "Test LPA", accountid: "acc1" }],
jsonpath: () => [{ accountid: "acc1" }], jsonpath: () => [{ accountid: "acc1" }],
hashAPIPath: () => "&hash=expected", azureHeaders: () => ({})
azureHeaders: () => ({}),
axios: {
get: async () => {
throw new Error("relay failed");
}
},
consoleLogger: () => {}
}); });
const req = { query: { lpaid: "Test LPA" } }; const req = { query: { lpaid: "Test LPA" } };