I am trying to upload images to cloudinary using react front-end and express server.
The problem is i cant properly post request image to my express server.
This is how i prepare image to send it later:
var data = new FormData();
console.log(event.target.files[0]) // this prints FileObject succesfully
data.append('image', event.target.files[0]);
console.log(data) // this prints {} but i guess its natural since its FormData ??
this.imageToUpload = data;
This is how i post request:
axios.post('/api/courses/uploadImage',this.imageToUpload, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then( (response) => {
alert(JSON.stringify(response));
})
.catch(function (error) {
console.log(error);
});
Now in server side,req.body is empty.
router.post("/courses/uploadImage",(req,res,next)=>{
console.log(req.body) // empty
var image = req.body;
cloudinary.uploader.upload(image, function(error, result) { console.log(result) });
})
Also what should i really put to first parameter of(image in this case) uploader.upload ?
Not a direct answer but if you want Cloudinary also offers a way to directly upload images from your front-end so it saves you some work. You can read here further.
I've worked with their widget and it is very simple to integrate into almost any app.
You can do like this. I have successfully tried in my project.
function upload(){
var data = new FormData();
data.append('image', event.target.files[0]);
data.append('username', 'Saurabh'); //if you have other fields
axios.post('/api/courses/uploadImage', data,
headers: {
//your headers
})
.then( (response) => {
alert(JSON.stringify(response));
})
.catch(function (error) {
console.log(error);
});
}
In your express route you can simply get values like this
router.post('/api/courses/uploadImage', upload.single('image'), async(req,res, next) => {
const result = await cloudinary.v2.uploader.upload(req.file.path);
console.log(req.body.username); //Saurabh
//your logic
});
I solved my problem by directly uploading images to cloudinary from client with their html5 codepen example.
Related
I have a component which processes and uploads images. Currently I process the image on my backend and then send it to my frontend and then upload it from there. I would like to do everything on my backend. The only issue is that the upload endpoint requires FormData() object. I found an npm package form-data which I'm using on my backend now, but I'm still getting error.
This is how it currently works:
// frontend logic:
const data = await uploadImage(img);
const file = new File([Buffer.from(data)], `img-${i}.webp`, {
type: "image/webp",
});
const formData = new FormData();
formData.append("path", "images");
formData.append("files", file, file.name);
await axios
.post("http://localhost:1338/api/upload", formData, {
headers: { authorization: `Bearer ${jwtToken}` },
})
.then(({ data }) => {
console.log(data);
})
.catch(console.log);
//
//
// backend logic:
const data = await processImage(img.url);
return data;
This is what im trying to do:
// frontend logic:
const data = await uploadImage(img);
//
//
// backend logic:
const data = await processImage(img.url);
const formData = new FormData();
formData.append("path", "images");
formData.append("files", data, "file.name");
await axios
.post("http://localhost:1338/api/upload", formData, {
headers: { authorization: `Bearer ${process.env.JWT_TOKEN}` },
})
.then(({ data }) => {
console.log(data);
})
.catch(console.log); // I get error: 413 Payload Too Large
I'm trying to do it with the same image which works with the first method. Perhaps I need to create a new File(), but I couldn't find any npm packages which worked for that. What should I do to get this working?
I want to implement the following cURL request (which is working) in react js using axios:
curl -k --request GET "BASE_URL_SERVER/sendText" --form "user_id="uidxxxx"" --form "sign_id="
I always get the same error: field sign_id not found, but technically I'm sending it, so I'm kind of desesperate.
var data = new FormData();
data.append('user_id', 'uidxxxx');
data.append('sign_id', '9');
const api = axios.create({
baseURL: BASE_URL_SERVER,
data: data,
headers: {
'Content-Type': `multipart/form-data; boundary=${data._boundary}`
},
timeout: 10000,
})
api.get('/sendText')
.then(response => console.log(JSON.stringify(response.data)))
.catch(error => { console.log(error) })
I've also tried adding '...getHeaders()' to the headers section but React says it is not a function; I've read in other posts that it has something to do with the browser
thanks in advance
ps: it is a pretty similar problem to this one, but none of the solutions worked for me
[UPDATE]
I ended up implementing it with POST, which is better for posting Form Data; no headers are needed, the browser automatically adds them:
var data = new FormData();
data.append('user_id', user_id);
data.append('sign_id', sign_id);
const api = axios.create({
baseURL: BASE_URL_SERVER,
timeout: TIMEOUT_SERVER,
})
api.post('/sendText', data)
.then(response => console.log(JSON.stringify(response.data)))
.catch(error => { console.log(error) })
You have a mistake, you try to send data via axios for POST and method is GET...
So that, You need to Change Method to be POST to can Post form data or you need to change it to url param or url path base on your api to be WORK as a GET...
Base on your curl, your case is you need a GET:
// Make a request for a user with a given ID
axios.get('/sendText?ID=12345')
.then(function (response) {
// handle success
console.log(response);
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always executed
});
// Optionally the request above could also be done as
axios.get('/user', {
params: {
sendText: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
})
.then(function () {
// always executed
});
Also, you can save all config in instance and share it for all nested of write it again and again..
for example:
// Common Axios Instance Config
const axiosConfig = {
baseURL: process.env.REACT_APP_API_ENDPOINT,
};
// Create Default Axios Instace
const instance = axios.create(axiosConfig);
I think base on your example this will work, but not sure sine I'm not test it..:
var data = new FormData();
data.append('user_id', 'uidxxxx');
data.append('sign_id', '9');
const api = axios.create({
baseURL: 'https://193.146.38.4:56076',
headers: {
'Content-Type': `multipart/form-data; boundary=${data._boundary}`
},
timeout: 10000,
})
api.get('/sendText', {
user_id: 111,
sign_id: 2222
)
.then(response => console.log(JSON.stringify(response.data)))
.catch(error => { console.log(error) })
For more details view this url
How can I send an image along with a text in VueJs to my backend ExpressJs?
Right now, what I did was create two http post request
NOTE this.albumName and this.albumDesc are just text and the formData is an image.
createAlbum() {
const formData = new FormData();
for (let file of Array.from(this.myAlbumImages)) {
formData.append("files", file);
}
if (this.albumName) {
axios
.post("http://localhost:9001/image/album", {
ALBUM: this.albumName,
DESCRIPTION: this.albumDesc
})
.then(resp => console.log(resp))
.catch(err => console.log(err));
setTimeout(function() {
axios
.post("http://localhost:9001/image/album", formData)
.then(resp => console.log(resp))
.catch(err => console.log(err));
}, 3000);
this.albumName = "";
this.albumDesc = "";
} else {
alert("Please fill the above form.");
}
},
and here is my Backend.
This creates the folder based on the passed data and it also creates a named undefined folder
router.post('/album', (req, res) => {
let sql = "INSERT INTO GALLERY SET ALBUM = ?, DESCRIPTION = ?";
let body = [req.body.ALBUM, req.body.DESCRIPTION]
myDB.query(sql, body, (error, results) => {
if (error) {
console.log(error);
} else {
let directory = `C:/Users/user/Desktop/project/adminbackend/public/${req.body.ALBUM}`;
fse.mkdirp(directory, err => {
if (err) {
console.log(err);
} else {
console.log(directory);
}
})
}
})
I think this is because of NodeJS is Asynchronous that's why it creates the undefined folder.
Reason for behavior you see is you are sending two different requests to the same route. 1st includes ALBUM and DESCRIPTION form field values, but not the files. Second (inside setTimeout) will contain just files and no other fields, so referencing them like req.body.ALBUM will return undefined
You can send all data (text fields and files) in one request. Just do this:
const formData = new FormData();
for (let file of Array.from(this.myAlbumImages)) {
formData.append("files", file);
}
formData.append("ALBUM", this.albumName);
formData.append("DESCRIPTION", this.albumDesc);
axios.post("http://localhost:9001/image/album", formData)
.then(resp => console.log(resp))
.catch(err => console.log(err));
FormData always uses content type multipart/form-data. To parse it on server side you need Express middleware that parses multipart forms, and gives you access to both fields and image/s. For example multer...
for the first part the client may can help you this link How to post image with fetch?
const fileInput = document.querySelector('#your-file-input') ;
const formData = new FormData();
formData.append('file', fileInput.files[0]);
const options = {
method: 'POST',
body: formData,
// If you add this, upload won't work
// headers: {
// 'Content-Type': 'multipart/form-data',
// }
};
fetch('your-upload-url', options);
and for the seerver part cant help you this link
Node Express sending image files as API response
app.get('/report/:chart_id/:user_id', function (req, res) {
res.sendFile(filepath);
});
and oficial documentation about this
http://expressjs.com/en/api.html#res.sendFile
I am currently trying to directly send an image via ngx-webcam without saving it to my backend server and send it to a Face Detection API via my node.js. The problem is that I keep getting an error for my header in my node.js file. How can I resolve this issue?
I noticed that the image url being passed is quite long. Could that be an issue?
Image url:
"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAHgAoADASIAAhEBAxE..."
My error is:
TypeError [ERR_HTTP_INVALID_HEADER_VALUE]: Invalid value "undefined" for header "Content-Length"
at ClientRequest.setHeader (_http_outgoing.js:473:3)
at FormData.<anonymous> (C:\Users\Roger\Documents\GitHub\angular-face-recognition-app\back-end\node_modules\form-data\lib\form_data.js:321:13)
at C:\Users\Roger\Documents\GitHub\angular-face-recognition-app\back-end\node_modules\form-data\lib\form_data.js:265:7
at C:\Users\Roger\Documents\GitHub\angular-face-recognition-app\back-end\node_modules\form-data\node_modules\async\lib\async.js:251:17
at done (C:\Users\Roger\Documents\GitHub\angular-face-recognition-app\back-end\node_modules\form-data\node_modules\async\lib\async.js:126:15)
at C:\Users\Roger\Documents\GitHub\angular-face-recognition-app\back-end\node_modules\form-data\node_modules\async\lib\async.js:32:16
at C:\Users\Roger\Documents\GitHub\angular-face-recognition-app\back-end\node_modules\form-data\node_modules\async\lib\async.js:248:21
at C:\Users\Roger\Documents\GitHub\angular-face-recognition-app\back-end\node_modules\form-data\node_modules\async\lib\async.js:572:34
at C:\Users\Roger\Documents\GitHub\angular-face-recognition-app\back-end\node_modules\form-data\lib\form_data.js:105:13
at FSReqWrap.oncomplete (fs.js:153:21)
Front end: Angular
Component file:
//captures image function
public handleImage(webcamImage: WebcamImage): void {
//stores it into webcamImageg variable
this.webcamImage = webcamImage;
//uses fda.sendImage function to send webcamImage to api via a service
this.fda.sendImage(this.webcamImage.imageAsDataUrl).subscribe(res => {});
}
Service file
sendImage(imgUrl){
console.log(imgUrl);
const obj = {
url: imgUrl
};
return this.http.post(`${this.uri}`, obj);
}
Backend: node.js
Route file
facedetAPIRoutes.route("/").post(function (req, res){
let imageUrl = req.body.url;
myFaceDetAPI.recognizeImg(imageUrl).then(function(result) {
// here is your response back
res.json(result);
});
});
Function file for api call: uses a promise
//I believe problem lies here somewhere
this.recognizeImg = (url)=>{
let requestString = "https://lambda-face-recognition.p.rapidapi.com/recognize";
let req = unirest("POST", requestString);
let imgURL = url;
let promise = new Promise(function(resolve, reject) {
unirest.post(requestString)
.header("X-RapidAPI-Key", API_KEY)
.attach("files", fs.createReadStream(imgURL))
.field("album", ALBUM_NAME)
.field("albumkey", ALBUM_KEY)
.end(result => {
console.log("successfully recognized image");
resolve(result.body) // giving response back
});
});
return promise;
}
You should try adding x-rapidapi-host and content-type headers.
.headers({
"content-type": "application/x-www-form-urlencoded",
"x-rapidapi-host": "lambda-face-recognition.p.rapidapi.com",
"x-rapidapi-key": "",
"useQueryString": true
})
I'm doing an application with react-native. Now I'm trying to send an image from the mobile to the server (Node Js). For this I'm using react-native-image-picker. And the problem is that when I send the image it save a file but it's empty not contain the photo. I think that the problem probably is that the server can't access to the path of the image because is in a different device. But I don't know how I can do it.
React-Native:
openImagePicker(){
const options = {
title: 'Select Avatar',
storageOptions: {
skipBackup: true,
path: 'images'
}
}
ImagePicker.showImagePicker(options, (imagen) =>{
if (imagen.didCancel) {
console.log('User cancelled image picker');
}
else if (imagen.error) {
console.log('ImagePicker Error: ', imagen.error);
}
else if (imagen.customButton) {
console.log('User tapped custom button: ', imagen.customButton);
}
else {
let formdata = new FormData();
formdata.append("file[name]", imagen.fileName);
formdata.append("file[path]", imagen.path);
formdata.append("file[type]", imagen.type);
fetch('http://X/user/photo/58e137dd5d45090d0b000006', {
method: 'PUT',
headers: {
'Content-Type': 'multipart/form-data'
},
body: formdata
})
.then(response => {
console.log("ok");
})
.catch(function(err) {
console.log(err);
})
}})}
Node Js:
addPhotoUser = function (req, res) {
User.findById(req.params.id, function(err, user) {
fs.readFile(req.body.file.path, function (err, data) {
var pwd = 'home/ubuntu/.../';
var newPath = pwd + req.body.file.name;
fs.writeFile(newPath, data, function (err) {
imageUrl: URL + req.body.file.name;
user.save(function(err) {
if(!err) {
console.log('Updated');
} else {
console.log('ERROR: ' + err);
}
res.send(user);
});
});
});
});
};
Yes, the problem is that the filepath is on the local device and not the server. You want to send the actual data returned to you by react-native-image-picker not the uri. It looks like that library encodes the data with base64 so you're going to want send that to your server, not the uri returned from the library because it won't be accessible on a remote server.
What this means is that you won't be reading any files on your server but instead just decoding a base64 string in the response body and writing that to your filesystem.
For the client side:
let formdata = new FormData();
formdata.append("file[name]", imagen.fileName);
formdata.append("file[data]", imagen.data); // this is base64 encoded!
formdata.append("file[type]", imagen.type);
fetch('http://X/user/photo/58e137dd5d45090d0b000006', {
method: 'PUT',
headers: {
'Content-Type': 'multipart/form-data'
},
body: formdata
})
On the server side atob to decode from base64 before writing to the filesystem:
let decoded = atob(req.body.data)
// now this is binary and can written to the filesystem
From there:
fs.writeFile(newPath, decoded, function (err) {
imageUrl: newPath;
user.save(function(err) {
if(!err) {
console.log('Updated');
} else {
console.log('ERROR: ' + err);
}
res.send(user);
});
});
Note, you don't need the filesystem write that's in your code because you're decoding the image that was sent as a b64 string in your request.
There also seems to be some oddities with how you're using that user object. You seem to be only passing a function that handles errors and not any actual data. I don't know what ORM you're using so it's hard to say how it should work. Maybe something like this?
user.save({imageUrl:uriReturnedByFsWrite}, (err, data)=>{...})
Good luck :)
Make an object then send that object to the server. The object will consist of name,path and type, like this:
var imageData = {name: 'image1', path: uri, type: 'image/jpeg'}
Above is a one way to send the image data. The other way is to convert it into BLOB so that server side programmer doesn't have to do this task on their end. You can make BLOB by use of react-native-fetch-blob.
One more way is to directly upload the images to the amazon server(s3) and send the link to the backend..
Function that returns base64 string:
var RNFetchBlob = require('react-native-fetch-blob').default;
getImageAttachment: function(uri_attachment, mimetype_attachment) {
return new Promise((RESOLVE, REJECT) => {
// Fetch attachment
RNFetchBlob.fetch('GET', config.apiRoot+'/app/'+uri_attachment)
.then((response) => {
let base64Str = response.data;
var imageBase64 = 'data:'+mimetype_attachment+';base64,'+base64Str;
// Return base64 image
RESOLVE(imageBase64)
})
}).catch((error) => {
// error handling
console.log("Error: ", error)
});
},
Cheers :)