Cannot pass mongo/express data to react - mongodb

I was trying to pass my data from mongodb/express to react using componentDidMount() life cycle function but for some reason it doesn't work but instead it gives me this "Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0" error.
Here's how I set up my express:
app.get('/movies', function(req, res){
movie.find({}, function(err, allMovies){
if(err){
console.log(err);
} else {
res.send(allMovies);
}
})
});
app.listen(3000, function(){
console.log('App server is listening to 3000');
});
And inside my react file I call the componentDidMount function which is running via webpack at port 8080.
componentDidMount() {
console.log('test')
fetch('/movies')
.then(response => response.json())
.then(movies => this.setState({
movies: movies
}));
}
when i console.log response it returns this https://prnt.sc/iye6kk.
Any idea what am I doing wrong why my data is not passing properly?

In componentDidMount,script is parsing the response to JSON.
.then(response => response.json())
But server is not sending the response in the JSON format.
Send it in json format.
res.json({allMovies}); //ecma6 shorthand property names
Or
res.json({allMovies : allMovies});

Related

Content-type using axios

I'm working with React and axios. I'm trying to fetch the response using axios however, unable to understand why I'm getting wrong content-type even though I'm setting it in my backend code.
Code (backend):
router.get(url, async (req, res) => {
// return new Promise(async (resolve, reject) => {
try {
if (file exists) {
var fileContents = Buffer.from(document[0].data, "base64"); //document contains the data from the postgres database
var readStream = new stream.PassThrough();
readStream.end(fileContents);
res.set(
"Content-disposition",
"attachment; filename=" + document[0].fileName
);
res.setHeader("content-type", document[0].fileType);
readStream.pipe(res);
console.log("+++++++++++++++++++");
console.log(res);
console.log("+++++++++++++++++++");
return;
} else {
res.json({
status: 0,
message: "File not found",
});
return;
}
// resolve({ document });
} catch (err) {
console.log(err);
}
});
The above backend code works absolutely fine. I even printed the response to check whether the content-type is setting or not. I'm even providing the output snippet for that as well
However, in the frontend if I try to fetch the response this is what I'm receiving
I'm not sure what's wrong. Why I'm receiving wrong content-type. Even the content length is same for any sort of file which I try to download.
The axios call :
let response = await Axios.get(fileURL, {
responseType: "blob"/"arraybuffer",
Authorization: "Bearer " + token,
});
Response.data output :
Any help will be appreciated!

Put / Update to my MongoDb with Express, immutable error of cross _id field

So I am sending data of a mission, the startdate and the finish date. However I am not able to put any changes into the database as it believes I get an immutable error with mongoDB... I would like to stick with using the .then method for my js code.
My other methods are working properly, I just can't get this update method right...
app.put('/missions/:id', function (req, res) {
if (req.user) {
model.Mission.findById(req.params.id).then(function(Mission){
console.log("req.body.secret_mission: ",req.body.secret_mission)
Mission['secret_mission'] = req.body.secret_mission;
Mission['start'] = req.body.start;
Mission['complete'] = req.body.complete;
Mission.update().then(function(){
res.set('Access-Control-Allow-Origin', '*');
res.sendStatus(201);
});
});
}else{
res.sendStatus(401);
}
});
Error I receive in the command line
I was able to use all the help provided to come up with a working solution and keep consistent to how I am calling the rest of my code. A big thanks to those that responded!!
Rather than setting the elements in my collection beforehand I am supposed to do it in the update request. Instead of calling 2 methods I used the findOneAndUpdate.
app.put('/missions/:id', function (req, res) {
if (req.user) {
model.Mission.findOneAndUpdate(
{'_id' : req.params.id},
{ $set: {"secret_mission" : req.body.secret_mission,
"start" : req.body.start},
"complete" : req.body.complete
}).then(function(err, missions){
if (err) return res.json({Error: err});
res.json(missions);
});
} else {
res.sendSatus(401);
}
});
I've cleaned up Your code:
removed req.user check to middleware,
included cors module to not to play with CORS headers in every handler
used async/await stuff to give it more synchronous look
mission/:id route handler just have concrete logic without garbage
Check this solution:
const cors = require('cors'); // install: npm i --save cors
const _ = require('lodash'); // install: npm i --save lodash
app.use(cors());
const isUserAuthorized = (req, res, next) => {
if (!req.user) return res.status(401).send();
next();
}
app.put(
'/missions/:id',
isUserAuthorized,
async (req, res) => {
try {
const mission = await model.Mission.findById(req.params.id);
if (!mission) return res.status(404).send();
mission.set(_.pick(req.body, ['secret_mission', 'start', 'complete']);
await mission.save();
res.status(201).send();
}
catch (error) {
console.log(error);
res.status(500).send();
}
});
or if You don't care if record in db exist or not, so You can just push update directly:
app.put(
'/missions/:id',
isUserAuthorized,
async (req, res) => {
try {
const data = _.pick(req.body, ['secret_mission', 'start', 'complete']);
await model.Mission.update({_id: req.params.id}, {$set: data});
res.status(201).send();
}
catch (error) {
console.log(error);
res.status(500).send();
}
});

How upload and save image using Sails and MongoDB

I'm working on a project and I'm using a backend sails js, a MongoDB as database and front-end React js.
I have a problem on the upload image.
Here is the code Sails backend and when I test it in PostMan, I got this result (result test PostMan), and the image is not stored in the specified folder but a value containing id and name of file is inserted in MongoDB,
uploadFile: function (req, res) {
var image= req.file('avatar');
image.upload({
adapter: require('skipper-gridfs'),
uri: 'mongodb://localhost:27017/name_db.name_collection',
dirname: '../../assets/images/'
}, function (err, filesUploaded) {
if (err){
return res.header("Access-Control-Allow-Origin", "*");
/*res.negotiate(err);*/res.json(err);
}
else{
return
res.header("Access-Control-Allow-Origin", "*"); res.ok({
files: filesUploaded,
textParams: req.params.all()
});
}
});
},
result test postMan
And here is the Reactjs front-end code
_handleSubmit(e) {
e.preventDefault();
// TODO: do something with -> this.state.file
fetch('http://localhost:1337/uploadPhoto/logos', {
method: 'POST',
body: JSON.stringify({avatar:this.state.file})
})
.then((response) => response.json())
.catch((err) => { console.log(err); });
}
Sails version 0.12,
React version 15.5,
and MongoDB version 3.4.9.
Thanks for your help
There is no dirname parameter for skipper-gridfs adapter because the file won't be stored onto the local file system.
Skipper will store the file into the MongoDB database.
U need to send it as form Data
let formData = new FormData()
console.log(values);
await formData.append('profile_picture',values.profile_picture.rawFile,values.profile_picture)
await fetch('http://localhost:1337/api/moderators',{
body:formData,
method:'POST',
credentials:'include' //If Using Session for react-app instead of JWT token
})

ng-file-upload accessing data sent in upload

I am sending my data like. I am new to angular. I am not able to access the userDetails in my post request.
Upload.upload({
url: '/api/upload/',
data: {'File': File, 'userDetails': userDetails}
});
Server Code:
userRouter.route('/upload')
.post(function(req, res) {
console.log(req.data);
upload(req, res, function(err) {
if(err) {
res.json({ error_code:1, err_desc:err });
return;
}
res.json({ error_code:0, err_desc:null });
})
});
the field req.data is undefined
I'm new on angularjs too and I had the same problem. I made use of https://github.com/expressjs/node-multiparty to get the data sent from ng-file-upload.
I hope it helps you too.

React + Sails + Socket.io

This is quite a broad question, however I currently have a Sails API server and a React Front-end (Standalone).
Note: The React Front-End is NOT part of Sails
I'm trying to get to grips with sockets, so I figured I would start simple. I want to achieve the following:
User visits my website (React)
React opens a socket and connects to Sails
Sails streams the data from within a function/model
React updates when new data is added to the model
I semi understand how this works using Express and React, however I cannot get my head around how Sails implements their version of WebSockets on top of Sockets.io.
What I've done is install the sockets.io-client within React, and then trying to use sails.sockets inside Sails.
This is what I currently have:
React Component NB: I don't think this is correct at all
componentDidMount =()=> {
this.getSessionData();
UserStore.listen(this.getSessionData);
Socket.emit('/listSessions', function(data){
console.log(data);
})
}
Sails Function (listSessions)
listSessions: function(req, res) {
Session.find({ where: {visible: true}, sort: 'createdAt DESC'},
function(err, sessions){
if(req.isSocket){
Session.watch(req.socket);
console.log('User subscribed to ' + req.socket.id);
}
if(err) return res.json(500, {
error: err,
message: 'Something went wrong when finding trades'
});
return res.json(200, {
sessions: sessions,
});
})
},
Sails Function (createSession) Trying to use publishCreate to use in conjunction with Session.watch in the above function
createSession: function(req, res){
var token = jwt.sign({
expiresIn: 30,
}, 'overwatch');
Session.create({
username: req.body.username,
platform: req.body.platform,
lookingFor: req.body.lookingFor,
microphone: req.body.microphone,
gameMode: req.body.gameMode,
comments: req.body.comments,
avatar: null,
level: null,
hash: token,
competitiveRank: null,
region: req.body.region,
visible: true,
}).exec(function(err, created){
Session.publishCreate(created);
if(err) {
console.log(err);
return res.send({
error: err,
message: 'Something went wrong when adding a session',
code: 91
})
}
if(req.isSocket){
Session.watch(req.socket);
console.log('User subscribed to ' + req.socket.id);
}
return res.send({
session: created,
code: 00,
})
});
},
Both of the Sails functions are called using POST/GET.
I'm completely stumped as where to go with this, and it seems to documentation or explanation on how to get this working is limited. All the Sails documentation on Sockets seems to relate to using Sails as a front-end and server
OK so I managed to solve this:
Simply put:
Within React, I had to include https://github.com/balderdashy/sails.io.js/tree/master
Then within my React component I did:
componentDidMount =()=> {
io.socket.get('/listSessions',(resData, jwres) => {
console.log('test');
this.setState({
sessions: resData.sessions,
loaded: true,
})
})
io.socket.on('session', (event) => {
if(event.verb == 'created') {
let sessions = this.state.sessions;
sessions.push(event.data);
this.setState({
sessions: sessions
})
} else {
console.log('nah');
}
});
}
This makes a virtual get request to Sails using Socket.io, and sets the response in state. It also watches for updates to the 'session' connection and updates the state with these updates meaning I can update a list in real time
Within my Sails controller I have:
listSessions: function(req, res) {
if(req.isSocket){
Session.find({ where: {visible: true}, sort: 'createdAt DESC'},
function(err, sessions){
Session.watch(req.socket);
if(err) return res.json(500, {
error: err,
message: 'Something went wrong when finding trades'
});
return res.json(200, {
sessions: sessions,
});
})
}
},
The Session.watch line listens for updates via publishCreate on the model which is found in my model as follows:
afterCreate: function(message, next) {
Session.publishCreate(message);
next();
},
Adding to answer by #K20GH , add the following to my "index.js" in React to help get sails.io.js from the CDN :
const fetchJsFromCDN = (src, externals = []) => {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.setAttribute('src', src);
script.addEventListener('load', () => {
resolve(
externals.map(key => {
const ext = window[key];
typeof ext === 'undefined' &&
console.warn(`No external named '${key}' in window`);
return ext;
})
);
});
script.addEventListener('error', reject);
document.body.appendChild(script);
});
};
fetchJsFromCDN(
'https://cdnjs.cloudflare.com/ajax/libs/sails.io.js/1.0.1/sails.io.min.js',
['io']
).then(([io]) => {
if (process.env.NODE_ENV === 'development') {
io.sails.url = 'http://localhost:1337';
}
});
Once you have this, you'll be able to use the HTTP type GET, PUT, POST and DELETE methods. So here you can do:
componentDidMount =()=> {
io.socket.get('/listSessions',(resData, jwres) => {
console.log('test');
this.setState({
sessions: resData.sessions,
loaded: true,
})
})
io.socket.on('session', (event) => {
if(event.verb == 'created') {
let sessions = this.state.sessions;
sessions.push(event.data);
this.setState({
sessions: sessions
})
} else {
console.log('Not created session');
}
});
}
And you can do the required setup in sails for the models of sessions as suggested above