Reputation: 838
I am building a web application using the MERN stack (MongoDB, Express Server, ReactJS front end and NodeJS back end) and was wondering some good ways to store images from the back end.
In the past, I have used Firebase for authentication and storage directly from the front end. As I am handling my own user authentication model in MongoDB, is it possible to still use firebase storage and if so would it be from the front end or back end. If it was from the front end, how would I secure it without having firebase authentication?
Other options I have read into are storing images into MongoDB using GridFS or storing on the server using Multer.
Once I have a solution in mind, I will be able to read the docs and figure out how to get it done.
Any advice is appreciated.
Upvotes: 8
Views: 12431
Reputation: 838
I ended up implementing Firebase Storage from the Firebase Admin SDK and using Multer to store images in memory until I load them to Firebase.
https://firebase.google.com/docs/storage/admin/start
const uploader = multer({
storage: multer.memoryStorage(),
limits: {
fileSize: 5 * 1024 * 1024,
},
});
// @route POST api/users/upload/avatar
// @desc Upload a new avatar and save to storage
// @access Private
router.post('/upload/avatar', [auth, uploader.single('image')], async (req, res, next) => {
if (!req.file) {
res.status(400).json({ msg: 'No file submitted.' });
return;
}
try {
const blob = firebase.bucket.file(req.file.originalname);
const blobStream = blob.createWriteStream({
gzip: true,
resumable: false,
metadata: {
contentType: req.file.mimetype,
},
});
blobStream.on('error', (err) => next(err));
blobStream.on('finish', () => {
publicUrl = `https://firebasestorage.googleapis.com/v0/b/${
firebase.bucket.name
}/o/${encodeURI(blob.name)}?alt=media`;
res.status(200).json({
photoURL: publicUrl,
});
User.findById(req.user.id).then((user) => {
user.photoURL = publicUrl;
user.save();
});
});
blobStream.end(req.file.buffer);
} catch (error) {
console.error(error.message);
res.status(500).send({ msg: 'A Server error occurred' });
}
});
Thought this might be helpful if someone stumbles upon this post in the future.
Upvotes: 3
Reputation: 86
I think using multer is the very convenient way.
You can upload the images into a folder using multer and store the reference URL in MongoDB. It is also important if you are willing to host your MERN application. You don't need any third party help like firebase or Cloudinary uploads and authentications (you have done this already).
So you can host your own app using your own functionalities. No external cost (just for the domain :D)
This may help you to get a brief idea.
const InstrumentImageStore = multer.diskStorage({
destination: function (req, file, callback) {
const userId = req.userId;
const dir = `instrumentImgs/${userId}`;
fs.exists(dir, (exist) => {
if (!exist) {
return fs.mkdir(dir, (error) => callback(error, dir));
}
return callback(null, dir);
});
},
filename: function (req, file, callback) {
callback(null, Date.now() + "-" + file.originalname);
},
});
router.post(
"/add/instrument",
[isauth, multer({ storage: InstrumentImageStore }).array("imageArr", 5)],
//isauth is another middleware that restricts requests using JWT
instrumentController.addInstrument
);
Upvotes: 3
Reputation: 4873
An option is to upload the image to Cloudinary in the client-side and save the returned URL to MongoDB with your own API. Cloudinary does more than hosting your images but also handles image manipulation and optimization and more.
Basically what you will have to do is:
Then your upload function can be something like this:
async function uploadImage(file) { // file from <input type="file">
const data = new FormData();
data.append("file", file);
data.append("upload_preset", NAME_OF_UPLOAD_PRESET);
const res = await fetch(
`https://api.cloudinary.com/v1_1/${YOUR_ID}/image/upload`,
{
method: "POST",
body: data,
}
);
const img = await res.json();
// Post `img.secure_url` to your server and save to MongoDB
}
Upvotes: 5
Reputation: 599011
You can wire up any external authentication system to Firebase Authentication by [implementing a custom provider](https://firebase.google.com/docs/auth/web/custom-auth for the latter.
This requires that you run code in a trusted environment, such as a server you control or Cloud Functions, where you take the authentication results of the user and convert them into a Firebase Authentication token.
The client-side then signs into Firebase with that token, and from that moment on Storage (and other services) knows about the user just as before.
Upvotes: 1