@zambelz/zhc
Version:
API Management Tools
268 lines • 10.1 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = executeRestApi;
const node_path_1 = __importDefault(require("node:path"));
const node_fs_1 = __importDefault(require("node:fs"));
const global_1 = require("../../../utils/global");
const common_1 = require("../../../utils/common");
const config_1 = require("../../../utils/config");
const logger_1 = require("../../../utils/logger");
const scriptExecutor_1 = __importDefault(require("../shared/scriptExecutor"));
const requestScript_1 = require("../shared/requestScript");
const getEnvData = (profile, env) => {
try {
const configData = (0, config_1.getConfigData)();
const targetProfile = profile || configData?.defaultProfile;
const envDirPath = node_path_1.default.join(global_1.PROFILES_PATH, targetProfile, "env");
const targetEnv = `${env || "default"}.jsonc`;
const envFilePath = node_path_1.default.join(envDirPath, targetEnv);
const envContent = node_fs_1.default.readFileSync(envFilePath, "utf-8");
return {
path: envFilePath,
content: envContent,
};
}
catch (err) {
throw new Error(`Failed to get env data: ${err}`);
}
};
const getEndpointData = (name, profile) => {
if (!name || name.trim() === "") {
throw new Error("Name is required");
}
try {
const configData = (0, config_1.getConfigData)();
const targetProfile = profile || configData?.defaultProfile;
const endpointsDirPath = node_path_1.default.join(global_1.PROFILES_PATH, targetProfile, "endpoints");
const targetEndpointPath = name.split(":").slice(0, -1).join("/");
const targetEndpointName = name.split(":").slice(-1)[0];
const endpointFilePath = node_path_1.default.join(endpointsDirPath, `${targetEndpointPath || "default"}.jsonc`);
const endpointContent = node_fs_1.default.readFileSync(endpointFilePath, "utf-8");
const content = (0, common_1.parseContent)(endpointContent);
const data = Object.entries(content.parsed)
.filter(([key]) => key === targetEndpointName)[0];
return {
path: endpointFilePath,
data: data[1]
};
}
catch (err) {
(0, logger_1.logError)(`${err}`);
return undefined;
}
};
const assignValueFromVar = (src, target) => {
let result = { ...target };
const hasBracket = (str) => {
return str[0] === "{" && str[1] === "{"
&& str[str.length - 1] === "}" && str[str.length - 2] === "}";
};
for (const [key, value] of Object.entries(target)) {
if (!hasBracket(value)) {
continue;
}
const paramKey = value.slice(2, value.length - 2);
if (src[paramKey]) {
result[key] = src[paramKey];
}
else {
result[key] = "";
}
}
return result;
};
const assignValueFromArgs = (target, args) => {
let result = { ...target };
if (!args || args.trim() === "") {
return result;
}
const argObjects = args.split(":").map((arg) => {
const [key, value] = arg.split("=");
return { [key]: value };
});
for (const arg of argObjects) {
const key = Object.keys(arg)[0];
const value = Object.values(arg)[0];
if (target[key]) {
result[key] = value;
}
}
return result;
};
const assignValueFromScript = (target) => {
let result = { ...target };
const hasScriptSign = (str) => {
return str[0] === "<" && str[1] === "%"
&& str[str.length - 2] === "%" && str[str.length - 1] === ">";
};
const getScriptName = (key) => {
const openParenthesisIndex = key.indexOf("(");
return key.slice(2, openParenthesisIndex);
};
const getArgs = (key) => {
const openParenthesisIndex = key.indexOf("(");
const closeParenthesisIndex = key.indexOf(")");
return key.slice(openParenthesisIndex + 1, closeParenthesisIndex)
.split(",");
};
for (const [key, value] of Object.entries(target)) {
if (!hasScriptSign(value)) {
continue;
}
const scriptName = getScriptName(value);
const scriptFn = value.slice(2, value.length - 2);
const args = getArgs(scriptFn);
const valueFromScript = (0, scriptExecutor_1.default)(scriptName, ...args);
if (valueFromScript) {
result[key] = valueFromScript;
}
}
return result;
};
const assignEndpointVariables = (src, endpoint) => {
const endpointVariables = endpoint.match(/\{\{(.+?)\}\}/g);
if (!endpointVariables) {
return endpoint;
}
let result = endpoint;
for (const variable of endpointVariables) {
const variableName = variable.slice(2, variable.length - 2);
const variableValue = src[variableName];
if (!variableValue) {
continue;
}
const formattedVariable = `${variableValue}`.trim().replace(/\s+/g, " ");
const finalVariable = formattedVariable.replaceAll(/\s/g, "%20");
result = result.replace(variable, finalVariable);
}
return result;
};
const configureRequest = (envData, endpointData, additionalArgs) => {
if (!envData || !endpointData) {
(0, logger_1.logError)("Environment or endpoint data not found");
return { method: "GET", finalURL: "", requestData: {} };
}
const endpointPath = assignEndpointVariables(envData, endpointData["path"]);
const fullURL = `${envData.protocol}://${envData.baseURL}${endpointPath}`;
const method = endpointData["method"];
const headers = assignValueFromScript(assignValueFromArgs(assignValueFromVar(envData, endpointData["headers"]), additionalArgs));
const params = assignValueFromScript(assignValueFromArgs(assignValueFromVar(envData, endpointData["params"]), additionalArgs));
let finalURL = fullURL;
let requestData = {};
switch (method) {
case "GET":
// TODO: Need to revisit this part
finalURL = params && Object.keys(params).length > 0
? `${fullURL}?${new URLSearchParams(params).toString()}`
: fullURL;
requestData = {
method,
headers
};
break;
case "POST":
case "PUT":
case "PATCH":
requestData = {
method,
headers,
body: params ? params : ""
};
break;
case "DELETE":
break;
}
return { method, finalURL, requestData };
};
const constructResponse = async (method, response) => {
let responseHeaders = {};
for (const [key, value] of response.headers.entries()) {
responseHeaders[key] = value;
}
const contentType = responseHeaders["content-type"];
if (contentType.includes("text/html")) {
return await response.text();
}
const result = {};
if (response.status > 499) {
result["status"] = response.status;
result["error"] = response.statusText;
return result;
}
const responseBody = await response.json();
result[method] = response.url;
result["status"] = response.status;
result["headers"] = responseHeaders;
result["cookie"] = response.headers.getSetCookie();
result["body"] = responseBody;
return result;
};
const httpRequest = async (opt) => {
const verbose = opt?.verbose;
try {
const env = getEnvData(opt?.profile, opt?.env);
if (!env) {
(0, logger_1.logError)("Environment data not found");
return;
}
const envContent = (0, common_1.parseContent)(env.content);
const envData = envContent.parsed;
const protocol = envData.protocol;
const baseURL = envData.baseURL;
if (!protocol || !baseURL) {
(0, logger_1.logError)("Base URL not found");
return;
}
const name = opt?.call;
const endpoint = getEndpointData(name, opt?.profile);
if (!endpoint) {
(0, logger_1.logError)("Endpoint data not found");
return;
}
const endpointData = endpoint.data;
const preRequestScript = endpointData.scripts?.pre;
let updatedEnv = envData;
if (preRequestScript) {
updatedEnv = (0, requestScript_1.execPreRequestScript)(preRequestScript, env, verbose);
}
const additionalArgs = opt?.args;
const { method, finalURL, requestData } = configureRequest(envData, endpointData, additionalArgs);
if (verbose) {
(0, logger_1.logInfo)("[REST] Request Payload:");
console.log({ destination: finalURL, ...requestData });
console.log();
}
const response = await fetch(finalURL, {
...requestData,
body: JSON.stringify(requestData.body)
});
const httpResponse = await constructResponse(method, response);
if (typeof httpResponse === "string") {
return httpResponse;
}
const postRequestScript = endpointData.scripts?.post;
if (postRequestScript) {
(0, requestScript_1.execPostRequestScript)(postRequestScript, {
path: env.path,
unparseable: envContent.unparseable,
parsed: updatedEnv
}, httpResponse, verbose);
}
return httpResponse;
}
catch (err) {
(0, logger_1.logError)(`${err}`);
}
};
async function executeRestApi(options) {
console.time("[REST] API Request Time");
const response = await httpRequest(options);
console.log("[REST] API Response:");
console.dir(response, { depth: 5 });
console.log();
console.timeEnd("[REST] API Request Time");
}
//# sourceMappingURL=restApiCall.js.map