error Path must be a string without null bytes [duplicate] - node.js

I am using Angular 5 on front-end, Node on back-end and Mongo as the database. Now I am trying to save an image to the database but constantly getting this error. I can't figure out if I'm making mistake on front or back because this is my first time working with files. I did my research but it points mostly to angular 1.x.
HTML Component
<form [formGroup]="form" (ngSubmit)="onSubmitPhoto()">
<div class="form-group">
<input type="file" class="form-control" formControlName="photo">
</div>
<button class="btn btn-default" type="submit">Sačuvaj</button>
</form>
TS Component
onSubmitPhoto() {
this.profile.photo = this.form.value.photo;
this.usersService.updatePhoto(this.profile, this.id)
.subscribe(
data => {
this.router.navigateByUrl('/');
},
error => console.error(error)
);
}
Service
updatePhoto(profile: Profile, id: string) {
const body = new FormData();
body.append('photo', profile.photo);
const headers = new Headers({ 'Content-Type': 'application/json' });
return this.http.post('http://localhost:3000/profile/photo/' + id, body, { headers: headers })
.map((response: Response) => response.json())
.catch((error: Response) => {
return Observable.throw(error.json());
});
}
Node.JS
router.post('/photo/:id', (req, res) => {
console.log(req.files);
User.find({ _id: req.params.id })
.exec((err, user) => {
if (err) {
return res.status(500).json({
title: 'An error occured',
error: err
});
}
user.img.data = fs.readFileSync(req.files);
user.img.contentType = 'image/png';
user.save((err, obj) => {
if (err) {
throw err
}
console.log('success')
})
});
});
Model
const schema = new Schema({
img: { data: Buffer, contentType: String}
});
module.exports = mongoose.model('User', schema);
Any help is appreciated.
Also, loging req.files returns undefined.

To upload a file you need to wrapp it in a FormData instance as follows:
interface Profile {
photo: File;
}
updatePhoto(profile: Profile, id: string) {
const body = new FormData();
body.append('photo',profile.photo);
return this.http.post(`http://localhost:3000/profile/photo/${id}`, body,)
.map((response: Response) => response.json())
.catch((error: Response) => {
return Observable.throw(error.json());
});
}
Furthermore, your backend is most likely failing in the following section:
user.img.data = fs.readFileSync(req.body.photo);
Considering that you are now uploading a form with multipart/form-data encoding, you will need to use some middleware to parse the request in your backend as stated in the expressjs doc
You could use multer or express-fileupload
If you go with the second, you will need the following:
const fileUpload = require('express-fileupload');
router.use(fileUpload());// use express-fileupload as default parser for multipart/form-data encoding
router.post('/photo/:id', (req, res) => {
User.find({ _id: req.params.id })
.exec((err, user) => {
if (err) {
return res.status(500).json({
title: 'An error occured',
error: err
});
}
user.img.data = req.files.photo.data;
user.img.contentType = 'image/png';
user.save((err, obj) => {
if (err) {
throw err
}
console.log('success')
})
});
});

Related

How to Post Data Form to mongoDB with ReactJS using hooks

Hi everyone, I am facing an issue while trying to post data to my mongoDB from the frontend using React Hooks. The problem is that when I send the data instead of getting the all body I am only getting the id as response in my database. I don't know what I am missing in my code, I really need your help and I am open for all advices so I can better understand how to do. Here bellow are my codes:
CustomerPost:
import React, { useState } from "react";
import axios from "axios";
export default function CreateCustomer() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [phone, setPhone] = useState("");
const [passport, setPassport] = useState("");
const [booked, setBooked] = useState(false);
const onChangeName = (e) => {
setName({ name: e.target.value });
};
const onChangeEmail = (e) => {
setEmail({ email: e.target.value });
};
const onChangePhone = (e) => {
setPhone({ phone: e.target.value });
};
const onChangePassport = (e) => {
setPassport({ passport: e.target.value });
};
const onSubmit = (e) => {
e.preventDefault();
const bookingData = {
name: name,
email: email,
phone: phone,
passport: passport,
};
console.log(bookingData);
axios
.post("http://localhost:5000/customers", bookingData)
.then((res) => {
console.log(res.data);
setName(name);
setEmail(email);
setPhone(phone);
setPassport(passport);
})
.catch((error) => {
console.log(error);
});
setBooked(true);
};
return (
<div>
{booked ? (
<p className="bookedMsg">Your room was booked successfully!!!</p>
) : (
<form onSubmit={onSubmit} className="form contact-form">
<div className="input-group-wrap">
<div className="input-group">
<input
className="input"
type="text"
onChange={onChangeName}
placeholder="Name..."
required
/>
<span className="bar"></span>
</div>
<div className="input-group">
<input
className="input"
type="email"
onChange={onChangeEmail}
placeholder="Email..."
required
/>
<span className="bar"></span>
</div>
<div className="input-group">
<input
onChange={onChangePhone}
type="number"
className="input"
placeholder="Phone..."
required
/>
<span className="bar"></span>
</div>
<div className="input-group">
<input
onChange={onChangePassport}
type="number"
className="input"
placeholder="Passport..."
required
/>
<span className="bar"></span>
</div>
</div>
<button type="submit" className="btn form-btn btn-purple">
BOOK NOW
<span className="dots">
<i className="fas fa-ellipsis-h"></i>
</span>
</button>
</form>
)}
</div>
);
}
Customer.Route.js:
const Express = require("express");
var cors = require("cors");
const router = Express.Router();
const Controller = require("./Controller");
const data = require("./controller");
router.post("/", cors(), function (req, res) {
Controller.insertCustomer(req.body)
.then(function (data) {
res.status(data.status).send({ message: data });
})
.catch(function (err) {
res.status(data.status).send({ message: err.message });
});
});
router.get("/", cors(), function (req, res) {
Controller.searchAll()
.then((data) => {
res.status(data.status).send({ data: data.message });
})
.catch((err) => {
res.status(err.status).send({ message: err.message });
});
});
router.get("/:id", cors(), function (req, res) {
Controller.search(req.params.id)
.then((data) => {
res.status(data.status).send({ message: data.message });
})
.catch((err) => {
res.status(err.status).send({ message: err.message });
});
});
router.put("/:id", cors(), function (req, res) {
Controller.updateCustomer(req.params.id, req.body)
.then((data) => {
res.status(data.status).send({ message: data.message });
})
.catch((err) => {
res.status(err.status).send({ message: err.message });
});
});
router.delete("/:id", cors(), (req, res) => {
Controller.delete(req.params.id)
.then((data) => {
res.status(data.status).send({ message: data.message });
})
.catch((err) => {
res.status(err.status).send({ message: err.message });
});
});
module.exports = router;
dbConfig:
require("dotenv").config();
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const CustomerSchema = new Schema({
name: {
type: String,
require: true,
},
email: {
type: String,
require: false,
},
phone: {
type: Number,
require: true,
},
passport: {
type: Number,
require: true,
},
});
mongoose.connect(
process.env.DATABASE_URL,
{ useNewUrlParser: true, useUnifiedTopology: true },
(err) => {
if (err) {
console.log(err);
}
console.log("Connected to the mongodb");
}
);
module.exports = mongoose.model("Customer", CustomerSchema);
Controller.js:
const mongoose = require("../dbSchema/dbConfig");
const CustomerSchema = mongoose.model("Customer");
const Controller = function () {
this.insertCustomer = function (data) {
return new Promise(function (resolve, reject) {
var Customer = new CustomerSchema({
name: data.name,
email: data.email,
phone: data.phone,
passport: data.passport,
});
Customer.save()
.then(function () {
resolve({ status: 200, message: "Customer inserted Successfully" });
})
.catch(function (err) {
reject({ status: 500, message: "Error " + err });
});
});
};
this.updateCustomer = function (id, data) {
return new Promise((resolve, reject) => {
CustomerSchema.update({ _id: id }, data)
.then(() => {
resolve({ status: 200, message: "Customer updated Successfully" });
})
.catch(function (err) {
reject({ status: 500, message: err });
});
});
};
this.searchAll = function () {
return new Promise(function (resolve, reject) {
CustomerSchema.find()
.exec()
.then(function (data) {
resolve({ status: 200, message: data });
})
.catch(function (err) {
reject({ status: 500, message: err });
});
});
};
this.search = function (id) {
return new Promise(function (resolve, reject) {
CustomerSchema.find({ _id: id })
.exec()
.then(function (Customer) {
resolve({ status: 200, message: Customer });
})
.catch((err) => {
reject({ status: 500, message: err });
});
});
};
this.delete = function (id) {
return new Promise(function (resolve, reject) {
CustomerSchema.remove({ _id: id })
.then(() => {
resolve({ status: 200, message: "Customer Removed" });
})
.catch((err) => {
reject({ status: 500, message: err });
});
});
};
};
module.exports = new Controller();
Route.js:
const Express = require("express");
const Routes = Express.Router();
const CustomerRoute = require("../CustomerController/Customer.Route");
Routes.use("/customers", CustomerRoute);
module.exports = Routes;
It looks like you are sending an empty object from react, can you try adding async and await to your onSubmit function. I'm posting it as an answer to have more space for the code.
const onSubmit = async (e) => {
e.preventDefault();
const bookingData = {
name: name,
email: email,
phone: phone,
passport: passport,
};
console.log(bookingData);
await axios.post("/customers",
bookingData).then((res) => {
console.log(res.data);
setName(name);
setEmail(email);
setPhone(phone);
setPassport(passport);
}).catch((error) => {
console.log(error); });
setBooked(true);
};
Maybe you can modify your handleChange functions, something like this:
const onChangeName = (e) => {
setName(e.target.value)
}
I hope this works for you

Weather API data request

I have this ejs template that inputs the name of the city, the city gets stored into the database and then display the related weather result. I created a controller to POST the city from that input box. The city name gets stored easily and gets a success message but it does not pass that city to the GET request into the weather API URL to display the related weather details.
Here is my controller for city:
const mongoose = require('mongoose');
const axios = require('axios');
const City = require('../models/city');
exports.addCity = (req, res, next) => {
const city = new City({
_id: new mongoose.Types.ObjectId(),
cityName: req.body.cityName
});
city
.save()
.then(result => {
console.log(result);
res.status(201).json({
message: "Created city successfully"
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
};
exports.getCity = (req, res, next) => {
City.find({}).then(docs => {
cities: docs.map(doc => {
return {
city: doc.cityName
}
})
let apiKey = '**************************';
var city = cities;
var url= `http://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}`;
axios(url)
.then( (response) => {
var cityData = response.data;
var weather = {
city: city,
temperature: Math.round(cityData.main.temp),
description: cityData.weather[0].description,
icon: cityData.weather[0].icon
}
// var weather_data = { weather : weather };
console.log('heyyyy', weather);
res.render('index', {
weather: weather
});
})
.catch( (error) => {
console.log(error);
})
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
})
}
And here is the snippet of the ejs template:
<article class="media">
<div class="media-left">
<figure class="image is-50x50">
<img src="http://openweathermap.org/img/w/<%= weather.icon %>.png" alt="Image">
</figure>
</div>
<div class="media-content">
<div class="content">
<p>
<span class="title"><%= weather.city %></span>
<br>
<span class="subtitle"><%= weather.temperature %></span>
<br> <%= weather.description %>
</p>
</div>
</div>
</article>
Whenever I run my localhost, it only creates the city into the database and display console with the lots of error data back with last two lines saying:
data: { cod: '404', message: 'city not found' } } }
{ _id: 5c6d4e18d1ad342458c3df64, cityName: 'mumbai', __v: 0 }
Kindly help to figure out the problem.
Looks like the getCity controller you provided has some syntax errors but I tried my best to work with it. Main changes are 1. the logic to find matching document and 2. the way you construct the GET query using Axios
exports.getCity = (req, res, next) => {
const cityName = req.query.cityName;
City.find({})
.then(docs => {
// 1. Find matching city document
const city = docs.find(doc => {
return doc.cityName === cityName;
});
if (city) {
const apiKey = "**********";
const url = "https://api.openweathermap.org/data/2.5/weather";
// 2. Axios GET query with params as object instead of interpolating inside url
axios
.get(url, {
params: {
q: city.cityName,
appId: apiKey
}
})
.then(response => {
const cityData = response.data;
const weather = {
city: city,
temperature: Math.round(cityData.main.temp),
description: cityData.weather[0].description,
icon: cityData.weather[0].icon
};
// Do something with weather
console.log(weather);
})
.catch(err => {
// Weather query failed
console.log(err);
});
} else {
// No city found matching cityName
}
})
.catch(err => {
// Database fetch failed
console.log(err);
});
};

Multer + React + Nodejs Axios request

Axios Post request
// Create profile
export const createProfile = (profileData, avatar, history) => dispatch => {
dispatch(clearErrors());
const image = new FormData();
image.append("avatar", avatar, avatar.name);
axios
.post("/api/profile", image, profileData)
.then(res => history.push("/dashboard"))
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
};
Edit ---> Axios post request second attempt
// Create profile
export const createProfile = (profileData, avatar, history) => dispatch => {
dispatch(clearErrors());
const image = new FormData();
image.append("avatar", avatar, avatar.name);
image.append("user", profileData, profileData.username);
axios
.post("/api/profile", image)
.then(res => history.push("/dashboard"))
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
};
profileData is what i want in the req.body and avatar is what i receive in req.file in my back-end with multer, but what i receive is the req.file with the image but nothing in my req.body(Just an empty object)
This is my router in node
router.post(
"/",
upload.single("avatar"),
passport.authenticate("jwt", { session: false }),
(req, res) => {
console.log(req.body);
}
);
Try to implement in following way using FormData
handleSubmit(e)
{
e.preventDefault();
const err = this.validate();
if (!err) {
var formData = {
category: this.state.category,
course: this.state.course,
};
const { category, course } = this.state;
let fd = new FormData();
fd.append('Test', this.state.testFile, this.state.testFile.name);
fd.append('category', category);
fd.append('course', course);
console.log(fd);
axios({
method: 'post',
url: 'http://localhost:7777/api/uploadTest',
data: fd,
})
.then((response) => {
if (response.data == 'Success') {
alert('Test has been Added..!!');
}
else {
alert('Something went wrong');
this.setState({ category: '' });
}
// this.setState({success:'Alert: '+response.data});
})
.catch((e) => {
console.error(e);
this.setState({ success: 'Alert: Something went wrong' });
});
}
}
I consider your route as /api/profile in route file.
You don't show your header profileData.
It should be like this
const profileData = {
headers: { 'content-type': 'multipart/form-data' }
}
Then you can request to the server as you already did.

Node Server unable to respond to PUT request

I am making a quite easy CRUD application in MEAN stack.
I have succesfully done all but Update function. Problem is not with request itself but inability of Node server to respond. Request is making changes to database as requested and I even eget a { n: 1, nModified: 0, ok: 1 } response from mongojs.
However, I am unable to send it back to Angular frontend.
I try res.json() but it won't all allow me as it is a not a function? But I am succesfuly doing res.json in create, delete and read. In network tab in developers console, request seems to be pending and after like 30 seconds it throws an error.
No luck with postman either.
How can I send a response to frontend?
// Error handling
const sendError = (err, res) => {
response.status = 501;
response.message = typeof err == 'object' ? err.message : err;
res.status(501).json(response);
};
// Response handling
let response = {
status: 200,
data: [],
message: null
};
// Update log <-- doesn't send response but works
router.put('/update/:id', (req, body, res) => {
console.log("Received UPDATE request");
console.log(req.params.id);
const bodyToUpdate = {
'_id': mongojs.ObjectId(req.params.id),
'week': req.body.week,
'type': req.body.type,
'text': req.body.text,
'days': req.body.days
};
console.log(bodyToUpdate);
db.logs.update({
_id: mongojs.ObjectId(req.params.id)}, bodyToUpdate, (err, res) => {
if (err) return next(err);
response.data = res;
res.json(response);
console.log(response);
});
});
// Delete log <--does work without problems
router.post('/delete/:id', (req, res) => {
console.log("Received DELETE request");
console.log(req.params.id);
db.logs.remove({
_id: mongojs.ObjectId(req.params.id)}, (err, users) => {
if (err) return next(err);
console.log(response);
response.data = users;
res.json(response);
});
});
Service API frontend
deleteLog(id) {
return new Promise((resolve, reject) => {
this._http.post('/api/delete/' + id , id)
.map(res => res.json())
.subscribe(res => {
resolve(res);
console.log(res);
}, (err) => {
reject(err);
});
});
}
updateLog(logToUpdate) {
return new Promise((resolve, reject) => {
this._http.put('/api/update/' + logToUpdate._id, logToUpdate)
.map(res => res.json())
.subscribe(res => {
resolve(res);
// console.log(res);
}, (err) => {
reject(err);
});
});
}
As #JithinSebastian correctly pointed out - I should not have 3 arguments in put request. I also had to change name of callbacks in mongo update function because I already used res in router function callback.
// Update log
router.put('/update/:id', (req, res) => {
console.log("Received UPDATE request");
console.log(req.body);
const bodyToUpdate = {
'_id': mongojs.ObjectId(req.params.id),
'week': req.body.week,
'type': req.body.type,
'text': req.body.text,
'days': req.body.days
};
db.logs.update({
_id: mongojs.ObjectId(req.params.id)
}, bodyToUpdate, (err, logs) => {
if (err) return next(err);
response.data = logs;
res.json(response);
console.log(response);
});
});

TypeError: path must be a string or Buffer MEAN stack

I am using Angular 5 on front-end, Node on back-end and Mongo as the database. Now I am trying to save an image to the database but constantly getting this error. I can't figure out if I'm making mistake on front or back because this is my first time working with files. I did my research but it points mostly to angular 1.x.
HTML Component
<form [formGroup]="form" (ngSubmit)="onSubmitPhoto()">
<div class="form-group">
<input type="file" class="form-control" formControlName="photo">
</div>
<button class="btn btn-default" type="submit">Sačuvaj</button>
</form>
TS Component
onSubmitPhoto() {
this.profile.photo = this.form.value.photo;
this.usersService.updatePhoto(this.profile, this.id)
.subscribe(
data => {
this.router.navigateByUrl('/');
},
error => console.error(error)
);
}
Service
updatePhoto(profile: Profile, id: string) {
const body = new FormData();
body.append('photo', profile.photo);
const headers = new Headers({ 'Content-Type': 'application/json' });
return this.http.post('http://localhost:3000/profile/photo/' + id, body, { headers: headers })
.map((response: Response) => response.json())
.catch((error: Response) => {
return Observable.throw(error.json());
});
}
Node.JS
router.post('/photo/:id', (req, res) => {
console.log(req.files);
User.find({ _id: req.params.id })
.exec((err, user) => {
if (err) {
return res.status(500).json({
title: 'An error occured',
error: err
});
}
user.img.data = fs.readFileSync(req.files);
user.img.contentType = 'image/png';
user.save((err, obj) => {
if (err) {
throw err
}
console.log('success')
})
});
});
Model
const schema = new Schema({
img: { data: Buffer, contentType: String}
});
module.exports = mongoose.model('User', schema);
Any help is appreciated.
Also, loging req.files returns undefined.
To upload a file you need to wrapp it in a FormData instance as follows:
interface Profile {
photo: File;
}
updatePhoto(profile: Profile, id: string) {
const body = new FormData();
body.append('photo',profile.photo);
return this.http.post(`http://localhost:3000/profile/photo/${id}`, body,)
.map((response: Response) => response.json())
.catch((error: Response) => {
return Observable.throw(error.json());
});
}
Furthermore, your backend is most likely failing in the following section:
user.img.data = fs.readFileSync(req.body.photo);
Considering that you are now uploading a form with multipart/form-data encoding, you will need to use some middleware to parse the request in your backend as stated in the expressjs doc
You could use multer or express-fileupload
If you go with the second, you will need the following:
const fileUpload = require('express-fileupload');
router.use(fileUpload());// use express-fileupload as default parser for multipart/form-data encoding
router.post('/photo/:id', (req, res) => {
User.find({ _id: req.params.id })
.exec((err, user) => {
if (err) {
return res.status(500).json({
title: 'An error occured',
error: err
});
}
user.img.data = req.files.photo.data;
user.img.contentType = 'image/png';
user.save((err, obj) => {
if (err) {
throw err
}
console.log('success')
})
});
});

Resources