I have a class with methods which should give me domains of an API.
That also works so far. But if I want to render it with Node Express I get an array with 1.2.3. without the domain name.
I think my problem is located at async await?!
Here is a snippet from my class method:
class ISPConfig {
constructor(base_url, options) {
this.base_url = base_url;
this.options = options;
}
async _call() {
... // gives me the sessionId
}
async getDataByPrimaryId(ispFunction, param) {
try {
const results = await axios.post(this.base_url + ispFunction, {
session_id: await this._call(),
primary_id: param
});
return await results.data.response;
//console.log(results.data.response);
} catch (err){
console.log(err);
}
}
And her a snippet from my app.js:
const renderHome = (req, res) => {
let domains = [],
message = '';
let a = new ispwrapper.ISPConfig(BASE_URL, OPTIONS)
a.getDataByPrimaryId('sites_web_domain_get', { active: 'y' })
.then(response => {
for (let i = 0; i < response.length; i++){
domains = response[i]['domain'].domains;
}
})
.catch(err => {
message = 'Error when retriving domains from ISPApi';
})
.then(() => {
res.render('home', { // 'home' template file for output render
title: 'ISPConfig',
heading: 'Welcome to my ISPConfig Dashboard',
homeActive: true,
domains,
message
});
});
};
With push(domains) I get on the HTML page only 1.2.3.
Which corresponds exactly to the three active domains of my API. But just without the domain names. :(
But if I output in for loop console.log(response[i]['domain'].domains) I get all domains with names in console.
Does anyone see my mistake?
Here is my Solution:
const renderHome = async (req, res) => {
let domain = [],
message = '';
try {
let a = new ispwrapper.ISPConfig(BASE_URL, OPTIONS);
const response = await a.getDataByPrimaryId('sites_web_domain_get', { active: 'y' });
for (let i = 0; i < response.length; i++){
domain.push(response[i].domain);
}
} catch(err) {
message = 'Error when retriving domains from ISPApi';
} finally {
res.render('home', { // 'home' template file for output render
title: 'ISPConfig',
heading: 'Welcome to my ISPConfig Dashboard',
homeActive: true,
domain,
message
});
}
};
Try making your route async too like:
const renderHome = async (req, res) => {
let domains = [],
message = '';
try {
let a = new ispwrapper.ISPConfig(BASE_URL, OPTIONS)
const response = await a.getDataByPrimaryId('sites_web_domain_get', { active: 'y' })
for (let i = 0; i < response.length; i++){
domains.push(response[i].domain);
}
} catch(err) {
message = 'Error when retriving domains from ISPApi';
} finally {
res.render('home', { // 'home' template file for output render
title: 'ISPConfig',
heading: 'Welcome to my ISPConfig Dashboard',
homeActive: true,
domains,
message
});
}
};
Yes ok the undefined is no problem anymore. But how do I get the domains displayed on the HTML page? The call is grey.
Related
I'm strugeling with async/await order, I need the code to wait for the getAttachements and proceed after but thats not working atm. I have looked at some options on SE for example a callback function but i did not get it to work yet.
processJsonToXML()
async function processJsonToXML() {
for (let i = 0; i < wordpressOutput.length; i++) {
imageUrls = []
let obj = wordpressOutput[i];
let content = processContent(obj.Content)
await getAttachments().then(attachments =>{
const filledXml = xmlTemplate(
{
title: obj.Title,
content: content,
date: obj.Date,
summary: obj.Excerpt,
unixTime: moment(obj.Date).unix(),
attachments: attachments
}
)
fs.writeFile(`xml-files/${obj.Title}.xml`, filledXml, function (err) {
if (err) throw err;
console.log('File is created successfully.');
});
})
}
}
Second part is the code to fetch an url and create a object out of it with the info I need in the first function.
async function getAttachments(){
const attachments: attachment[] = []
imageUrls.forEach(async url => {
let filename = extractUsingRegex(url, /([a-zA-Z0-9\s_\\.\-\(\):])+(.png|.jpg)/gm);
await fetch(url).then(response => {
response.buffer().then(resolvedBuffer => {
let attachment: attachment = {
type: response.type,
content: resolvedBuffer.toString('base64'),
filename: filename,
size: response.size.toString()
}
console.log(attachment);
attachments.push(attachment)
})
});
})
return attachments
}
Your first part of the code should look like this
processJsonToXML();
async function processJsonToXML() {
await Promise.all(
wordpressOutput.map(async (obj) => {
imageUrls = [];
let content = processContent(obj.Content);
let attachments = await getAttachments();
const filledXml = xmlTemplate({
title: obj.Title,
content: content,
date: obj.Date,
summary: obj.Excerpt,
unixTime: moment(obj.Date).unix(),
attachments: attachments,
});
fs.writeFile(`xml-files/${obj.Title}.xml`, filledXml, function (err) {
if (err) throw err;
console.log("File is created successfully.");
});
}) );}
And Second part of your code should look like this
async function getAttachments(){
const attachments: attachment[] = []
await Promise.all(
imageUrls.map(async url => {
let filename = extractUsingRegex(url, /([a-zA-Z0-9\s_\\.\-\(\):])+(.png|.jpg)/gm);
await fetch(url).then(response => {
response.buffer().then(resolvedBuffer => {
let attachment: attachment = {
type: response.type,
content: resolvedBuffer.toString('base64'),
filename: filename,
size: response.size.toString()
}
console.log(attachment);
attachments.push(attachment)
})
});
}));
return attachments
}
I hope this will help
I am uploading files to GraphQL API with plain JS. I've been doing this from the same origin for months now and now am trying to implement the exact same thing externally with NodeJS.
My code looks something like this:
const FormData = require('form-data');
const fs = require('fs')
const axios = require('axios')
const payload = generateRequest(input)
axios.post(apiBaseUrl + "/graphql", payload, {
headers: {...payload.getHeaders()}
}).then(response => {
let res = response.data
if (res.data.triggerPcWorkflow.status === 200) {
console.log("success!")
} else {
console.error(res.data.triggerPcWorkflow.message)
}
})
.catch(err => {
if (err.response) {
console.log(err.response.data);
console.log(err.response.status);
console.log(err.response.headers);
}
})
With the generateRequest function generating the multipart payload (https://github.com/jaydenseric/graphql-multipart-request-spec).
I have two identical versions of the Backend running on localhost:5000 and mycooldomain.com. When setting apiBaseUrl to http://localhost:5000 everything works flawlessly. However just by changing the URL to https://www.mycooldmain.com I get a 400 error thrown at me with { errors: [ { message: 'Must provide query string.' } ] }
BTW: A simple query works with both URLs...
Here is my generateRequest function:
const mutation = `
mutation MyMutation($xyz: String) {
doSomething(myInput: $xyz) {
status
message
}
}
`
let sendData = new FormData();
const fileNull = [];
// map
files = generateRequestInput.files
let map = '{'
for (let i = 0; i < files.length; i++) {
fileNull.push(null);
map += `"${i}": ["variables.files.${i}"], `
}
map = map.substring(0, map.length-2);
map += '}'
// operations
const operations = JSON.stringify({
query: mutation,
variables: {
"xyz": "Hello"
}
});
// build payload
sendData.append("operations", operations)
sendData.append("map", map)
for (let i = 0; i < files.length; i++) {
sendData.append(i, files[i]);
}
return sendData
I know that map looks a bit ugly but thats not the point (unless it is).
Has anyone had a similar problem or knows what my error is here?
Thanks!
I skipped on the axios dependency and implemented the request with FormData directly.
The code below works.
function makeRequest(formData, options) {
formData.submit(options, (err, res) => {
if (err) {
console.error(err.message)
return
} else {
if (res.statusCode < 200 || res.statusCode > 299) {
console.error(`HTTP status code ${res.statusCode}`)
}
const body = []
res.on('data', (chunk) => body.push(chunk))
res.on('end', () => {
const resString = Buffer.concat(body).toString()
console.log(resString)
})
}
})
}
const options = {
host: 'mycooldomain.com',
port: 443,
path: '/graphql',
method: 'POST',
protocol: 'https:'
}
makeRequest(payload, options)
I'm new here on the site, and new to React.
I built a function that works great in nodejs. There are rare cases where I want to run this function according to the parameters I send it to, so I try to send it the parameters but I think I can not, I try to print it - and I do not get a print of the parameters I want to send.
i run the function throw click at buttom in react:
<Button onClick={() => {
const result = [1,2,3,4,5,"test"];
props.makeMatchVer2(result);
}}>
make match ver2
</Button>
the action I'm run in axios:
export const makeMatchVer2 = (data) => (dispatch) => {
dispatch({ type: LOADING_DATA });
axios
.get('/kmeans', {
params: {
filterArray: data
}
})
.then((res) => {
dispatch({
type: MAKE_MATCH,
payload: res.data
});
})
.catch((err) => {
dispatch({
type: MAKE_MATCH,
payload: []
});
});
};
the function I'm build in nodeJS:
exports.addUserKmeansMatch = (req, res) => {
console.log("addUserKmeansMatch function start:");
console.log(req.data);
if(req.params)
{
console.log(req.params);
}
let userIndex = 0;
let engineers = [];
let engineersHandles = [];
let engineerDetailsNumeric = {};
db.collection("preferences").get().then(querySnapshot => {
querySnapshot.forEach(doc => {
const engineerDetails = doc.data();
if (engineerDetails.handle === req.user.handle) {
engineersHandles.unshift(engineerDetails.handle);
delete engineerDetails.handle;
engineerDetailsNumeric = convertObjectWithStrToNumber(engineerDetails);
engineers.unshift(engineerDetailsNumeric);
}
else {
engineersHandles.push(engineerDetails.handle);
delete engineerDetails.handle;
engineerDetailsNumeric = convertObjectWithStrToNumber(engineerDetails);
engineers.push(engineerDetailsNumeric);
}
});
kmeans.clusterize(engineers, { k: 4, maxIterations: 5, debug: true }, (err, result) => {
if (err) {
console.error(err);
return res.status(500).json({ error: err.code });
} else {
const cluster = result.clusters;
let foundedMatches = GetUserSerialGroup(userIndex, [...cluster], [...engineers]);
let foundedMatchesHandle = GetUserSerialGroupHandle(userIndex, [...cluster], [...engineersHandles]);
let totalTest = {
foundedMatches: foundedMatches,
foundedMatchesHandle: foundedMatchesHandle,
cluster: cluster,
engineersHandles: engineersHandles,
engineers: engineers
};
let userMatchHandle = reduceUserMatchHandle(foundedMatchesHandle);
userMatchHandle.handle = req.user.handle;
db.doc(`/match/${req.user.handle}`)
.set(userMatchHandle)
.then(() => {
return res.json({ message: "Details added successfully" });
})
.catch((err) => {
console.error(err);
return res.status(500).json({ error: err.code });
});
}
})
})
};
Through the button, I send parameters to the function, but I do not see their print, probably something does not work, but I do not know why, I'm new to it
makeMatchVer2 is a thunk. You should call it with dispatch: dispatch(props.makeMatchVer2(result))
The code is correct, I accidentally sent the wrong object, I have 2 objects with almost identical names, one array and the other an object. And I accidentally sent the object instead of the array, it's working right now, thank you.
basically what I want to achieve is check in a middleware whether an uploaded file has the correct image type (png for example). This is what I have come up with till now:
export const fileCheckMiddleware = (req, res, next) => {
const acceptedImageTypes = ["image/gif", "image/jpeg", "image/png"];
const oldWrite = res.write;
const oldEnd = res.end;
const chunks = [];
res.write = (...restArgs) => {
chunks.push(new Buffer(restArgs[0]));
oldWrite.apply(res, restArgs);
};
res.end = async (...restArgs) => {
if (restArgs[0]) {
chunks.push(new Buffer(restArgs[0]));
}
const body = Buffer.concat(chunks).toString("utf8");
try {
let parsedBody = {};
try {
parsedBody = JSON.parse(body);
} catch (err) {
parsedBody = { data: { unparsedBody: body } };
}
const { variables } = req.body;
console.log("\x1b[1m%s\x1b[0m", "LOG variables", variables.file);
if (variables.file) {
console.log("\x1b[1m%s\x1b[0m", "LOG type", typeof variables.file);
}
} catch (err) {}
oldEnd.apply(res, restArgs);
};
next();
};
The logged type of variables.file is an object. And the result of the console.log is this:
LOG variables Promise {
{ filename: 'trump.jpeg',
mimetype: 'image/jpeg',
encoding: '7bit',
createReadStream: [Function: createReadStream] } }
So how can I access the mimetype here? I tried to map over the keys, variables.file["Promise"],...
Promise is not a key of variables.file, it's the type of variables.file. That means your code starts executing as soon as the HTTP request starts, and the file is received asynchronously, so you have to do something like:
variables.file.then(file => {
// Do whatever you want with the file
next();
});
Or declare the surrounding function as async and do this:
const file = await variables.file;
// Do whatever you want with the file
next();
Currently I have axios and cheerio return data from a webpage. I then setup express to setup a few views. I double checked my index.hbs and it include {{data}} inside the body. This should allow the page to render the text from the index render data: dealss . Am I missing anything ? The dealss obj holds 4 different objects that I can access.
getdeals(result => console.log(result.totaldeals[0].date))
This returns [ 09/04/2019/ ] in the console.
const path = require('path')
const express = require('express')
const hbs = require('hbs')
const axios = require('axios');
const cheerio = require('cheerio');
const app = express()
// Define paths for express config
const publicDirPath = path.join(__dirname, '../public')
const viewsPath = path.join(__dirname, '../templates/views')
const partialsPath = path.join(__dirname, '../templates/partials')
// Setup handlebars engine and views location
app.set('view engine', 'hbs')
app.set('views', viewsPath)
hbs.registerPartials(partialsPath)
// Setup static directory to serve
app.use(express.static(publicDirPath))
// Views
app.get('', (req, res) => {
res.render('index', {
title: 'ClearVision',
data: dealss,
name: 'Chris'
})
})
app.get('/about', (req, res) => {
res.render('about', {
title: 'ClearVision - About Us',
header: 'About Us',
name: 'Chris'
})
})
app.get('/help', (req, res) => {
res.render('help', {
title: 'ClearVision - Help',
helptext: 'Please contact x for help.',
name: 'Chris'
})
})
app.get('/weather', (req, res) => {
res.send({
forecast: 'It is sunny.',
location: 'x, Ca'
})
})
app.listen(1337, () => {
console.log('Server is currently running on port 1337.')
})
const url = 'https://abcdef.com/';
axios.defaults.withCredentials = true
// Get the deals
const getdeals = (callback) => {
axios(url, {
headers: {
Cookie: "x=xx;"
}
})
.then(response => {
const html = response.data;
const $ = cheerio.load(html);
// Deals Page
const statsTable = $('tbody > tr');
const totaldeals = [];
// Loop Table for data in each row
statsTable.each(function () {
const nwline = "\n"
let date = $(this).find('td:nth-child(1)').text()
let bodydeals = $(this).find('td:nth-child(2)').text()
let newdeal = $(this).find('td:nth-child(3)').text()
let revdeal = $(this).find('td:nth-child(4)').text()
let monthlydealrev = $(this).find('td:nth-child(5)').text()
// Clear /n
if (date.includes(nwline)) {
date = date.toString().replace("\n", ""),
date = date.toString().replace("\n", "")
}
// Clear /n
if (bodydeals.includes(nwline)) {
bodydeals = bodydeals.toString().replace("\n", ""),
bodydeals = bodydeals.toString().replace("\n", ""),
bodydeals = bodydeals.toString().replace("\n", "")
}
// Clear /n
if (newdeal.includes(nwline)) {
newdeal = newdeal.toString().replace("\n", ""),
newdeal = newdeal.toString().replace("\n", ""),
newdeal = newdeal.toString().replace("\n", "")
}
// Clear /n
if (revdeal.includes(nwline)) {
revdeal = revdeal.toString().replace("\n", ""),
revdeal = revdeal.toString().replace("\n", ""),
revdeal = revdeal.toString().replace("\n", "")
}
// Clear /n (lookup jquery table functions)
if (monthlydealrev.includes(nwline)) {
monthlydealrev = monthlydealrev.toString().replace("\n", ""),
monthlydealrev = monthlydealrev.toString().replace("\n", ""),
monthlydealrev = monthlydealrev.toString().replace("\n", "")
}
totaldeals.push({
date,
bodydeals,
newdeal,
revdeal,
monthlydealrev
})
})
callback({
totaldeals
})
//console.log(totaldeals[1].date)
})
.catch(console.error);
}
function newFunction() {[getdeals(result => console.log(result.totaldeals))]}
I added a data: dealss under the res.render for the index. I also checked the index.hbs which has {{data}} in there. Shouldn't this just add the text to the screen?
Any ideas on how to print it to the view?
You just need to pass it as a variable to your hbs file:
app.get('', (req, res) => {
getdeals(result => {
res.render('index', {
title: 'ClearVision',
data: result, // or result.totaldeals depending
name: 'Chris' // on what you really mean
})
});
})
Improvements
If you rewrite getdeals() to return a Promise instead of accepting a callback you can use async/await:
const getdeals = () => {
// NOTE THIS CHANGE, return axios promise:
return axios(url, {
/* ... */
})
.then(response => {
/* .. */
statsTable.each(function () {
/* .. */
})
return totaldeals; // NOTE we return the result instead
// of calling a callback. This will
// return a resolved Promise
})
// Don't catch here, your request will hang if an error occurs
}
Now with the change above (return axios and return the result) we can rewrite the route as:
app.get('', async (req, res, next) => { // must have async keyword!
try {
let result = await getdeals();
res.render('index', {
title: 'ClearVision',
data: result, // or result.totaldeals depending
name: 'Chris' // on what you really mean
})
}
catch (err) {
console.log(err);
next(err); // this will close the request socket
}
})