This article meant to be written for everything you need to know about file upload MERN stack specifically. π
if you want to escape this article for the code you can find here π
file upload mern Stack
Getting started
To get the client side running locally:
git clone https://github.com/IbrahimShamma99/file-upload
cd file-upload/
npm i
npm start
To get the server side running:
sudo service mongod restart
cd ./server
npm i
npm run dev
Let's get started π₯
1.Creating Server and Client instances ποΈ
I assume you have already installed npm, NodeJS & MongoDB, we need to create a react app.
NOTE: remember to put your repos on an organized folder structure.
Open the terminal and use the following commands:
npx create-react-app file-upload-mern
cd ./file-upload-mern
Also, we want to use axios to send the file to the server instance, to install axios:
npm i axios
here we created the react client-side app, we end with a file structure like this:
file-upload-mern
βββ .gitignore
βββ public
βββ package.json
βββ src
β βββ App.js
β βββ index.js
β βββ App.css
β βββ index.css
β βββ serverWorker.js
β βββ setupTests.js
βββ README.md
Now, we need now to create the server-side app also, on the folder file-upload-mern
write the following on the terminal:
mkdir server
cd ./server
npm init -y
touch server.js
touch model.js
mkdir public
- server.js => is where the server instance will be
- model.js => Where the file schema on mongoDB
To make sure we are on the same page this is the final file structure scheme:
file-upload-mern
βββ .gitignore
βββ public
βββ package.json
βββ src
β βββ App.js
β βββ index.js
β βββ App.css
β βββ index.css
β βββ serverWorker.js
β βββ setupTests.js
βββ server
β βββ package.json
β βββ public
β βββ server.js
β βββ node_modules
β βββ model.js
βββ README.md
To install the backend dependencies:
npm i express
npm i mongoose
npm i multer
To make things clear about the dependencies we installed:
- Express is the API library for nodeJS. π€
- Mongoose is a MongoDB object modeling tool aka nodeJS driver. π
- Multer is a node.js middleware for handling multipart/form-data π±
Now we created the server and the client sides so move to the next point.
2.Write the code π»
First, we will start with the client π¦ π code by heading to /src/App.js
to write the following:
// destination /src/App.js
import React from 'react';
import './App.css';
import axios from 'axios';
class App extends React.Component {
constructor(props) {
super(props);
this.state ={
file: null
};
this.onFormSubmit = this.onFormSubmit.bind(this);
this.onChange = this.onChange.bind(this);
}
onFormSubmit(e){
e.preventDefault();
const formData = new FormData();
formData.append('myfile',this.state.file);
const config = {
headers: {
'content-type': 'multipart/form-data'
}
};
axios.post("http://localhost:5000/upload",formData,config)
.then((response) => {
alert("The file is successfully uploaded");
}).catch((error) => {
});
}
onChange(e) {
this.setState({file:e.target.files});
}
render() {
return (
<form onSubmit={this.onFormSubmit}>
<h1>File Upload</h1>
<input type="file" className="custom-file-input" name="myImage" onChange= {this.onChange} />
{console.log(this.state.file)}
<button className="upload-button" type="submit">Upload to DB</button>
</form>
)
}
}
export default App;
Here we created a form in which the user uploads the file and saves it in the app component state which after submitting will be transferred for the server-side.
Now let head into the ππ side we start with the /server/model.js
var mongoose = require('mongoose');
const fileSchema = new mongoose.Schema({
meta_data:{}
});
mongoose.model("file",fileSchema);
And this is how we built the user schema sounds easy right? π€
Now let's build the server instance which will listen on port 5000 on /server/server.js
// destination /server/server.js
const express = require("express");
const path = require("path");
const multer = require("multer");
const mongoose = require("mongoose");
const app = express();
const PORT = 5000;
require("./model")
const File = mongoose.model("file");
const router = express.Router();
const storage = multer.diskStorage({
destination: "./public/",
filename: function(req, file, cb){
cb(null,"IMAGE-" + Date.now() + path.extname(file.originalname));
}
});
const upload = multer({
storage: storage,
limits:{fileSize: 1000000},
}).single("myfile");
const obj =(req,res) => {
upload(req, res, () => {
console.log("Request ---", req.body);
console.log("Request file ---", req.file);//Here you get file.
const file = new File();
file.meta_data = req.file;
file.save().then(()=>{
res.send({message:"uploaded successfully"})
})
/*Now do where ever you want to do*/
});
}
router.post("/upload", obj);
app.use(router);
app.get("/",(req,res)=>{
return res.send("<p>hello!</p>");
});
mongoose.connect("mongodb://localhost/file-upload",{
useUnifiedTopology: true,
useNewUrlParser: true,
useCreateIndex: true,
}).then(()=>{console.log("DB is connected")})
app.listen(PORT,()=>{
console.log("\u{1F525}\u{1F680} app listen on port",PORT,"\u{1F525}\u{1F680}")
});
Note: path library is a built in NodeJS library to deal with file systems paths operations and dealing with it is more recommended than using RegEx.
3.Running the code π₯ π
First, make sure you are on the root directory of the project via terminal and open two instances of terminals one for the client and second for the server-side of the project:
To run the server
node ./server/server.js
To run the client
npm start
4.Dealing with exporting files to the client side
you need to make the files Directory public just by exporting it as a static asset using Express
const path = require("path");
app.use(express.static(path.join(__dirname, "./public/")));
Conclusion
We discussed simple details in terms of MERN stack development note that you may get a CORS permission error and that happens because the client fetches data from different origin API and fixing it from your browser by allowing all origins of APIs and it has an extension on chrome to handle it properly.
Happy coding.
Top comments (3)
Awesome post! I have a question though.
In your section 4, doesn't this line of code
app.use(express.static(path.join(__dirname, "./public/")))
save the files tofile-upload-mern/server/public
rather thanfile-upload-mern/public
(because you did./public
instead of../public
)? Correct me if I'm wrong please, thanks!Awesome Post For Beginners Highly Recomended.
Awesome Very well exlpained