Simple File or Image Upload With Node Server and React Js

We are making a simple file upload with React Js and will use Node Js in the backend to handle the uploaded file. We are going to use the CRA (Create React App) for the quick setup and the Ant Design for the UI.

Our first step is to set up the front-end to handle to make a file uploader. Let’s start with CRA.

npx create-react-app simple-file-upload

The next step is to navigate to the simple-file-upload directory and install the design dependency i.e. Ant Design and styled-component.

npm i antd styled-components

The next step is to make a UploadContainer.js file at /src/containers directory. You can not find the containers directory by default. We have to create it manually to organize the files.

import React from 'react'
import styled from 'styled-components'
import Uploader from './../components/Uploader'

const Container = styled.div`
    width: 80%;
    background: #fff;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    vertical-align: middle;
    margin: 0 auto;
`

const UploadContainer = () => {
    return (
        <Container>
            <Uploader />
        </Container>
    )
}

export default UploadContainer;

We do not require to handle any state in the UploadContainer file, so we have exported it as a function ( Stateless component ). The next step is to create a component at /src/components with the name Uploader.js.

import React from 'react'
import styled from 'styled-components'
import { Upload, Icon, message } from 'antd';
const { Dragger } = Upload;

const Container = styled.div`
    width: 100%;
    height: 100%;
`

const Uploader = () => {
    ....
}

export default Uploader;

Here we have created the stateless component because we don’t have to handle any state for this file uploader. The next step is to apply the Dragger.

const Uploader = () => {

    return (
        <Container>
            <Dragger {...props}>
                <div style={{width: '100%'}}>
                    <p className="ant-upload-drag-icon">
                        <Icon type="inbox" />
                    </p>
                    <p className="ant-upload-text">Click or drag file to this area to upload</p>
                </div>
            </Dragger>
        </Container>
    )
}

Now the next step is to define some properties to handle this Dragger uploader. We have to define the attribute name that holds the image, the action URL to handle the uploaded file etc.

const Uploader = () => {

    const props = {
        name: 'photo',
        multiple: false,
        action: 'http://localhost:5000/photo',
        onChange(info) {
            const { status } = info.file;
            if (status !== 'uploading') {
                console.log(info.file, info.fileList);
            }

            if (status === 'done') {
                message.success(`${info.file.name} file uploaded successfully.`);
            } else if (status === 'error') {
                message.error(`${info.file.name} file upload failed.`);
            }
        },
    };

    return (
        <Container>
            <Dragger {...props}>
                ....
            </Dragger>
        </Container>
    )
}

Please follow the documentation link to know more about the acceptable properties for Dragger. The main thing to notice here is the action property.

action: 'http://localhost:5000/photo',

This is the URL of our Node Js server that we will be going to create in after finishing the front-end.

Now the only step remaining is to attach the UploadContainer to the App.js file.

import React from 'react';
import UploadContainer from './containers/UploadContainer'
import "antd/dist/antd.css";
import './App.css';

const App = () => {
    return (
        <div className="App">
            <UploadContainer />
        </div>
    );
}

export default App;

Set up Node Js Server

We have successfully created the front-end for the file uploader. Now its time to quickly set up the Node Js server. First, create a directory with the name server at the document root i.e. simple-file-upload. Now move to the created server directory with the cd server command and install the required packages.

Required Packages for Node Server

  • express
  • cors
  • multer
  • nodemon

We are using express to quickly built the end-points and set up the Node server. Cors to handle the Cross-Origin requests. The Multer for to handle the uploaded file from multipart-form data and the nodemon to automatically restart the node application when the file changes detected.

npm i express cors multer nodemon

Add nodemon to the /server/package.json file to automatically restart the application.

{
  "name": "server",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "start": "nodemon app.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "cors": "^2.8.5",
    "express": "^4.17.1",
    "multer": "^1.4.2",
    "nodemon": "^1.19.3"
  }
}

The next step is to create a file app.js or you can create server.js whatever you prefer. This file will be the starter for the node server. Now open the created file and set up the node server.

const express = require('express');
const cors = require('cors')
const app = express();

app.use(cors());

app.listen(5000);

Now we have created the node server and if you like to run the node server then just run the following command from the same server directory that holds all the files for our node server.

node app.js

The above command started our node server but we can not access through the browser. Because we haven’t defined any route yet.

The next step is to define the route. Create a file at /server/routes with the name web.js. Open the file and define a route that we have used at our frontend.

const path = require('path');
const express = require('express');
const router = express.Router();

// Upload Image
router.post("/photo", (req, res, next) => {
    return res.json({
        image: null
    });
});

module.exports = router;

As the above codes described, we have created a post route that only accepts the POST request. Next, we have to use multer here to handle the file uploads and define the store to save the uploaded file.

const path = require('path');
const express = require('express');
const multer  = require('multer')


const storage = multer.diskStorage({
    destination: function (req, file, cb) {
        cb(null, 'assets/uploads')
    },
    filename: function (req, file, cb) {
        // You could rename the file name
        // cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname))

        // You could use the original name
        cb(null, file.originalname)
    }
});

var upload = multer({storage: storage})

const router = express.Router();

.......

As you see, we have defined the disk storage with destination and filename options. The destination function is responsible for the directory and the filename function is responsible for the filename name used to store the file.

Make sure the defined directory is exists and the path is correct.

The next step is to inject the upload to the defined route and return the file with the storage path.

....
const router = express.Router();

// Upload Image
router.post("/photo", upload.single('photo'), (req, res, next) => {
    return res.json({
        image: req.file.path
    });
});

Now attach this web.js route to the node server app.js file.

const express = require('express');
const cors = require('cors')
const app = express();
const webRoutes = require('./routes/web');

app.use(cors());

// Front Routes handling
app.use(webRoutes);

app.listen(5000);