@stylework/loopback-query-parser
Version:
LoopBack 4/8 middleware to parse and coerce query parameters
68 lines (67 loc) • 1.98 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.queryParserMiddleware = void 0;
const qs_1 = __importDefault(require("qs"));
// --- Coercion Helpers ---
function coerce(value) {
if (value === "true")
return true;
if (value === "false")
return false;
if (typeof value === "string" &&
value.trim() !== "" &&
!isNaN(Number(value))) {
return Number(value);
}
return value;
}
function deepCoerce(obj) {
if (Array.isArray(obj))
return obj.map(deepCoerce);
if (obj && typeof obj === "object") {
const coerced = {};
for (const key of Object.keys(obj)) {
coerced[key] = deepCoerce(obj[key]);
}
return coerced;
}
return coerce(obj);
}
// --- Only-Whitelist Coercion Wrapper ---
const whitelistedKeys = new Set([
"filter",
"where",
"fields",
"include",
"order",
"limit",
"skip",
"offset",
"page",
"count",
]);
function selectivelyCoerceTopLevel(parsed) {
if (!parsed || typeof parsed !== "object")
return parsed;
const out = {};
for (const key of Object.keys(parsed)) {
out[key] = whitelistedKeys.has(key) ? deepCoerce(parsed[key]) : parsed[key];
}
return out;
}
// --- Middleware ---
const queryParserMiddleware = async (ctx, next) => {
const req = ctx.request;
if (req.url.includes("?")) {
const [, query] = req.url.split("?");
const parsed = qs_1.default.parse(query, { allowDots: false });
// CHANGE: Only coerce whitelisted LoopBack fields; others remain unchanged
req.query = selectivelyCoerceTopLevel(parsed);
console.log("[queryParserMiddleware] Parsed query:", req.query);
}
await next();
};
exports.queryParserMiddleware = queryParserMiddleware;
;