From f16161bcee15ab25a002a0c5d12f52e3cbdb927c Mon Sep 17 00:00:00 2001 From: robbond Date: Tue, 17 Mar 2026 12:55:05 +0000 Subject: [PATCH] TASK22102: slice2 migrate remaining email handlers --- memory-bank/change-log.md | 32 ++++++++++++++++++++++++++++++++ pages/api/email/getall.js | 9 ++++++--- pages/api/email/getcaseref.js | 10 +++++++--- pages/api/email/getdocuments.js | 17 +++++++++++------ pages/api/email/getevents.js | 23 ++++++++++++++++------- 5 files changed, 72 insertions(+), 19 deletions(-) diff --git a/memory-bank/change-log.md b/memory-bank/change-log.md index 300c2dec..b3268476 100644 --- a/memory-bank/change-log.md +++ b/memory-bank/change-log.md @@ -1339,3 +1339,35 @@ Follow-ups: - Slice 2 should migrate remaining email handlers (`getcaseref`, `getall`, `getevents`, `getdocuments`) to helper responses. - After email/admin completion, expand to selected high-risk file handlers using same non-breaking helper model. + +--- + +### CL-036: TASK22102 API contract consistency — Slice 2 (remaining email handlers) + +date: 2026-03-17 +author: Cline +scope: `pages/api/email/{getcaseref,getall,getevents,getdocuments}.js` +type: change +rationale: Complete the email-domain response-contract consistency rollout by moving remaining handlers to shared helper-based success/error responses. +impact: Removes raw error passthrough in remaining email handlers and standardizes structured error envelopes while preserving success payload compatibility. +status: completed + +Summary: + +- Migrated remaining email handlers to shared response helper usage: + - `getcaseref` + - `getall` + - `getevents` + - `getdocuments` +- Replaced direct `res.status(...).json(...)` branches with: + - `respondSuccess(...)` + - `respondError(...)` +- Added stable error codes/messages for expected negative paths and catch branches. + +Validation: + +- `npx next lint --file pages/api/email/getcaseref.js --file pages/api/email/getevents.js --file pages/api/email/getdocuments.js --file pages/api/email/getall.js` -> pass (no warnings/errors) + +Follow-ups: + +- Next slice can target selected file handlers for equivalent response contract cleanup. diff --git a/pages/api/email/getall.js b/pages/api/email/getall.js index d423a303..e54812ac 100644 --- a/pages/api/email/getall.js +++ b/pages/api/email/getall.js @@ -6,6 +6,7 @@ import { consoleLogger } from "../../../actions/core/logger"; import { getToken } from "../../../actions/core/token"; import { formatDates } from "../../../components/utils"; import { hashAPIPath } from "../../../actions/core/hash"; +import { respondError, respondSuccess } from "../middleware/apiResponse"; var NotifyClient = require("notifications-node-client").NotifyClient; @@ -439,11 +440,13 @@ export default async function CombinedApiProxy(req, res) { sendingResults.push(result); } - res.status(200).json({ sendingResults }); + return respondSuccess(res, { sendingResults }); } catch (error) { consoleLogger(error); - res.status(500).json({ - error: "An error occurred while retrieving combined data.", + return respondError(res, { + status: 500, + code: "EMAIL_COMBINED_FETCH_FAILED", + message: "An error occurred while retrieving combined data.", details: error.message || error.toString() }); } diff --git a/pages/api/email/getcaseref.js b/pages/api/email/getcaseref.js index ab259902..b4aa179d 100644 --- a/pages/api/email/getcaseref.js +++ b/pages/api/email/getcaseref.js @@ -5,6 +5,7 @@ import { azureHeaders } from "../../../actions/core/headers"; import { consoleLogger } from "../../../actions/core/logger"; import { getToken } from "../../../actions/core/token"; import { hashAPIPath } from "../../../actions/core/hash"; +import { respondError, respondSuccess } from "../middleware/apiResponse"; const WEBAPI_URL = process.env.RELAY_ROOT || @@ -23,7 +24,6 @@ function flattenWatchlistEntry(entry) { } export default async function ApiProxy(req, res) { - const incidentID = req.query.incidentid; var token = await getToken(); var queryUrl = @@ -39,10 +39,14 @@ export default async function ApiProxy(req, res) { const flattenedResults = data.value.map(flattenWatchlistEntry); - res.status(200).json(flattenedResults); + return respondSuccess(res, flattenedResults); }) .catch((error) => { consoleLogger(error); - res.status(400).json(error); + return respondError(res, { + status: 400, + code: "CASE_REF_FETCH_FAILED", + message: "Failed to fetch case references" + }); }); } diff --git a/pages/api/email/getdocuments.js b/pages/api/email/getdocuments.js index 781d74cb..3caa7ef7 100644 --- a/pages/api/email/getdocuments.js +++ b/pages/api/email/getdocuments.js @@ -5,6 +5,7 @@ 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 { respondError, respondSuccess } from "../middleware/apiResponse"; const WORDKEY = process.env.HASHKEY; const WEBAPI_URL = @@ -26,9 +27,11 @@ export default async function ApiProxy(req, res) { const incidentID = req.query.incidentid; if (!incidentID) { - return res - .status(400) - .json({ error: "incidentid query parameter is required." }); + return respondError(res, { + status: 400, + code: "INCIDENT_ID_REQUIRED", + message: "incidentid query parameter is required." + }); } try { @@ -79,11 +82,13 @@ export default async function ApiProxy(req, res) { ) })); - res.status(200).json({ ...data, value: resultsWithLinks }); + return respondSuccess(res, { ...data, value: resultsWithLinks }); } catch (error) { consoleLogger(error); - res.status(500).json({ - error: "Failed to fetch document details.", + return respondError(res, { + status: 500, + code: "DOCUMENTS_FETCH_FAILED", + message: "Failed to fetch document details.", details: error.message || error.toString() }); } diff --git a/pages/api/email/getevents.js b/pages/api/email/getevents.js index 75fc8e50..79c9feda 100644 --- a/pages/api/email/getevents.js +++ b/pages/api/email/getevents.js @@ -5,6 +5,7 @@ import { azureHeaders } from "../../../actions/core/headers"; import { consoleLogger } from "../../../actions/core/logger"; import { getToken } from "../../../actions/core/token"; import { hashAPIPath } from "../../../actions/core/hash"; +import { respondError, respondSuccess } from "../middleware/apiResponse"; const WORDKEY = process.env.HASHKEY; const WEBAPI_URL = @@ -18,7 +19,11 @@ export default async function ApiProxy(req, res) { const { incidentID } = req.query; if (!incidentID) { - return res.status(400).json({ error: "incidentID is required" }); + return respondError(res, { + status: 400, + code: "INCIDENT_ID_REQUIRED", + message: "incidentID is required" + }); } try { @@ -34,9 +39,11 @@ export default async function ApiProxy(req, res) { const sipsRecords = _.get(sipsResponse, "data.value", []); if (sipsRecords.length === 0) { - return res - .status(404) - .json({ error: "No SIPs record found for this incidentID." }); + return respondError(res, { + status: 404, + code: "SIPS_RECORD_NOT_FOUND", + message: "No SIPs record found for this incidentID." + }); } const sipsId = sipsRecords[0].pinswg_sipsid; @@ -53,11 +60,13 @@ export default async function ApiProxy(req, res) { azureHeaders(token.access_token) ); - res.status(200).json(eventsResponse.data); + return respondSuccess(res, eventsResponse.data); } catch (error) { consoleLogger(error); - res.status(500).json({ - error: "An error occurred while retrieving data.", + return respondError(res, { + status: 500, + code: "EVENTS_FETCH_FAILED", + message: "An error occurred while retrieving data.", details: error.message || error.toString() }); }