TASK22211: normalize advanced search paged endpoint contract

This commit is contained in:
2026-03-23 12:07:40 +00:00
parent 98e159d523
commit 88e4586541
2 changed files with 209 additions and 90 deletions
@@ -48,33 +48,69 @@
// */ // */
import axios from "axios"; import axios from "axios";
import CryptoJS from "crypto-js";
import _ from "lodash"; import _ from "lodash";
import { import { azureHeadersPagedCustom } from "../../../actions/core/headers";
azureHeadersPagedCustom,
azureHeadersPaged,
azureHeaders
} from "../../../actions/core/headers";
import { consoleLogger } from "../../../actions/core/logger"; import { consoleLogger } from "../../../actions/core/logger";
import { getToken } from "../../../actions/core/token"; import { getToken } from "../../../actions/core/token";
import { hashAPIPath } from "../../../actions/core/hash"; import { hashAPIPath } from "../../../actions/core/hash";
import { respondError, respondSuccess } from "../middleware/apiResponse";
const WEBAPI_URL = const WEBAPI_URL =
process.env.RELAY_ROOT || process.env.RELAY_ROOT ||
"https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/"; "https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/";
export default async function ApiProxy(req, res) { export default async function ApiProxy(req, res) {
var searchString = req.query.searchstring; const rawSearchString = req.query.searchstring;
var pageNumber = req.query.pageNumber; const pageNumber = req.query.pageNumber;
var token = await getToken(); const orderby = req.query.orderby;
const fieldSort = req.query.fieldSort;
const showNumberOfRecords = req.query.showNumberOfRecords;
var orderby = req.query.orderby; if (
var fieldSort = req.query.fieldSort; typeof rawSearchString !== "string" ||
var showNumberOfRecords = req.query.showNumberOfRecords; rawSearchString.trim().length === 0
) {
return respondError(res, {
status: 400,
code: "SEARCH_STRING_REQUIRED",
message: "searchstring is required"
});
}
if (typeof orderby !== "string" || orderby.trim().length === 0) {
return respondError(res, {
status: 400,
code: "ORDER_BY_REQUIRED",
message: "orderby is required"
});
}
if (typeof fieldSort !== "string" || fieldSort.trim().length === 0) {
return respondError(res, {
status: 400,
code: "FIELD_SORT_REQUIRED",
message: "fieldSort is required"
});
}
if (
typeof showNumberOfRecords !== "string" ||
showNumberOfRecords.trim().length === 0
) {
return respondError(res, {
status: 400,
code: "SHOW_NUMBER_OF_RECORDS_REQUIRED",
message: "showNumberOfRecords is required"
});
}
searchString = _.isEmpty(searchString) let searchString;
? searchString try {
: JSON.parse(decodeURI(searchString)); searchString = JSON.parse(decodeURI(rawSearchString));
} catch (error) {
return respondError(res, {
status: 400,
code: "INVALID_SEARCH_STRING",
message: "searchstring must be valid encoded JSON"
});
}
var queryString = ""; var queryString = "";
@@ -146,19 +182,15 @@ export default async function ApiProxy(req, res) {
console.log("adv qu: ", queryUrl); console.log("adv qu: ", queryUrl);
var apiResponse = _.isEmpty(searchString) try {
? res.status(400).json() const token = await getToken();
: axios const { data } = await axios.get(
.get(
WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
azureHeadersPagedCustom( azureHeadersPagedCustom(token.access_token, showNumberOfRecords)
token.access_token, );
showNumberOfRecords
) let dataStr;
) _.has(data, "@odata.nextLink") === true &&
.then(async ({ data }) => {
var dataStr;
_.has(data, "@odata.nextLink") == true &&
((dataStr = JSON.stringify(data["@odata.nextLink"])), ((dataStr = JSON.stringify(data["@odata.nextLink"])),
(data["@odata.nextLink"] = dataStr.split("/v8.2/")[1])); (data["@odata.nextLink"] = dataStr.split("/v8.2/")[1]));
@@ -216,14 +248,15 @@ export default async function ApiProxy(req, res) {
// data["@odata.count"] = data.value.length; // data["@odata.count"] = data.value.length;
} }
res.status(200).json(data); return respondSuccess(res, data);
}) } catch (error) {
.catch((error) => {
consoleLogger(error); consoleLogger(error);
res.status(400).json(error); return respondError(res, {
status: 400,
code: "ADVANCED_SEARCH_PAGED_FETCH_FAILED",
message: "Failed to fetch advanced search paged results"
}); });
}
return apiResponse;
} }
// export default async function ApiProxy(req, res) { // export default async function ApiProxy(req, res) {
@@ -971,6 +971,92 @@ test("getadvancedsearch catch path returns ADVANCED_SEARCH_FETCH_FAILED", async
); );
}); });
test("getadvancedsearchpaged returns SEARCH_STRING_REQUIRED when searchstring missing", async () => {
const mod = loadModule("pages/api/endpoint/getadvancedsearchpaged_api.js", {
respondError: respondErrorMock,
respondSuccess: respondSuccessMock,
getToken: async () => ({ access_token: "token" }),
hashAPIPath: () => "&hash=expected",
azureHeadersPagedCustom: () => ({}),
axios: { get: async () => ({ data: { value: [] } }) },
consoleLogger: () => {},
_: { has: () => false }
});
const req = {
query: {
orderby: "createdon",
fieldSort: "asc",
showNumberOfRecords: "10"
}
};
const res = createRes();
await mod.default(req, res);
assert.strictEqual(res.state.statusCode, 400);
assert.strictEqual(res.state.jsonBody.error.code, "SEARCH_STRING_REQUIRED");
});
test("getadvancedsearchpaged returns ORDER_BY_REQUIRED when orderby missing", async () => {
const mod = loadModule("pages/api/endpoint/getadvancedsearchpaged_api.js", {
respondError: respondErrorMock,
respondSuccess: respondSuccessMock,
getToken: async () => ({ access_token: "token" }),
hashAPIPath: () => "&hash=expected",
azureHeadersPagedCustom: () => ({}),
axios: { get: async () => ({ data: { value: [] } }) },
consoleLogger: () => {},
_: { has: () => false }
});
const req = {
query: {
searchstring: encodeURI(JSON.stringify({ q: "cas" })),
fieldSort: "asc",
showNumberOfRecords: "10"
}
};
const res = createRes();
await mod.default(req, res);
assert.strictEqual(res.state.statusCode, 400);
assert.strictEqual(res.state.jsonBody.error.code, "ORDER_BY_REQUIRED");
});
test("getadvancedsearchpaged catch path returns ADVANCED_SEARCH_PAGED_FETCH_FAILED", async () => {
const mod = loadModule("pages/api/endpoint/getadvancedsearchpaged_api.js", {
respondError: respondErrorMock,
respondSuccess: respondSuccessMock,
getToken: async () => ({ access_token: "token" }),
hashAPIPath: () => "&hash=expected",
azureHeadersPagedCustom: () => ({}),
axios: {
get: async () => {
throw new Error("relay failed");
}
},
consoleLogger: () => {},
_: { has: () => false }
});
const req = {
query: {
searchstring: encodeURI(JSON.stringify({ q: "cas" })),
orderby: "createdon",
fieldSort: "asc",
showNumberOfRecords: "10"
}
};
const res = createRes();
await mod.default(req, res);
assert.strictEqual(res.state.statusCode, 400);
assert.strictEqual(
res.state.jsonBody.error.code,
"ADVANCED_SEARCH_PAGED_FETCH_FAILED"
);
});
test("getsearchdocumenthistory returns DOCUMENT_ID_REQUIRED when documentid missing", async () => { test("getsearchdocumenthistory returns DOCUMENT_ID_REQUIRED when documentid missing", async () => {
const mod = loadModule( const mod = loadModule(
"pages/api/endpoint/getsearchdocumenthistory_api.js", "pages/api/endpoint/getsearchdocumenthistory_api.js",