I am trying to upload multiple files to Google Cloud bucket using Node.js and multer. It works with multer.single function but I don't know how to upload multiple images at once.
const bucket = gc.bucket('still-cover');
// Multer is required to process file uploads and make them available via
// req.files.
const multer = Multer({
storage: Multer.memoryStorage(),
limits: {
fileSize: 5 * 1024 * 1024, // no larger than 5mb, you can change as needed.
},
});
Router.post('/test/upload',multer.array('files',5),async(req,res)=>{
if (!req.files) {
res.status(400).send('No file uploaded.');
return;
}
// Create a new blob in the bucket and upload the file data.
const blob = bucket.file(req.files.originalname);
const blobStream = blob.createWriteStream();
blobStream.on('finish', res => {});
blobStream.on('finish', () => {
// The public URL can be used to directly access the file via HTTP.
const publicUrl = `https://storage.googleapis.com/${bucket.name}/${blob.name}`
res.status(200).send(publicUrl);
});
blobStream.end(req.files.buffer);
});
You can use multer.array('files', numberoffiles) or multer.any()to upload files to your Google Cloud Storage Bucket. You can use the following code to upload multiple files using Multer:
const express = require('express');
const path = require('path');
const cors = require('cors');
const Multer = require('multer');
const bodyParser = require('body-parser');
const {Storage} = require('#google-cloud/storage');
// Creates a client
const storage = new Storage();
const bucket = storage.bucket('YOUR_BUCKET_NAME')
const PATH = './public/';
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
const multer = Multer({
storage: Multer.memoryStorage(),
limits: {
fileSize: 5 * 1024 * 1024, // no larger than 5mb, you can change as needed.
},
});
app.get('/', function(req, res){
res.json({
json: "json"
});
})
// You can also use multer.array('data', numberofFiles)
app.post('/', multer.any(), function(req, res) {
console.log(req.files);
var counter = 0;
if (!req.files) {
res.status(400).send('No file uploaded.');
return;
}
// Create a new blob in the bucket and upload the file data.
req.files.forEach((fil) => {
const blob = bucket.file(fil.originalname);
const blobStream = blob.createWriteStream();
blobStream.on('finish', () => {
counter+=1
// The public URL can be used to directly access the file via HTTP.
const publicUrl = `https://storage.googleapis.com/${bucket.name}/${blob.name}`
if(counter>=2){
res.status(200).send(publicUrl);
}
});
blobStream.end(req.files.buffer);
});
});
app.listen(3000, function () {
console.log("Working on port 3000");
});
On the line blobStream.end(req.files.buffer); replace files.buffer with fil.buffer.
Related
I am trying to use Multer file upload in my React/Express application. But, I am getting an error that says that the file object is undefined. I have moved all of my Express server api functions into their own file, which has been working fine. I would like to keep the file upload API function in the same file as the rest of the API functions. This is what I have:
server.js
const express = require("express");
var cors = require("cors");
const config = require('config');
const { errorHandler } = require("./middleware/errorMiddleware");
const PORT = config.get('app_port') || 8000;
const app = express();
app.use(express.json());
app.use(cors());
app.use(express.urlencoded({ extended: false }));
app.use("/api/meshnodes", require("./routes/myCrudRoutes"));
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
app.use(errorHandler);
myCrudRoutes.js
const express = require('express')
const router = express.Router()
const {uploadFile} = require('../controllers/myCrudContoller')
router.post('/catalog/files/upload/', uploadFile)
module.exports = router
myCrudControllers.js
const ansyncHandler = require("express-async-handler");
const multer = require("multer");
let storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "./uploads");
},
filename: function (req, file, cb) {
let extension = getFileExtention(file.mimetype);
cb(null, file.fieldname + "-" + Date.now() + "." + extension);
},
});
const upload = multer({ storage: storage });
const uploadFile = (upload.single("File"), (req,res, next)=>{
console.log("got file2 ")
const file = req.body;
console.log(req)
if (!file) {
const error = new Error("No File");
error.httpStatusCode = 400;
return next(error);
}
console.log("server upload ")
});
I believe the issue is with my myCrudControllers.js uploadFile function. If I have this same functionality placed directly in my server.js file, like this:
app.post(
"/catalog/files/upload",
upload.single("File"),
(req, res, next) => {
const file = req.file;
//...
It works fine, but I want to be consistent in where I have my API functions.
thanks
I refactored my code and this works:
First, I created a helper file:
uploader.js
const multer = require('multer');
let storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, process.env.REACT_APP_UPLOAD_LOCATION);
},
filename: function (req, file, cb) {
let extension = getFileExtention(file.mimetype);
cb(null, file.fieldname + "-" + Date.now() + "." + extension);
},
});
const upload = multer({ storage: storage });
myCrudRoutes.js
const uploadHelper = require('../helpers/uploader');
router.post('/catalog/files/upload', uploadHelper.upload.single('File'), uploadFile);
myCrudControllers.js
const uploadFile = ansyncHandler(async (req,res)=>{
const file = req.file;
if (!file) {
const error = new Error("No File");
error.httpStatusCode = 400;
return error;
}
//other stuff
}, (error, req, res, next) => {
res.status(400).send({ error: error.message });
}
);
Please I'm new to Nodejs and I'm trying to create an image uploader that will upload files to my server using Nodejs and multer, but the problem is in getting the image back to be displayed in my angular app.
This is the backend code:
const express = require('express');
const multer = require('multer');
const cors = require('cors');
const app = express();
var corsOptions = {
origin: "*",
optionsSuccessStatus: 200,
}
app.use(cors(corsOptions));
app.use(express.static('uploads'));
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 });
app.post('/file', upload.single('file'), (req, res) => {
const file = req.file;
if (file) {
res.json(file);
} else {
throw new Error('File upload unsuccessful')
}
})
const port = 3000;
app.listen(port, () => console.log(`Server running on port ${3000}`));
This is my app.html code:
<input type="file" name="image" (change)="upload($event)">
This is my app.ts code:
upload(event: any) {
const file = event.target.files[0];
const formdata = new FormData();
formdata.append('file', file)
this.httpClient.post('http://localhost:3000/file', formdata)
.subscribe((data) => {
console.log(data);
},
(error) => {
console.log(error)
})
Please help me retrieve the image so that I can use it in my angular app. Thank you.
There are two ways you can achieve this. Both the approaches have their own pros and cons.
Store the image locally and send the URL back to the browser.
if (req.files) {
const fileNames = [];
for (let i = 0; i < req.files.length; i++) {
const file = req.files[i];
const relPath = "your/img/path";
const dirName = path.join(BASE_APP_PATH, relPath);
const relFileName = path.join(
relPath,
`${i + 1}_${file.originalname.replace(",", "")}`
);
const img_location = `${dirName}/${
i + 1
}_${file.originalname}`;
if (!fs.existsSync(dirName)) fs.mkdirSync(dirName, { recursive: true });
fs.writeFileSync(img_location, file.buffer, {});
fileNames.push(relFileName);
}
}
Get the image and send back base64 to the browser.
const encoded = req.files[0].buffer.toString('base64')
So I am looking at the sample code from Google and I can't work out how do I activate the config file?
https://cloud.google.com/appengine/docs/flexible/nodejs/using-cloud-storage
The sample code:
const {format} = require('util');
const express = require('express');
const Multer = require('multer');
const bodyParser = require('body-parser');
// By default, the client will authenticate using the service account file
// specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable and use
// the project specified by the GOOGLE_CLOUD_PROJECT environment variable. See
// https://github.com/GoogleCloudPlatform/google-cloud-node/blob/master/docs/authentication.md
// These environment variables are set automatically on Google App Engine
const {Storage} = require('#google-cloud/storage');
// Instantiate a storage client
const storage = new Storage();
const app = express();
app.set('view engine', 'pug');
app.use(bodyParser.json());
// Multer is required to process file uploads and make them available via
// req.files.
const multer = Multer({
storage: Multer.memoryStorage(),
limits: {
fileSize: 5 * 1024 * 1024, // no larger than 5mb, you can change as needed.
},
});
// A bucket is a container for objects (files).
const bucket = storage.bucket(process.env.GCLOUD_STORAGE_BUCKET);
// Display a form for uploading files.
app.get('/', (req, res) => {
res.render('form.pug');
});
// Process the file upload and upload to Google Cloud Storage.
app.post('/upload', multer.single('file'), (req, res, next) => {
if (!req.file) {
res.status(400).send('No file uploaded.');
return;
}
// Create a new blob in the bucket and upload the file data.
const blob = bucket.file(req.file.originalname);
const blobStream = blob.createWriteStream();
blobStream.on('error', (err) => {
next(err);
});
blobStream.on('finish', () => {
// The public URL can be used to directly access the file via HTTP.
const publicUrl = format(
`https://storage.googleapis.com/${bucket.name}/${blob.name}`
);
res.status(200).send(publicUrl);
});
blobStream.end(req.file.buffer);
});
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`App listening on port ${PORT}`);
console.log('Press Ctrl+C to quit.');
});
However when you read https://github.com/GoogleCloudPlatform/google-cloud-node/blob/master/docs/authentication.md it says to set up a config file and do the following
{
"projectId": "grape-spaceship-123",
"keyFilename": "./PROJECT-XXXXXX.json"
}
The keyFilename links to the google generated JSON.
But now how do I tell the sample code above to use that?
NOTE: Adding the config file
const config = require('./config')
I created storage and its work for me:
import { Storage } from '#google-cloud/storage';//may be you need to use require()
import * as path from 'path';
const storage = new Storage({
keyFilename: path.join(__dirname, '../********************.json'),
projectId: '***********Id'
})
const fileBucket = storage.bucket('***********-storage');
Good video about this: https://www.youtube.com/watch?v=pGSzMfKBV9Q
I am using first-time AWS' S3 bucket. I used node, express server, multer, and multerS3. For testing I used postman. I wanted to upload image to my s3 bucket. I have created the bucket also add my credentials to my backend. But when I am trying to upload an image by using postman, (this is how I did post request). I got error "TypeError: Cannot read property 'transfer-encoding' of undefined".
This is my s3 setup
const aws = require("aws-sdk");
const multer = require("multer");
const multerS3 = require("multer-s3");
aws.config.update({
secretAccessKey: "AKIAJWFJ6GS2*******",
accessKeyId: "W/2129vK2eLcwv67J******",
region: "us-east-1"
});
const s3 = new aws.S3();
const upload = multer({
storage: multerS3({
s3: s3,
bucket: "testing-alak",
metadata: function(req, file, cb) {
cb(null, { fieldName: file.fieldname });
},
key: function(req, file, cb) {
cb(null, Date.now().toString());
}
})
});
module.exports = upload;
This is upload file setup
const express = require("express");
const router = express.Router();
const upload = require("./upload-file");
const singleUpload = upload.single("image");
router.post("/", (req, res) => {
singleUpload((req, res, next) => {
return res.json({
imgUrl: req.file.location
});
});
});
module.exports = router;
This is my express server
const express = require("express");
const app = express();
const route = require("./route");
const bodyParser = require("body-parser");
app.use(express.json()); //body Parser
app.use(bodyParser.urlencoded({ extended: true }));
app.use("/img", route);
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`🚀 App is listening at port ${port}!`));
If singleUpload is multer middleware, I've always used it like this:
router.post("/", singleUpload, (req, res) => {
return res.json({
imgUrl: req.file.location // this should be path?
});
});
Also, I don't think there is a location property. Maybe path is what you are looking for?
fieldname Field name specified in the form
originalname Name of the file on the user's computer
encoding Encoding type of the file
mimetype Mime type of the file
size Size of the file in bytes
destination The folder to which the file has been saved DiskStorage
filename The name of the file within the destination DiskStorage
path The full path to the uploaded file DiskStorage
buffer A Buffer of the entire file MemoryStorage
I have a file nodejs that adds the picture(lion.jpg) to Cloud Storage
const firebase = require('firebase-admin');
const express = require('express');
const app = express();
const serviceAccount= require("./key9525")
firebase.initializeApp({
credential: firebase.credential.cert(serviceAccount),
databaseURL: "https://myadress.firebaseio.com" //example adress
});
const bucketName = 'myadress.appspot.com';
const filename ='./lion.jpg'; //example file
async function uploadFile() {
const {Storage} = require('#google-cloud/storage');
const storage = new Storage();
await storage.bucket(bucketName).upload(filename, {
gzip: true,
metadata: {
cacheControl: 'public, max-age=31536000',
},
});
console.log(`${filename} uploaded to ${bucketName}.`);
}
uploadFile();
and I have a file that allows me to select and upload a photo for example in postman
const express = require('express');
const app = express();
const port = 3000;
app.get('/', (req, res) => {
res.send('hello people');
});
app.listen(port, () => {
console.log('listening to the port: ' + port);
});
var multer = require('multer');
var upload = multer({dest:'uploads/'});
app.post('/single', upload.single('profile'), (req, res) => {
try {
res.send(req.file);
}catch(err) {
res.send(400);
}
}
How I can connect these codes so that after loading the nodejs file, then selecting the file in postman, the file was upload in firebase?
thank you for all tips
You have to pass the multer as the middleware to your POST call as like what you did. Please refer this link