Trouble using expo file upload - node.js

So i've been trying to wrap my head around uploading an image to backend node.js server, but i'm having trouble understanding the doc and the process. Note that i've already done this in a web app before using react in the front and multer in the backend. done it multiple times without trouble. I've found the expo-file-system package which is helpful.
https://docs.expo.dev/versions/v45.0.0/sdk/filesystem/#filesystemuploadasyncurl-fileuri-options
i'm having trouble understanding the FileSystem.uploadAsync method. Here's all code listed down below. a normal axios api call to upload the image would look like this
const data = new FormData();
data.append("images", listing.images[0]);
await axios({
method: "post",
url: "http://localhost:5000/products/addProduct",
data: data,
headers: { "Content-Type": "multipart/form-data" },
})
.then((response) => {
console.log(response);
})
.catch((error) => {
//
});
the backend
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "./images");
},
filename: function (req, file, cb) {
cb(null, Date.now() + file.originalname);
},
});
router.post(
"/products/addProduct",
upload.single("images"),
async (req, res) => {
try {
res.send("ok");
} catch (err) {
res.send("Error " + err);
}
}
);
Also, i tested the backend using an api client (insomnia) it works without a problem !
So please how can i use the FileSytem.uploadAsync method to upload my images to the backend !!!

Related

Trouble uploading file using expo FileSystem library

So i'm building a marketplace mobile app using, expo that let users upload products to the marketplace. I'm having difficult times using the expo FileSystem.FileSystemUploadType(https://docs.expo.dev/versions/latest/sdk/filesystem/#filesystemfilesystemsessiontype) to pick the image and send to the backend.
here's my front-end code
const handleSubmit = async (listing, { resetForm }) => {
const data = new FormData();
data.append("images", listing.images[0]);
data.append("description", "Good product");
console.log( listing.images[0])
// it does console the file uri
// file:///Users/zakisb/Library/Developer/CoreSimulator/Devices/83E12EA5-E8FA-4850-82C1-84021B25450D/data/Containers/Data/Application/6873BF40-26E4-4BD3-834D-F6772448C004/Library/Caches/ExponentExperienceData/%2540anonymous%252Flokazz_app2-5f4724db-b9d7-45aa-a8ca-ac5acf2f4780/ImagePicker/B72CF40C-EC27-430E-B1F8-B983C0ACF2FB.jpg
// i tried this solution first and worked perfectly. but it does upload the image only and i want to send the formdata object
const response = await FileSystem.uploadAsync(
"http://192.168.43.8:5000/products/addProduct",
listing.images[0],
{
fieldName: "images",
uploadType: FileSystem.FileSystemUploadType.MULTIPART,
}
);
// so i tried this but i get an error
const response = await FileSystem.FileSystemUploadType.MULTIPART(
"http://192.168.43.8:5000/products/addProduct",
data
);
};
My backend works perfectly. i tried the api call using insomnia and postman the file gets uploaded successfully to the folder. but using expo methods i get nothing.
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "./images");
},
filename: function (req, file, cb) {
cb(null, Date.now() + file.originalname);
},
router.post(
"/products/addProduct",
upload.single("images"),
async (req, res) => {
console.log(req.body);
try {
res.send(req.body);
} catch (err) {
res.send("Error " + err);
}
}
);
});

How To Send Files From One Nodejs Server To Another Nodejs Server using POST request and save into folder?

I want to send some image file from one Nodejs server to another Nodejs server. And how to get the file in second server? Also how to save into a folder in second server?
How to do that any suggestion?
First server
uploadImage(req, callback) {
var formData = new FormData();
var body = {
"file": req.file,
}
var options = {
'method': 'POST',
'url': config.db_layer_endpointUpload,
'headers': {
'api_key': config.db_layer_access_key,
'content-type': 'application/json'
},
body: JSON.stringify(body),
}
request(options, function (error, response) {
return callback(response.body);
})
}
Second server
app.post(
"/upload",
multerObj.single("file"),
(req, res) => {
console.log(req.body);
}
);
When console.log i am getting following result in Second server file
But Image is not saved in the asset folder. Multer and storage are fine. When i uploaded Image to Second server directly its working fine.
The first thing you need to do is create an API using node/Express.js and create store using multer:
const storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, 'uploads/');
},
// By default, multer removes file extensions so let's add them back
filename: function(req, file, cb) {
cb(null, file.fieldname + '-' + Date.now() +
path.extname(file.originalname));
}
});
Build the image filter function:
const imageFilter = function(req, file, cb) {
// Accept images only
if (!file.originalname.match(/\.(jpg|JPG|jpeg|JPEG|png|PNG|gif|GIF)$/)) {
req.fileValidationError = 'Only image files are allowed!';
return cb(new Error('Only image files are allowed!'), false);
}
cb(null, true);
};
exports.imageFilter = imageFilter;
Create an API to handle image get from request:
app.post('/upload-pic', (req, res) => {
let upload = multer({ storage: storage, fileFilter: helpers.imageFilter }).single('pic');
upload(req, res, function(err) {
// req.file contains information of uploaded file
// req.body contains information of text fields, if there were any
if (req.fileValidationError) {
return res.send(req.fileValidationError);
}
else if (!req.file) {
return res.send('Please select an image to upload');
}
else if (err instanceof multer.MulterError) {
return res.send(err);
}
else if (err) {
return res.send(err);
}
// Display uploaded image for user validation
res.send(`You have uploaded this image`);
});
});
Now you have the server side accept the image from request and save it on file. After that, let us go back to the other server. On other server it's like a client and we need create request to the API upload-pic . To do that you can use axios package and form-data package.
Handling File Uploads

How to compress image using Sharp JS after uploading with Multer

I feel like my code is complete frankenstein at this point but I do wonder why this formula does not work.
Once the file is uploaded, I can access the path with req.file.path and so I try to plug that into sharp but nothing happens. I'm not getting any errors or the expected result. (I'm using .rotate() to make it more obvious in testing)
var storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, 'public/uploads')
},
filename: function(req, file, cb) {
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname))
}
});
var upload = multer({
storage: storage
});
router.post("/new", upload.single('image'), function(req, res) {
sharp(req.file.path).rotate();
var post = {
title: req.body.title,
image: uploadedImage,
description: req.body.description,
body: req.body.body
}
Blog.create(post, function(err, newPost) {
if (err) {
console.log(err);
res.redirect("/")
} else {
res.redirect("/");
}
});
});
You either need to use async/await or Promises as the calls to sharp are asynchronous. You will also need to do something with the modified/rotated file like copying it to a Buffer or saving to a File. See these examples in the documentation.
// use an async function
router.post("/new", upload.single('image'), async function(req, res) {
await sharp(req.file.path).rotate().toFile('/path/to/file');
// ... rest of your code
});

not able to upload file using multer

I have seen many answers on this and tried almost all of it but none seems to work for me. I can print the form data as ascii chars but I don't see the file stored in the public/uploads folder as expected. I can read and render stored files on react app using API but can't upload it. I get no errors, everything works fine but no file is uploaded in the folder. I'm trying to upload a file using multer and below are the code snippets :
routes/uploads.js
var storage = multer.diskStorage({
dest : function (req, file, cb) {
cb(null, path.join(__dirname, 'public/uploads/'))
}
});
var upload = multer({storage:storage}) ;
router.post('/upload', upload.single('mypic'), function (req, res, next) {
console.log("inside upload files");
console.log(req.body); //prints non-readable characters as I am uploading image as expected
console.log(req.file); //says undefined
return res.status(204).end();
});
API.js (React side):
export const uploadFile = (payload) => //payload is actually formdata
fetch(`${api}/files/upload`,
{
method: 'POST',
//headers: { 'Content-Type': 'application/json' },
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
},
body: payload
}
)
.then(res => {
console.log(res);
return res.status;
})
.catch(error => {
console.log(error);
return error;
});
Try below IT contains multiple parts:
var storage = multer.diskStorage({
destination: function (req, file, cb) {
const extension = file.mimetype.split('/')[1];
//you can change destination runtime
if(file.fieldname == "covers[]")
{
cb(null, __dirname, '../public/uploads/cover');
return;
}
else
{
cb(null, '../public/uploads/image');
return;
}
},
filename: function (req, file, cb) {
//you can also change name
cb(null, filename)
}
});
var upload = multer({
storage: storage,
});
Try removing :
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'

Transform upload with NodeJS Multer

I'm currently implementing a file/image upload service for my users. I want to transform these images (resize/optimize) before uploading to my s3 bucket.
What I'm currently doing: Using a multipart form on my frontend (I think the actual implementation doesn't matter here..) and the multer and multer-s3 packages on my backend.
Here my implementation stripped down to the important parts.
// SETUP
var multer = require('multer');
var s3 = require('multer-s3');
var storage = s3({
dirname: 'user/uploads',
bucket: auth.aws.s3.bucket,
secretAccessKey: auth.aws.s3.secretAccessKey,
accessKeyId: auth.aws.s3.accessKeyId,
region: auth.aws.s3.region,
filename: function (req, file, cb) {
cb(null, Date.now());
}
});
var upload = multer({storage: storage}).single('img');
// ROUTE
module.exports = Router()
.post('/', function (req, res, next) {
upload(req, res, function (err) {
if (err) {
return res.status(401).json({err: '...'});
}
return res.json({err:null,url: '..'});
});
});
What I want to do: transform the image before uploading it. I'm not sure if I need to use multer/busboy here or I can just do it with NodeJS (thus I've tagged NodeJS and express as well).
So my question is: where can I intercept the upload and transform it before uploading it to my S3 bucket?
Not sure if you're still looking for an answer to this, but I had the same problem. I decided to extend the multer-s3 package.
I've opened a pull request to the original repository, but for now, you can use my fork.
Here's an example of how to use the extended version:
var upload = multer({
storage: multerS3({
s3: s3,
bucket: 'some-bucket',
shouldTransform: function (req, file, cb) {
cb(null, /^image/i.test(file.mimetype))
},
transforms: [{
id: 'original',
key: function (req, file, cb) {
cb(null, 'image-original.jpg')
},
transform: function (req, file, cb) {
cb(null, sharp().jpg())
}
}, {
id: 'thumbnail',
key: function (req, file, cb) {
cb(null, 'image-thumbnail.jpg')
},
transform: function (req, file, cb) {
cb(null, sharp().resize(100, 100).jpg())
}
}]
})
})
EDIT: My fork is also now available via npm under the name multer-s3-transform.
I've tried using #ItsGreg's fork, but couldn't get it to work. I managed to get this behaviour working by using multer-s3 standard configuration, and inside my file upload endpoint, i.e.,
app.post('/files/upload', upload.single('file'), (req, res) => {...})
I am retrieving the file using request, and passing the Buffer to sharp. The following works (and assumes you are using ~/.aws/credentials):
let request = require('request').defaults({ encoding: null });
let dataURI = `https://s3.amazonaws.com/${process.env.AWS_S3_BUCKET}/${image.defaultUrl}`;
request.get(dataURI, function (error, response, body) {
if (! error && response.statusCode === 200) {
let buffer = new Buffer(body);
const sizes = ['thumbnail', 'medium', 'large'];
sizes.forEach(size => {
sharp(buffer)
.resize(image.sizes[size])
.toBuffer()
.then(data => {
// Upload the resized image Buffer to AWS S3.
let params = {
Body: data,
Bucket: process.env.AWS_S3_BUCKET,
Key: `${image.filePath}${image.names[size]}`,
ServerSideEncryption: "AES256",
};
s3.putObject(params, (err, data) => {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
})
})
}
});

Resources