Upload file to aws S3 bucket using absolute path - javascript

I am trying to upload files from Express ejs to AWS s3 bucket I am successful in doing so but when I am trying to select files from other directory or folder other than where my index.js is it doesn't accept the file and throw error file not found.
index.js
'use strict';
const express = require('express');
const app = express();
const multer = require('multer');
const multerS3 = require('multer-s3');
const AWS = require('aws-sdk');
const bodyParser = require('body-parser');
const s3 = new AWS.S3({
accessKeyId: '',
secretAccessKey: ''
});
app.use(bodyParser.urlencoded({extended : true}));
app.set('view engine', 'ejs');
const uploadS3 = multer({
storage: multerS3({
s3: s3,
bucket: '',
metadata: (req, file, cb) => {
cb(null, {fieldName: file.fieldname})
},
key: (req, file, cb) => {
cb(null, Date.now().toString() + '-' + file.originalname)
}
})
});
test.ejs
<html>
<form method="post" action="/upload">
<input type="file" name="file" />
<input type="submit" />
</form>
</html>
route.js
var fileupload = require('../../common/service/file-upload');
//some code in between
app.post('/upload', fileupload.uploadS3.single('file'),(req, res) => {
console.log(req.file);
});

whenever you are uploading the files you need to add attribute to form enctype="multipart/form-data". .then it will work.
to upload files to s3 use multer-s3 package which is simple to configure
Refrence : https://www.npmjs.com/package/multer-s3
so your test.ejs file will be like this
<html>
<form method="post" action="/upload" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" />
<const/form>
</html>
and index.js
const express = require('express');
const bodyParser = require('body-parser');
const AWS = require('aws-sdk');
const multer = require('multer')
const multerS3 = require('multer-s3')
const app = express();
const s3 = new AWS.S3({
accessKeyId: //aws access key ,
secretAccessKey: //aws secret key
});
const upload = multer({
storage: multerS3({
s3: s3,
bucket: 'some-bucket',
metadata: function (req, file, cb) {
cb(null, {fieldName: file.fieldname});
},
key: function (req, file, cb) {
cb(null, Date.now().toString())
}
})
})
app.post('/', upload.single('file'), (req, res) => {
res.json({
message: "File uploaded to S3"
});
});

Man, how could Express read client's file by path? The files are uploaded / sent in the POST request.
Use some body parser that support multipart/form-data file upload, like mutler, to parse the file from the request & upload it to S3.
In example...
html
<html>
<!-- don't forget enctype parameter -->
<form method="post" action="/upload" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" />
</form>
</html>
node server using AWS and multer manually
const multer = require('multer'),
AWS = require('aws-sdk'),
S3 = new AWS.S3({
...
});
router.post('/', multer().single('file'), (req, res) => {
// debug req.file
console.log(req.file);
S3.upload({
Bucket: '...',
Key: req.file.originalname,
Body: req.file.buffer
}, (err, res) => {
if (err) throw err;
res.json({
message: "File uploaded to S3"
});
});
});
node server using multer-s3
const multer = require('multer'),
multerS3 = require('multer-s3'),
AWS = require('aws-sdk'),
S3 = new AWS.S3({
...
});
let upload = multer({
storage: multerS3({
s3: s3,
bucket: '...',
key: (req, file, cb)
=> cb(null, file.originalname), // or whatever Key you like
})
});
router.post('/', upload.single('file'), (req, res) => {
res.json({
message: "File uploaded to S3"
});
});

Related

Multer doesn't save the file to the web server

Hey I'm trying to use multer to save files on the web server but it doesn't work.
I tried every answer on stack overflow but nothing solves it. No error it just doesn't work. I tried running it both locally and on Openshift.
Here's the relevant lines from my code.
Client side:
<form id="upload_form" method="POST" action="/submit_upload" enctype="multipart/form-data">
<input type="text" id="name" name="name"><br>
<input type="file" id="software" name="software"><br>
<input type="submit" value="Upload">
</form>
Server side:
const express = require("express");
const multer = require("multer");
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended = true }));
var storage = multer.diskStorage({
destination: "uploads/",
filename: function(req, file, cb) {
cb(null, file.fieldname);
}
});
var upload = multer({ storage: storage, limits: { fieldSize: 10 * 1024 * 1024 } }).single("software");
app.post("/submit_upload", upload, function(req, res) {
console.log(req.body); // is alright
console.log(req.file); // undefined
}
app.listen(8080, function() { console.log("started"); });

Image Not Rendering in ejs

I have a simple app which gets heading, description and image from the user multer handle the image uploading part and I get the images in static folder called public and its sub folder uploads. Then it is toed in the database. I find it in database and try to render the image but image is not rendering. Although it is present in uploads folder but it is not rendering.
Here is My code.
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
const mongoose = require("mongoose");
const multer = require("multer");
const fs = require("fs");
const path = require("path");
//APP use
app.set("view engine", "ejs");
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static(__dirname+"./public/"));
//Multer Setup
const storage = multer.diskStorage({
destination: "./public/uploads/",
filename: (req, file, cb) => {
cb(null, file.fieldname + '_' + Date.now()+path.extname(file.originalname));
}
});
const upload = multer({ storage: storage }).single("img");
//Mongoose Setup
mongoose.connect('mongodb://localhost:27017/project-1', {useNewUrlParser: true, useUnifiedTopology: true}).then(console.log("Successfully connected to the server"));
//Routes
app.get("/", (req, res)=>{
BlogModel.find({}, function(err, foundItem){
if(err){
console.log(err);
}else{
console.log(foundItem);
res.render("home", {foundItem : foundItem});
}
})
});
app.get("/creat", (req, res)=>{
res.render("creat");
});
app.post("/creat", upload ,(req, res)=>{
const data = new BlogModel({
heading: req.body.name,
desc: req.body.desc,
img: req.file.filename
});
data.save((err)=>{
if(!err){
res.redirect("/");
}else{
console.log(err);
}
});
console.log("Successfully Submited The Form");
});
//Database Schema
const Blogschema = new mongoose.Schema({
heading: String,
desc: String,
img: String
});
//Database Model
const BlogModel = new mongoose.model("Image", Blogschema);
//Listen On Port 3000
app.listen(3000, ()=>{
console.log("Listening on port 3000");
});
<%- include('partials/header'); -%>
<% foundItem.forEach(function(item){ %>
<h1><%= item.heading %></h1>
<p><%=item.desc%></p>
<img src="./uploads/<%=item.img%>" alt="image">
<%})%>
<%- include('partials/footer'); -%>
Here it is stored in the public Folder inside Uploads
Here is the error.
Sorry if the code is to long.
Try adding 'public' for static folder name
app.use(express.static("public"));
Or if you want to use __dirname,
app.use(express.static(path.join(__dirname, 'public')))

Req.file undefined with express-fileupload and multer packages

I tried all possible scenarios and I tried with multiple variations and approaches suggested by documentation and by other stackoverflow questions.
Any of them worked -> I keep getting req.file is: undefined
Form:
<form action="/send" enctype="multipart/form-data" method="POST">
<input type="file" id="file" name="file">
<button type="submit">Submit</button>
Express Setup:
const express = require('express');
const ejs = require('ejs');
const homeController = require('./controlers/homeController');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.set('view engine', 'ejs');
app.use(express.static('public'));
app.listen(3000);
/* routes */
app.use(homeController);
I have the following code:
var multer = require('multer')
const storage = multer.diskStorage({
destination: './public/data/uploads',
filename: function(req, file, cb) {
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
var upload = multer({
storage: storage
}).single('file');
router.get('/', (req, res) => {
res.render('home')
})
router.post('/send', (req, res) => {
upload(req, res, (err) => {
if (err) console.log(err);
console.log('req.file is: ' + req.file);
});
})
I spent 2 days trying to figure this out but I can't see the light at the end of the tunnel, and i just want to get the file from client and send it with nodemailer as attachement later on.
Answer obtained based on eMAD suggestion on question How to perform an HTTP file upload using express on Cloud Functions for Firebase (multer, busboy)
Solution below:
File is saved on the storage location you define in muller.
req.files is an array with the details of the file/files you upload.
PS: thanks #eol for pointing me in this direction
const contactControler = require('../controlers/contactController');
const busboy = require('busboy')
const express = require('express');
const router = express.Router();
var multer = require('multer');
const SIZE_LIMIT = 10 * 1024 * 1024 // 10MB
var stor = multer.diskStorage({
destination: '../public/cv',
filename: function(req, file, callback) {
callback(null, file.originalname);
}
});
const multipartFormDataParser = multer({
storage: stor,
// increase size limit if needed
limits: { fieldSize: SIZE_LIMIT },
// support firebase cloud functions
// the multipart form-data request object is pre-processed by the cloud functions
// currently the `multer` library doesn't natively support this behaviour
// as such, a custom fork is maintained to enable this by adding `startProcessing`
// https://github.com/emadalam/multer
startProcessing(req, busboy) {
req.rawBody ? busboy.end(req.rawBody) : req.pipe(busboy)
},
})
router.post('/send', multipartFormDataParser.any(), contactControler.send);
Please try adding upload in your route as middleware.
router.post('/send', upload, (req, res) => { ...

Multer Unexpected field

I'm trying to upload a file into my project using multer, but I have no idea how to do it.
here's some of the code I wrote thinking it could work
// here's my ejs view
<form action="/wistia" method="post" enctype="multipart/form-data">
<input type="file" name="archivo">
<input type="submit">
</form>
// here's my route file
const multer = require("multer");
const express = require('express');
const router = express.Router();
let location = path.join(__dirname, '/uploads');
let upload = multer({ dest: location });
router.get("/wistia",function(req, res){
res.render("wistia");
});
router.post("/wistia", upload.single("archivo") , function(req, res) {
console.log(req.file);
});
thanks.
Try making this change
var upload = multer({
storage: multer.diskStorage({
destination: function (req, file, cb) {
cb(null,location);
}
})
});

multer - req.file always undefined

I've looked at a lot of answer for this same question, but I haven't found a working solution yet. I am trying to make a web app that you can upload files to using express and multer, and I am having a problem that no files are being uploaded and req.file is always undefined.
My code below
'use strict';
var express = require('express');
var path = require('path');
var multer = require('multer')
var upload = multer({ dest: 'uploads/' })
var app = express();
require('dotenv').load();
app.use(express.static(path.join(__dirname, 'main')));
app.post('/upload', upload.single('upl'), function (req, res, next) {
// req.file is the `avatar` file
// req.body will hold the text fields, if there were any
console.log(req.file);
res.status(204).end();
})
var port = process.env.PORT || 8080;
app.listen(port, function () {
console.log('Node.js listening on port ' + port + '...');
});
The form
<form class="uploadForm" action="/upload" method="post" enctype="multipart/formdata">
<label class="control-label">Select File</label>
<input name="upl" id="input-1" type="file" class="file">
<input type="submit" value="submit" />
</form>
Help very much appreciated, this is driving me crazy.
In case of postman, try following:
Close the postman tab for the API
Open a new tab again
Rebuild the API request and then send.
This may fix the problem. Every time you restart the server you need to do above steps for calling the API again. The reason being multer sends back some cookies called connect.sid to the client which it may require in further communication. Using old cookies will not upload the file.
Your enctype is slightly incorrect, it should be multipart/form-data instead of multipart/formdata.
I put MY (there are many I imagine and surely better) solution to help many people like me because I have searched during 1 entire day ;-(
//JS file on node side
var express = require('express');
var fileUpload = require('express-fileupload');
var fs = require("fs");
var app = express();
console.log('étape 0');
app.use(express.static('mesStatic'));
app.use(fileUpload());
console.log('étape 1');
app.get('/indexFileUpload.htm', function (req, res) {
res.sendFile( __dirname + "/" + "indexFileUpload.htm" );
})
console.log('étape 2');
app.post('/file_upload', function (req, res) {
console.log('étape 3');
console.log('req.files:' , req.files);
if (!req.files) {
res.send('No files to upload.');
return;
}
console.log('req.files.file.data:' , req.files.file.data);
var bufDataFile = new Buffer(req.files.file.data, "utf-8");
console.log('étape 3.1');
console.log('__dirname : ' + __dirname);
fs.writeFile(__dirname + '/file_upload/output.txt', bufDataFile, function(err) {
if (err) {
return console.error(err);
}
else {
console.log("Data written successfully !");
}
console.log('étape 4');
res.end('Fin OK !!!');
})
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port);
})
Yes, your enctype is wrong and that is the only problem. Make sure that you correct your enctype otherwise you are likely to get undefined in req.file or req.files.
Hello Guys I have also wasted 24 hours and was getting same error i.e req.file is undefined. Now you can refer below code to check your solution. This is single file demo code for uploading file using multer in Node and postman. In POSTMAN Select POST method and select form-data and Key name should be 'profile'.
var express = require('express');
const app = express();
const port = 3000;
var multer = require('multer');
var upload = multer({dest:'uploads/'});
var storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, './uploads');
},
filename: function (req, file, cb) {
cb(null , file.originalname);
}
});
var upload = multer({ storage: storage })
app.post('/single', upload.single('profile'), (req, res, error) => {
try {
console.log(req.file);
res.send(req.file);
}catch(err) {
res.send(400);
}
});
app.get('/', (req, res) => {
res.send('hello Guys');
});
app.listen(port, () => {
console.log('listening to the port: ' + port);
});
If you are using error handling as mentioned in the document, then req.file will be undefined.
An alternative way to use both error handling and to check if the file exists is to make use of express error handling:
index.js
const express = require("express");
const bodyParser = require("body-parser");
const upload = require("./upload");
const multer = require("multer");
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.get("/", function (req, res) {
res.send("Hello World");
});
app.post("/upload_file", upload.single("file"), function (req, res) {
if (!req.file) {
throw Error("FILE_MISSING");
} else {
res.send("success");
}
});
//Express Error Handling
app.use(function (err, req, res, next) {
if (err instanceof multer.MulterError) {
res.statusCode = 400;
res.send(err.code);
} else if (err) {
if (err.message === "FILE_MISSING") {
res.statusCode = 400;
res.send("FILE_MISSING");
} else {
res.statusCode = 500;
res.send("GENERIC_ERROR");
}
}
});
const server = app.listen(8081, function () {
const port = server.address().port;
console.log("App started at http://localhost:%s", port);
});
upload.js
const multer = require("multer");
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "./uploads");
},
filename: function (req, file, cb) {
cb(null, Date.now() + "_" + file.originalname);
},
});
const upload = multer({
storage: storage,
// limits: { fileSize: 10 },
});
module.exports = upload;
HTML File,
<form class="uploadForm" action="/upload" method="post" enctype="multipart/form-data">
<label class="control-label">Select File</label>
<input name="upl" id="input-1" type="file" class="file">
<input type="submit" value="submit" />
</form>
app.js
var express=require("express");
var multer=require("multer");
var app=express();
var upload=multer({dest:"uploads/"});
app.post("/upload",upload.single("upl"),function(req,res){
console.log("Uploaded Successfull with filename : "+req.upl.filename);
});
For us this was because we were using express-http-proxy to proxy the call before multer, and we needed to use the parseReqBody: false option to properly send over the file.
ie.
app.post('file/upload', proxy(process.env.API_URL, {
parseReqBody: false,
}))
Use:
formdata.append('file',document.getElementById("input-file").files[0]);
Instead of:
formdata.append('file',document.getElementById("input-file").files);
This is where I have done the mistake.
1- Add the below lines in your server.js or index.js root file
app.use(express.json());
app.use(express.urlencoded({
extended: true,
})
);
2- Create a folder name middleware and inside it create a file name
upload.js.
3- Place the following code in upload.js file
const multer = require("multer");
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "public/");
},
filename: function (req, file, cb) {
const imgName = file.originalname;
cb(null, imgName );
},
});
const upload = multer({
storage: storage,
});
module.exports = upload;
4- Add this middleware in any route. For example:
const upload = require("../middlewares/fileUpload");
router.route("/send").post(upload.single("profile"),
((req,res) => {
*your controller logic here*
});
**Note: Here profile is the name of the key of image or file that you are sending**
having a similar issue with req.file being undefined. It looks like the image file is available up until the hook useFormSubmit wraps it in the formData object and sends the formData request to the router/controller.
However even just sending the image using the body, nothing comes through from the hook to the controller. I've included images of the console logs for the status of the data from the component to the controller below, would appreciate any guidance on this:
Things I've tried:
-Sending the form in incognito to avoid cookies or caching
-Sending reviewImage data in the body itself without wrapping it in formData.append
-including the multer middleWare directly in the router and controller
-pulling the image from req.body instead of req.file
CreateReview.tsx
//hooks
import {useFormSubmit} from '../../Hooks/useFormSubmit'
//dependencies
import { useForm, SubmitHandler } from "react-hook-form";
export const CreateReview = () => {
const { register, handleSubmit, formState: { errors } } = useForm<ReviewInputs>();
const {createReview, error, isLoading} = useFormSubmit()
const onSubmit: SubmitHandler<ReviewInputs> = async (data) => {
const userID = user
const title: string = data.title
const review: string = data.review
const artist: string = data.artist
const author: string = data.author
const authorBand: string = data.authorBand
const banner: string = data.banner
const reviewImage: any = data.reviewImage[0]
await createReview(title, review, artist, userID, author, authorBand, banner, reviewImage)
navigate('/adminReviews')
}
return (
<>
<Form onSubmit={handleSubmit(onSubmit)} encType="multipart/form-data">
<Form.Label>Create A Review</Form.Label>
<Form.Group className="mb-3" controlId="exampleForm.ControlInput1">
<Form.Label>Title</Form.Label>
<Form.Control type="text" placeholder="Title" {...register('title', {required: true })} {...register} />
</Form.Group>
<Form.Group className="mb-3" controlId="exampleForm.ControlInput1">
<Form.Label>Artist</Form.Label>
<Form.Control type="text" placeholder="Artist" {...register('artist', {required: true })} {...register} />
</Form.Group>
<Form.Group className="mb-3" controlId="exampleForm.ControlInput1">
<Form.Label>Author</Form.Label>
<Form.Control type="text" placeholder="Author" {...register('author', {required: true })} {...register} />
</Form.Group>
<Form.Group>
<Form.Label>Author Band</Form.Label>
<Form.Control type="text" placeholder="Author Band" {...register('authorBand', {required: true })} {...register} />
</Form.Group>
<Form.Group>
<Form.Label>Upload An Image</Form.Label>
<Form.Control type="file" placeholder="Upload" {...register('reviewImage', {required: true })} {...register} />
</Form.Group>
<Form.Group>
<Form.Label>Banner</Form.Label>
<Form.Control type="text" placeholder="Banner" {...register('banner', {required: true })} {...register} />
</Form.Group>
<Form.Group>
<Form.Label>Review</Form.Label>
<Form.Control as="textarea" rows={12} {...register('review', {required: true })} {...register} />
<>{errors.review?.message}</>
</Form.Group>
<Row>
<Col xs={12}>
<Button type='submit'>Submit</Button>
</Col>
</Row>
</Form>
useFormSubmit
export const useFormSubmit = () => {
const {dispatch} = useReviewsContext()
const [error, setError] = useState(null)
const [isLoading, setIsLoading] = useState(false)
const createReview = async (title, review, artist, userID, author, authorBand, banner, reviewImage) => {
const formData = new FormData();
formData.append("reviewImage", reviewImage);
setIsLoading(true)
setError(null)
const response = await fetch('http://localhost:8080/api/admin/', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({title, review, artist, userID, author, authorBand, banner, formData })
})
const jsonResponse = await response.json()
if(!response.ok) {
setIsLoading(false)
setError(jsonResponse.error)
}
if(response.ok) {
setIsLoading(false)
dispatch({type: 'CREATE_REVIEW', payload: jsonResponse})
}
}
adminMiddleware.js
const multer = require('multer')
const storage = multer.diskStorage({
destination: (req, file, callback) => {
callback(null, '../../client/public/images')
},
filename: (req, file, callback) => {
callback(null, file.originalname)
}
})
const upload = multer({storage: storage})
module.exports = upload;
adminRoutes.js
const express = require('express')
const router = express.Router();
const upload = require('../middleware/adminMiddleware')
//controllers
const { createReview } = require('../controllers/reviewsController')
//CRUD reviews routes
router.post('/', upload.single('reviewImage'), createReview)
module.exports = router;
reviewsController.js
const createReview = async (req, res) => {
const {title, review, artist, userID, author, authorBand, banner} = req.body
const reviewImage = req.file.reviewImage
let emptyFields = []
if(!title) {
emptyFields.push('title')
}
if(!review) {
emptyFields.push('review')
}
if(!artist) {
emptyFields.push('artist')
}
if(!userID) {
emptyFields.push('userID')
}
if(!author) {
emptyFields.push('author')
}
if(!authorBand) {
emptyFields.push('authorBand')
}
if(!banner) {
emptyFields.push('banner')
}
if(!reviewImage) {
emptyFields.push('reviewImage')
}
if(emptyFields.length > 0) {
return res.status(400).json({ error: 'Please fill in all the fields', emptyFields })
}
// add doc to db
try {
const createdReview = await Review.create({title, review, artist, userID, author, authorBand, banner, reviewImage})
res.status(200).json(createdReview)
} catch (error) {
res.status(400).json({error: error.message})
}
}
Error Messages / Console logs

Categories

Resources