node-red-contrib-conta-azul-api
Version:
Conta Azul API wrapper for Node-Red
225 lines (206 loc) • 6.85 kB
JavaScript
const {
createNewApiList,
getNewServerUrl,
identifyOperation,
} = require("./libs/server.js");
const { createBackwardCompatible } = require("./libs/utils.js");
const fs = require("fs");
const path = require("path");
const yaml = require("js-yaml");
const https = require("https");
const Swagger = require("swagger-client");
const download = async (url) => {
await new Promise((resolve, reject) => {
https.get(url, (res) => {
const dirPath = `${__dirname}/contaAzul.yaml`;
const filePath = fs.createWriteStream(dirPath);
res.pipe(filePath);
filePath.on('finish', () => {
filePath.close();
console.log('Download Completed');
resolve();
});
}).on('error', (err) => {
reject(err);
});
});
};
module.exports = function (RED) {
function contaAzul(config) {
RED.nodes.createNode(this, config);
const node = this;
node.on("input", function (msg, send, done) {
send =
send ||
function () {
node.send.apply(node, arguments);
};
createBackwardCompatible(config);
const sendError = (e) => {
node.status({ fill: "red", shape: "dot", text: "Error" });
let errorMsg = e.message;
if (e.message && isNaN(e.message.substring(0, 1)) && e.status) {
errorMsg = e.status + " " + e.message;
}
msg.response = e.response;
if (config.errorHandling === "other output") {
send([null, msg]);
} else if (config.errorHandling === "throw exception") {
if (done) {
done(errorMsg);
} else {
node.error(errorMsg, msg);
}
} else {
send(msg);
if (done) done();
}
};
const openApiUrl = "https://api.contaazul.com/schema";
let parameters = {};
let requestBody = {}; // we need a separate parameter for body in OpenApi 3
if (msg.openApi && msg.openApi.parameters) {
parameters = msg.openApi.parameters;
} else {
for (const p in config.parameters) {
const param = config.parameters[p];
let evaluatedInput = RED.util.evaluateNodeProperty(
param.value,
param.type,
this,
msg
);
// query input can't be object
if (typeof evaluatedInput === "object" && param.in === "query") {
evaluatedInput = JSON.stringify(evaluatedInput);
}
// can't use 'if (evaluatedInput)' due to values false and 0
if (
param.required &&
(evaluatedInput === "" ||
evaluatedInput === null ||
evaluatedInput === undefined)
) {
return done(`Required input for ${param.name} is missing.`, msg);
}
if (param.isActive) {
if (param.name !== "Request body") {
parameters[param.name] = evaluatedInput;
} else {
requestBody = evaluatedInput;
}
}
}
}
const { operationId, pathName, method } = identifyOperation(config);
// fallback if no content type can be found
let requestContentType = "application/json";
if (config.requestContentType)
requestContentType = config.requestContentType;
const openApiOptions = {
operationId,
pathName,
method,
parameters,
requestBody,
requestContentType,
// if available put token for auth
requestInterceptor: (req) => {
if (msg.openApiToken)
req.headers.Authorization = "Bearer " + msg.openApiToken;
if (msg.headers)
req.headers = Object.assign(req.headers || {}, msg.headers);
if (!config.keepAuth) {
delete msg.openApiToken;
delete msg.headers;
}
/**
* Warning: Reroute to a different server is experimental: should work as stated in https://github.com/swagger-api/swagger-js/issues/1901
*/
if (config.server && config.alternServer) {
req.url = getNewServerUrl(config, openApiUrl, req.url);
}
},
};
if (config.responseContentType)
openApiOptions.responseContentType = config.responseContentType;
let initiateOptions = {
url: openApiUrl,
};
if (node.devMode) {
const agent = require("https").Agent({
rejectUnauthorized: false,
});
initiateOptions.http = (request) => Swagger.http({ ...request, agent });
openApiOptions.http = (request) => Swagger.http({ ...request, agent });
}
const openapiYaml = path.join(__dirname, "contaAzul.yaml");
if (fs.existsSync(openapiYaml)) {
const spec = yaml.load(fs.readFileSync(openapiYaml), "utf8");
initiateOptions = { spec: spec };
} else {
download(openApiUrl)
}
// Start Swagger / OpenApi
Swagger(initiateOptions)
.then((client) => {
node.status({ fill: "yellow", shape: "dot", text: "Retrieving..." });
client
.execute(openApiOptions)
.then((res) => {
node.status({});
msg.payload = res;
send(msg);
if (done) done();
})
.catch((e) => {
return sendError(e);
});
})
.catch((e) => {
return sendError(e);
});
});
}
RED.nodes.registerType("conta-azul", contaAzul);
RED.httpAdmin.get("/getContaAzulSpec", (request, response) => {
const openApiUrl = "https://api.contaazul.com/schema";
let options = {
url: decodeURIComponent(openApiUrl),
};
if (request.query.devMode === "true") {
const agent = require("https").Agent({
rejectUnauthorized: false,
});
options.http = (request) => Swagger.http({ ...request, agent });
}
const openapiYaml = path.join(__dirname, "contaAzul.yaml");
if (fs.existsSync(openapiYaml)) {
const spec = yaml.load(fs.readFileSync(openapiYaml), "utf8");
options = { spec: spec };
} else {
download(openApiUrl)
}
Swagger(options)
.then((client) => {
const newApiList = createNewApiList(client);
response.send({
apiList: newApiList,
info: client.spec.info,
security: client.spec.security,
servers: client.spec.servers,
});
})
.catch((e) => {
if (e.message) {
let errorMsg = e.message;
if (e && e.response && e.response.data) {
errorMsg = errorMsg + ": " + e.response.data;
}
response.send(errorMsg);
} else {
throw new Error("Error" + e);
}
});
});
};