I am new to React and Node js. I have defined a function that run a Python script from my Node.js application using child process, and I have an router post that called pythonExecute and return that result back to
React. Router seemed to have trouble sending the data back to react using react.json(data),can someone please help and see what I did wrong and how to fix it?
Function
const pythonExecute = (data, input) => {
const res = {
err: false,
msg: ""
}
return new Promise((resolve, reject)=>{
const fileName = "test.py"
saveFile(fileName, data)
.then(()=>{
const filePath = path.join(__dirname,"../test.py")
const spawn = require("child_process").spawn;
const pythonProcess = spawn('python',[filePath]);
pythonProcess.stdout.on('data', (data) => {
console.log(data.toString());
resolve(data)
});
})
.catch(()=>{
console.log("ERROR SAVE FILE"+ saveFileRes)
const err = {
err: true,
output: "Internal Server Error!"
}
resolve(err)
})
})
Express Router
const execute = require('../../compile/compile')
router.post('/submit', (req,res)=>{
console.log(req.body)
const code = req.body.code
const input = req.body.input
const lang = req.body.lang
return execute.pythonExecute(code, input)
.then(data=>{
console.log("SUCCESSFULL PROMISE " + data)
console.log("SENDING " + data)
res.write(data)
deleteFile(path.join(__dirname, '../../test.py'))
})
.catch(err => {
console.log("ERROR PROMISE " + err)
deleteFile(path.join(__dirname, '../../test.py'))
})
}
)
React
export default class Ide extends Component {
state={
code: code.cpp,
result: 'Submit Code to See Result',
lang: 'cpp'
}
onSubmitHandler = (e) => {
e.preventDefault()
alert("submit code")
axios.post(`${secret.url}code/submit`,this.state)
.then(res=>{
console.log(res.data)
const data = res.data
if(data.err){
// Error in user code
this.setState({
result: data.error
})
}else{
this.setState({
result: data.output
})
}
})
.catch(err=>{
console.log(err)
})
}
Logs
Server started at port 8000
{
code: '# Your code will come here\nprint("b")',
result: 'Submit Code to See Result',
lang: 'python'
}
SAVING FILES
The file was saved!
FILE PATH >> \ide-server\test.py
[6 7 8]
SUCCESSFULL PROMISE [6 7 8]
SENDING [6 7 8]
File deleted!
SORRY NOT DELETED
File deleted!
File deleted!
if you want to send a JSON structure to react App try to do on server:
res.send(JSON.stringify(data))
data must be like {values: [6, 7, 8]} or smth else
on client:
axios.post(`${secret.url}code/submit`,this.state)
.then(res=> res.json())
.then(result => console.log(result))
...
if you want to send a plain text:
res.send(data)
on client:
axios.post(`${secret.url}code/submit`,this.state)
.then(res=> res.text())
.then(result => console.log(result))
...
And don't forget use res.end() after res.write();
Related
I got this strange error I don't understand
Have been using for a long time and it worked, just yesterday it stopped working
module.exports.login = async(req, res, next) => {
const { username, password } = req.body;
const ips = req.user.ip;
const email = req.user.email;
fetch('https://api.ipify.org')
.then((res) => res.text())
.then(ip => {
fetch(`http://ip-api.com/json/${ip}`)
.then(response =>response.json())
.then(data => {
console.log(data)
const city = data.city
const country = data.country
const location = `${city}, ${country}`
if (ip === ips) {
req.flash('success', `welcome back ${username}`);
const redirectUrl = req.session.returnTo || '/index';
console.log(req.session.returnTo)
delete req.session.returnTo;
res.redirect(redirectUrl);
} else {
...
};
})
.catch(err => {
req.logout(function(err) {
if (err) { return next(err); }
req.flash('error', 'An error occured')
res.redirect('/login');
});
})
})
.catch(err => {
req.logout(function(err) {
if (err) { return next(err); }
req.flash('error', 'An error occured, This may be due to bad network')
res.redirect('/login');
});
})
};
The last catch(err with message 'An error occured, This may be due to bad network' is what am getting
But it working in m localhost, but when I upload it online it does not take any action rather it trows error
Please any help with this?
Thanks for any future help
Trying to get user ip with fecth('api.ipify.org') but is giving me error when I put it online but working in my localhost
I actually found the answer, node-fetch just currently updated their v3.0.3 package
Reasons is that it works only in ESM which you use 'import' instead of require(), And if that does not work you get error except you go back using v2 or less.
Which is not Ok for me so I diverted to use 'axios'
npm install axios
Example
async() {
await axios.get('api.ipify.org')
.then(response => {
console.log(response)
}.catch(err => console.log(err))
return
};
The response contains the ip address
But if you still need to use node-fetch use the link 'node-fetch'
Full code below
module.exports.login = async(req, res, next) => {
const { username, password } = req.body;
const ips = req.user.ip;
const email = req.user.email;
await axios.get('https://api.ipify.org')
.then(async(response) => {
const ip = response.data
await axios.get(`http://ip-api.com/json/${ip}`)
.then(response => {
const data = response.data
console.log(data)
const city = data.city
const country = data.country
const location = `${city}, ${country}`
if (ip === ips) {
req.flash('success', `welcome back ${username}`);
const redirectUrl = req.session.returnTo || '/index';
console.log(req.session.returnTo)
delete req.session.returnTo;
res.redirect(redirectUrl);
} else {
...
};
})
.catch(err => {
req.logout(function(err) {
if (err) { return next(err); }
req.flash('error', 'An error occured')
res.redirect('/login');
});
})
})
.catch(err => {
req.logout(function(err) {
if (err) { return next(err); }
req.flash('error', 'An error occured, This may be due to bad network')
res.redirect('/login');
});
})
};
The problem:
I have a function that maps over countries and regions and creates an array of urls, then makes a GET request to each one. I want to save the responses in a single json file, and I want this function to handle that as well.
Expected results:
I expected to be able to run the function as needed (like when source data is updated), and get a new or updated local json file with all the data objects in one array.
Actual results:
A file with only one record, an array with the last response object.
What I've tried:
I tried using fs.writeFile and fs.readFile. I did not get any errors, but the resulting file had only one record, even though console showed all the requests being made. It seemed that each response was being written over the previous.
Minimum reproducable (node.js) example:
const fs = require('fs')
// subset of countries and codes for demo purposes
const countryDirList = [
'antarctica',
'central-asia',
]
const fbCountryCodes = [
{ "region": "antarctica", "codes": ["ay", "bv"] },
{ "region": "central-asia", "codes": ["kg", "kz"] },
]
const callingUrlsInSequence = async () => {
fs.writeFile('./test.json', '[]', function (err) {
if (err) throw err
console.log('File - test.json - was created successfully.')
})
try {
const urlConstructor = countryDirList.map(async (country) => {
console.log('countries mapped', country)
return fbCountryCodes.filter(async (f) => {
if (country === f.region) {
const urls = f.codes.map(async (c) => {
const response = await axios({
method: 'get',
url: `https://raw.githubusercontent.com/factbook/factbook.json/master/${country}/${c}.json`,
responseType: 'json',
headers: {
'Content-Type': 'application/json',
},
})
fs.readFile('./test.json', function (err, data) {
let json = JSON.parse(data)
json.push(response.data)
setTimeout(() => {
fs.writeFile('./test.json', JSON.stringify(json), function (err) {
if (err) throw err
console.log('The "data to append" was appended to file!')
})
}, 1000)
})
return response.data
})
const dataArr = await Promise.all(urls)
dataArr.map((item) =>
console.log(
'dataArr',
item.Government['Country name']['conventional short form']
)
)
}
})
})
} catch (err) {
console.log('axios error: ', err)
}
}
callingUrlsInSequence()
I'm re-writing this question now because it kept getting downvoted, and I could see that it was not very concise.
I can also see now, that obviously, the fs.readFile inside the fs.writeFile is not going to work in the code I provided, but I'm leaving it there in case it might help someone else, combined with the solution I provided in response to my own question.
I ended up learning how to solve this problem with both node-fetch and axios. They are not exactly the same.
For both:
First, check for existence of destination file, and create one if it's not already there.
const createNew = () => {
try {
if (existsSync('./data.json')) {
console.log('file exists')
return
} else {
writeFile('./data.json', '[]', (error, data) => {
if (error) {
console.log('fs.writeFile - create new - error: ', error)
return
}
})
}
} catch (err) {
console.log('fs.existsSync error: ', err)
}
}
createNew()
Then make the array of urls:
const countryDirList = [...countries]
const fbCountryCodes = [...codes]
const urls = []
// maybe a reducer function would be better, but my map + filter game is much stronger X-D
const makeUrls = (countriesArr, codesArr) =>
countriesArr.map((country) => {
return codesArr.filter((f) => {
if (country === f.region) {
return f.codes.map((code) => {
return urls.push(
`https://raw.githubusercontent.com/factbook/factbook.json/master/${country}/${code}.json`
)
})
}
})
})
makeUrls(countryDirList, fbCountryCodes)
Next, make the requests.
Axios:
fs.readFile('./data.json', (error, data) => {
if (error) {
console.log(error)
return
}
Promise.all(
urls.map(async (url) => {
let response
try {
response = await axios.get(url)
} catch (err) {
console.log('axios error: ', err)
return err
}
return response
})
)
.then((res) => {
const responses = res.map((r) => r.data)
fs.writeFile('./data.json', JSON.stringify(responses, null, 2), (err) => {
if (err) {
console.log('Failed to write data')
return
}
console.log('Updated data file successfully')
})
})
.catch((err) => {
console.log('axios error: ', err)
})
})
Node-fetch:
//same basic structure, readFile with fetch and write file inside
fs.readFile('./data2.json', (error, data) => {
if (error) {
console.log(error)
return
}
async function fetchAll() {
const results = await Promise.all(
urls.map((url) => fetch(url).then((r) => r.json()))
)
fs.writeFile('./data2.json', JSON.stringify(results, null, 2), (err) => {
if (err) {
console.log('Failed to write data')
return
}
console.log('Updated data file successfully')
})
}
fetchAll()
})
Both methods produce exactly the same output: a json file containing a single array with however many response objects in it.
I try to update JSON file in backend with express and display new datas on frontend. But currently when I do request I get good response but data don't change.
Server Express (route) Script to edit JSON:
function editJSON(fr,en,es){
var obj = {
list_words: []
}
fs.readFile('./assets/words.json', 'utf-8', (err, jsonString) =>{
if(err){
console.log(err)
}else {
try{
obj = JSON.parse(jsonString)
obj.list_words.push({fr: fr, en: en, es: es})
json = JSON.stringify(obj)
fs.writeFileSync('./assets/words.json',json,'utf-8',function (err){
if (err) throw err;
console.log('complete');
})
} catch (err){
console.log(" Error parsing JSON", err)
}
}
})
}
And below script to send data and other to display.
methods: {
async addWord () {
var obj = {
fr: this.words_input.fr,
en: this.words_input.en,
es: this.words_input.es
}
const res = await axios.post('http://localhost:3000/addwords', obj)
const data = res.data
console.log(data)
}
},
mounted: async function () {
await axios.get('http://localhost:3000/words.json')
.then(response => {
this.words_init = response.data
})
.catch(error => {
console.log('There was an error: ' + error.response)
})
}
If I restart server after request table with new data is displayed. If you know how I can display informations without restart server this can help me so much.
I tried this
const res = await axios.post('http://localhost:3000/addwords', obj)
const data = res.data.list_words
this.words_init = data
With this route
app.post('/addwords',(req,res)=>{
console.log(req.body.fr)
const fr = req.body.fr
const en = req.body.en
const es = req.body.es
editJSON(fr,en,es)
console.log(fr)
res.send(words)
res.status(201).send('created User')
res.end()
})
But I got error
"Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client"
From back
and
"[Vue warn]: Error in v-on handler (Promise/async): "Error: Request aborted"
From frontend
const res = await axios.post('http://localhost:3000/addwords', obj)
this.words_init = res.data.list_words
```
with this route everything work But mu new list don't display
You need to return latest JSON on post response and then assign it to this.words_init variable.
This is very complicated term for me because i am confused how things are done. I have React & Express application where you can upload data and when you upload it will redirect you to other page where your data is displayed, but problem is that it only redirects you one time and when you go back to main page and try to upload file second time it is not uploaded and whole application crashes
here is recipe.js file (part of it) (react)
axios({
method: 'post',
url: '/api/recipes',
config: {headers: {'Content-Type': 'multipart/form-data' }},
data: data
})
.then(res => {
window.location.replace(res.data.location)
})
.catch(err => {
if(err.response){
if(err.response.data.redirect === true){
window.location.replace(err.response.data.location)
}
if(err.response.data.message){
alert(err.response.data.message)
}
}
});
recipe.js (part of it)(expressjs)
const recipe = await Dish.create({
author: user.username,
name: name,
//properties and values
})
return res.status(200).send({
location: '/recipe/' + recipe.name + '/' + recipe._id
})
view-recipe.js (express (part))
componentDidMount(){
const { match: { params } } = this.props;
console.log(`/api/recipe/${params.dishName}/${params.id}`)
axios.get(`/api/recipe/${params.dishName}/${params.id}`)
.then(res => res.data)
.then(data =>{
console.log(data)
}).catch(err=>{
if(err.response.data.message){
alert(err.response.data.message)
}
})
}
view-recipe.js (express)
router.get('/:dishName/:id', async (req, res) => {
try {
const name = req.params.dishName;
const id = req.params.id;
console.log('name ' + name + ' id ' + id)
const recipe = await Dish.findOne({
name: name,
_id: id
}).lean();
if (!recipe) {
return res.status(404).send({
message: 'recipe not found'
})
}
return res.status(200).send({
recipe
})
} catch (err) {
return res.status(500).send({
message: err.message
})
}
})
and finally
index.js (express, for where is guard determinig whether jwt validation token is expired or not and route configurations )
router.use('/api/recipes', guardr, require('./recipe'))
router.use('/api/recipe', require('./view-recipe'))
What is wrong with this code? By the way, before window.location.replace() in recipe.js file (client) i had window.location.href instead and it worked 2 times. it is really confusing for me because i am doing this difficult project for the first time. Thanks!
I am currently experimenting Google Firebase functions to access Google APIs. It's running fine, but I am a little bit lost in trying to manage the errors that could be detected ...
In the .HTTPS getGoogleUsers functions , I would like to return an HTTP status code ( 200 or error code ) , and the data ( or error message )
As far as I can see , I can get errors:
from the connect() function ( 500: Internal server error or 401 Unauthorized )
from the listUsers() function ( 500: Internal server error or 400 Bad Request )
Am I totally or partially wrong ? what should be my strategy in this case ?
thanks for feedback ..
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const {google} = require('googleapis');
const KEY = require('./service-key.json');
// Create JSON Web Token Client
function connect () {
return new Promise((resolve, reject) => {
const jwtClient = new google.auth.JWT(
KEY.client_email,
null,
KEY.private_key,
['https://www.googleapis.com/auth/admin.directory.user'],
'adminuser#mydomain.com'
);
jwtClient.authorize((err) => {
if(err) {
reject(err);
} else {
resolve(jwtClient);
}
});
});
}
function listUsers (client) {
return new Promise((resolve, reject) => {
google.admin('directory_v1').users.list({
auth: client,
domain: 'mydomain.com',
}, (err, response) => {
if (err) {
reject(err);
}
resolve(response.data.users);
});
});
}
function getAllUsers () {
connect()
.then(client => {
return listUsers(client);
})
.catch(error => {
return error;
})
}
exports.getGoogleUsers = functions.https.onRequest((req, res) => {
const users = getAllUsers();
if (error) {
status = error.status;
data = error.message;
} else {
status = 200;
data = users;
}
res.send({ status: status, datas: data })
});
I think you are looking for
function getAllUsers () {
return connect().then(listUsers);
//^^^^^^
}
exports.getGoogleUsers = functions.https.onRequest((req, res) => {
getAllUsers().then(users => {
return {status: 200, datas: users};
}, error => {
return {status: error.status, datas: error.message};
}).then(response => {
res.send(response);
});
});
This uses the .then(…, …) method with two callbacks to distinguish between success and error case, and to wait for the result of the promise.