Client Server Architecture And Basics of Server Side Rendering – Video Tutorial

A Video Tutorial on Server Side Rendering, which describes how exactly client side rendering happens, what are the benefits on Server Side Rendering.

COVID-19 : corona virus epidemic, What one can do to stop it?

The world has hit badly by an invisible tiny virus who is shaking the entire scientific, medical community and challenging to save the lives. Corona virus is not that critical if every one takes some simple precautions but as usual we did mistakes, we neglected and hence paying for it and struggling to escape from it.

Coronavirus is spreading very fast, its an exponential way, person to person through different medium and hence an extreme precautions has to be taken to stop it

Social Distancing:

A simple technique can save our life and save your family, social distancing. Virus can spread through person to person when a infected person cough, spit, sneezes.

It will also spread through some surfaces when an infected person touch any metal surface, cardboard, plastic the virus can survive several hours on the surface and some one else touch the same surface it will transfer to his body.

Look at the below animated view which helps us to understand how social distancing helps us to stop coronavirus spread drastically

Is’t it a simple solution ? but we are failing follow.

“By our most conservative estimate, at least 59% of the infected individuals were out and about, without being tested and potentially infecting others,” says lead study author Prof. Wu Tangchun. Reference

What you should not do ?

Avoid

  1. Parties, functions
  2. Smoking
  3. Avoid taking tablets on your own for fever , cold or headache.
  4. touching your eyes, nose and mouth without washing it properly with soap and water or sanitisers

Social Warriors and NGOs working for Covid-19

There are lot of NGOs, social warriors working for coronavirus epidemic to stop it, lot of awareness programs running for COVID-19, lot of donations are being raised by many organisations to help the needy people in this lockdown situation almost everywhere in the world

Awareness Programs Run by SociallyGood Platform through some of the organisations

Awareness Campaign For Pandemic COVID-19

Awareness program by Sewa USA :

Coronavirus-(COVID-19) Awareness Program

Donate for Covid-19 epidemic

Donation Campaigns run by SociallyGood Platform through some of the organisations

Groceries to daily wage workers in view of outbreak of COVID-19

Support to Fight COVID-19

know more about COVID-19 through SociallyGood Platform

COVID-19 Campaigns on SociallyGood Platform

Let us stop Coronavirus by following the protocol

  1. Lockdown : Be at home, do not go out without the real need
  2. Social Distancing: Keep distance between people
  3. Be wise not panic
  4. Improve your health by doing simple physical work like yoga

COVID-19 Information Center on Facebook

Amazon AWS RDS Failed to Connect to MySQL at with user using MySql Workbench

When trying to connect to Amazon AWS RDS from local machine using MySql Workbench , if you face connection issue like error: Failed to Connect to MySQL at with user Kindly follow below steps

Follow setting up security group : Refer

Then set public access try by following these steps

To change the Publicly Accessible property of the Amazon RDS instance to Yes:

1.    Verify that your VPC has an internet gateway attached to it and that the inbound rules for the security group allow connections.

2.    Open the Amazon RDS console.

3.    Choose Databases from the navigation pane, and then select the DB instance.

4.    Choose Modify.

5.    Under Network & Security, choose Yes for Public accessibility.

6.    Choose Continue.

7.    Choose Modify DB Instance.

DB Import Error due to Triggers :

ERROR 1419 (HY000) at line 918: You do not have the SUPER privilege and binary logging is enabled (you might want to use the less safe log_bin_trust_function_creators variable)

To fix this issue follow steps

  1. Open the RDS web console.
  2. Open the “Parameter Groups” tab.
  3. Create a new Parameter Group. On the dialog, select the MySQL family compatible to your MySQL database version, give it a name and confirm. Select the just created Parameter Group and issue “Edit Parameters”.
  4. Look for the parameter ‘log_bin_trust_function_creators’ and set its value to ’1′.
  5. Save the changes.
  6. Open the “Instances” tab. Expand your MySQL instance and issue the “Instance Action” named “Modify”.
  7. Select the just created Parameter Group and enable “Apply Immediately”
  8. Click on “Continue” and confirm the changes.
  9. Wait for the “Modifying” operation to be completed.
  10. Again, open the “Instances” tab. Expand your MySQL instance and
  11. expand “Instance Action” tab and select “Reboot”.

Factory Design Pattern : A Creational Design Pattern

Factory design patterns provides an interface to create an object. Object creation is not just allocating some memory, in a complex systems the object creation will be a complex process. Setting certain defaults, following certain steps and initialisation of an object many more aspects will be taken care.

Let us take an example to understand it better, when we handle payment gateway transactions, a transaction object is not a simple object, it has much more complexities. It may be handling specific details for Master cards, Visa cards, or it may be related to income tax etc.

There are multiple ways of handling factory design patter, Factory Method pattern and Abstract Factory class are two different approaches.

Factory Method Pattern

Without a design pattern the code looks as fallow

processPayment() {
  switch(paymentGateway) {
    case 'RazorPay': 
       transaction = new RazorPayTransaction();
    break;
    case 'Paypal': 
       transaction = new PaypalTransaction();
    break; 
    case 'Paypal': 
       transaction = new StripeTransaction();
    break; 
  }
}

However the above code looks more cleaner when we apply design pattern the code looks as fallow

createRazorPayTransaction() {
  transaction = new RazorPayTransaction();
  return transaction;
}
createPaypalTransaction() {
  transaction = new PaypalTransaction();
  return transaction;
}
createTransactionFactory(paymentGateway) {
  switch(paymentGateway) {
    case 'RazorPay': 
       createRazorPayTransaction();
    break;
    case 'Paypal': 
       createPaypalTransaction();
    break; 
    case 'Paypal': 
    break; 
  }
}
processPayment() {
  transaction = createTransactionFactory('RazorPay');
}

the above code looks simple and we may not understand the significance of it with a small scale application. However the creational design pattern brings in lot of flexibility, like any complexity with respect to a particular payment gateway will be handled with respective creation method.

for example if I try to elaborate little about one particular method it may looks as below, and this shows how a particular method becomes complex while considering various cases.

createPaypalTransaction() {
  transaction = new PaypalTransaction();
   if (cardType === 'Master') {
     if (country === 'India') {
        if (cardKind === 'Chip') {

        }
      }
    }
  return transaction;
}

Abstract Factory Pattern

Abstract factory pattern simplifies and makes the pattern into more object oriented and enforces future extendability to follow certain strict guidelines by defining interfaces.

Taking an example of developing a super software to handle a robotic machines. There are various types of robotic machines like marine explorer, space explorer and terrain explorer. Its great to have abstract class which enforces and defines basic structure of the factory class. Let us see how does it look

abstract class RoboticMachineFactory {
  createCrawlingRobot();
  createRunningRobot();
  createFlyingRobot();
}

class SpaceExplorerRobotFactory extends RoboticMachineFactory {
  createCrawlingRobot();
  createRunningRobot();
  createFlyingRobot();
}

class TerrainExplorerRobotFactory extends RoboticMachineFactory {
  createCrawlingRobot();
  createRunningRobot();
  createFlyingRobot();
}

class MarineExplorerRobotFactory extends RoboticMachineFactory {
  createCrawlingRobot();
}

Read Classification of Design Patterns

Classification of design patterns : Creational Design Patterns

Before reading further , let us first understand what are design patterns read part 1 of this article

Creational Design Pattern

Object creation is a very common pattern we need to use almost for all complex objects. Object creation is not just allocating a memory and use it, we may need to consider lot of aspects while creating an object.

Creational design pattern solves this problem by following a sophisticated approach, typically creational design patterns will be used for initialising hardware configuration, database connections , Logger object.

Creational design patterns are important to use because they follow SOLID Principles closely. It allows long term flexibility, it allows more decoupling and easily testable.

Let us look into some of the important creational design patterns

Singleton Pattern

We have to identify a scenario where we may need to maintain only one object, even if you try to create an object, the program should not allow to create new object instead it has to return only one object.

Singleton pattern is meaningful where multiple objects doesn’t make any sense. Taking few scenarios here for example , DBConnectionHandler, MQManager for managing Queue connections, these are classical examples where having multiple objects has no meaning.

Example of Singleton Pattern in Javascript

class MQManager {
  constructor() {
    this.amqpProducerConn = null;
    this.amqpConsumerConn = null;
    this.producerChannel = null;
    this.consumerChannel = null;
  }
  createProducerConnection(onConnectSuccess, onConnectFail) {
  }

  createConsumerConnection(onConnectSuccess, onConnectFail) {
  }
  createProducerChannel(connection) {}
  createConsumerChannel() {}
  enqueueJob(queueName, jobDetails) {}
  dequeueJob(queueName, consumerCallback) {}
  closeProducerConnectionOnErr(err) {}
  closeConsumerConnectionOnErr(err) {}
};
module.exports = (() => {
  let instance;
  function getInstance() {
    //TO RESTRICT CREATING SINGLE OBJECT 
    if (instance === undefined) {
      instance = new MQManager();
    }
    return instance;
  }
  // Public API definition
  return {
    getInstance
  };
})();

The above class we can import as follows

const MQManager = require('./mqManager').getInstance();

Read More About Creational Design Pattern

Thanks to refactoring.guru for wonderful images - https://refactoring.guru/design-patterns/

Design Patterns – importance and Examples

What are design pattern?

design patterns are typical solutions to common problems a developer face repeatedly

Design Patterns Classification 

Creational Pattern

These patterns provides various objects creation mechanism. Which increase flexibility and reuse of existing code

Structural Pattern

These patterns explain how to assemble objects and classes into larger structure, while keeping these structures flexible and efficient

Behavioral Pattern

These patterns are concerned with algorithms and assignment or responsibilities between objects

Design patterns are the best practices adapted by experienced software developers, with a vast experience, we developers will find a best way to solve a problem which we face almost every day. The outcome of such solution we usually call it as design patterns

Let us look into some of the design patterns: Read Here

Thanks to refactoring.guru for wonderful images - https://refactoring.guru/design-patterns/

Server Side Rendering (SSR) in React 16 with create-react-app using Material Ui, Redux and Express Libraries

What is Server Side Rendering in React (SSR)?

Server side rendering is normally rendering the requested page at server side of client and sending back the whole html page from server.
i.e: Server-side rendering is all about handling the initial render whenever a request hits the server. For more on basics of SSR please read my first article

Let us see how to implement server side rendering in ReactJs

How to Enable Server Side Rendering using React and ExpressJS

Dependencies:

React: 16.7.0
Material Ui Library from Google: v3.9.3
redux: 4.0.1
redux-thunk: 4.0.1
express: 4.17.1
react-jss: 8.6.1
react-router-dom: 4.3.1
react-document-meta: 2.1.2
axios: 0.19.0
@babel/plugin-proposal-class-properties: 7.4.0
@babel/preset-env: 7.4.3
@babel/register: 7.4.4
babel-preset-es2015: 6.24.1

Step1: Create React Application
Create a react app using command create-react-app
Install the create-react-app globally on your machine with below command.

npm install -g create-react-app

Create a project by create-react-app as follows

create-react-app ssr-react-16


Step2: Install necessary npm packages for React server side rendering applicationInstall the following packages by running the following commands, if necessary please use the same version too.

npm install @material-ui/core
npm install  react-redux
npm install redux
npm install redux-thunk 
npm install express
npm install react-router-dom
npm install react-document-meta
npm install react-jss
npm install axios
npm install @babel/plugin-proposal-class-properties
npm install @babel/preset-env
npm install @babel/register
npm install babel-preset-es2015

Thats it now your app is ready with library setup

Step3: babel configs for react server side app
Create a file called .babelrc in root directory of the app and paste the below code.
Babel is a toolchain that is mainly used to convert ECMAScript 2015+ code into a backwards compatible version of JavaScript in current and older browsers or environments. For more you can read the babel doc.

{
  "presets": ["@babel/env", "@babel/preset-react"],
  "plugins": [
    "@babel/plugin-proposal-class-properties"
  ]
}

Step4:
Create a file called www under bin folder which is in root directory
In this file we will be creating a server for client and allocate a port (I am using 5000 here)
Copy the code below to file just created

const app = require('../src/client/src/ssr/clientServer');
const http = require('http');

const port = normalizePort(process.env.PORT || 5000);
app.set('port', port);

const server = http.createServer(app);
server.listen(port);

function normalizePort(val) {
  const port = parseInt(val, 10);
  if (isNaN(port)) {
    // named pipe
    return val;
  }
  if (port >= 0) {
    // port number
    return port;
  }
  return false;
}

In the above code snippet, we are importing a file called clientServer.js that’s covered in the next step.

Step5: ReactJS server side script to initialise server part of client app.
Create a file clientServer.js
For better folder structure, I have organised as shown in the below screenshot where bin and src will falls under root directory. Paste the below code in clientServer file. clientServer is kind of server side script for our client application, it will initiate expressjs and configurations for server side script of client.

require("@babel/register")({
  presets: ["@babel/preset-env"]
});

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

const requestHandler = require('./requestHandler');
const app = express();

//static files nd build file reference
app.use(express.static(path.join(__dirname, '../../../../build')));
app.use(express.static(path.join(__dirname, 'public')));

app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'public'));

//for server side rendering
app.use(requestHandler);

// catch 404 and forward to error handler
app.use((req, res, next) => {
  const err = new Error('Notdff Found');
  err.status = 404;
  next(err);
});

module.exports = app;


In the above code you can see a requestHandler file, which is very important file and will see there.

Step6: A request handler for ReactJS for server side rendering and invoking (calling) apis at server side
This step is very important for serving the requested page from server side.  All magic of serving the requested page is done in this script.  When client request for a page, it matches the path and determines whether is there any API call for this page and invokes api then updates HTML body for the respective response. Basically here its creating the react component at server side. Hence React component is fully ready with all the data for the first render itself. 
If there is no api call for a particular page, it just serves a just a static page 


Create a file requestHandler.js Copy the below code.

'use strict';
import React from 'react';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import { applyMiddleware, createStore } from 'redux';
import { renderToString } from 'react-dom/server';
import { SheetsRegistry } from 'jss';
import JssProvider from 'react-jss/lib/JssProvider';
import path from 'path'
import fs from 'fs'
import {
  MuiThemeProvider,
  createMuiTheme,
  createGenerateClassName,
} from '@material-ui/core/styles';
import green from '@material-ui/core/colors/green';
import red from '@material-ui/core/colors/red';
import { StaticRouter, matchPath } from 'react-router-dom';
import DocumentMeta from 'react-document-meta';
import reducers from '../reducers/index';
import routes from '../routes';
import routesConfigs from './routesConfig';

const middleware = applyMiddleware(thunk);

function renderView(req, res, state) {

  // Create a theme instance.
  const theme = createMuiTheme({
    palette: {
      primary: green,
      accent: red,
      type: 'light',
    },
  });

  // STEP-1 CREATE A REDUX STORE ON THE SERVER
  const store = createStore(reducers, state, middleware);
  const sheetsRegistry = new SheetsRegistry();
  // Create a sheetsManager instance.
  const sheetsManager = new Map();
  const generateClassName = createGenerateClassName();
  // STEP-2 GET INITIAL STATE FROM THE STORE
  const initialState = JSON.stringify(store.getState()).replace(/<\/script/g, '<\\/script').replace(/<!--/g, '<\\!--');
  // STEP-3 IMPLEMENT REACT-ROUTER ON THE SERVER TO INTERCEPT CLIENT REQUESTs AND DEFINE WHAT TO DO WITH THEM
  const context = {};
  const reactComponent = renderToString(
    <JssProvider registry={sheetsRegistry} generateClassName={generateClassName}>
      <MuiThemeProvider theme={theme} sheetsManager={sheetsManager}>
        <Provider store={store}>
          <StaticRouter
            location={req.url}
            context={context}>
            {routes}
          </StaticRouter>
        </Provider>
      </MuiThemeProvider>
    </JssProvider>
  );
  const css = sheetsRegistry.toString()
  const reactMetaComponent = DocumentMeta.renderToStaticMarkup();
  if (context.url) {
    // can use the `context.status` that
    // we added in RedirectWithStatus
    redirect(context.status, context.url);
  } else {
    //https://crypt.codemancers.com/posts/2016-09-16-react-server-side-rendering/
    //res.status(200).render('index', { reactComponent, reactMetaComponent, initialState });
    fs.readFile(path.resolve('build/index.html'), 'utf8', (err, data) => {
      if (err) {
        return res.status(500).send('An error occurred')
      }
      const replacedData = data.replace(
        '<div id="root"></div>',
        `<div id="root">${reactComponent}</div>
        <style id="jss-server-side">${css}</style>
        <script>
          window.INITIAL_STATE = ${initialState}
        </script>`
      );
      const replacedMetaTagData = replacedData
        .replace(`<meta id="reactMetaTags"/>`,
          `${reactMetaComponent}`);
      res.send(replacedMetaTagData);
    })
  }
}

function handleRender(req, res) {
  const components = routesConfigs
    .filter(route => matchPath(req.path, route)) // filter matching paths
    .map(route => route.component); // check if components have data requirement
  let promiseObj = null;
  if (components.length > 0 && (components[0].fetchData instanceof Function)) {
    /* fetchData is the function defined in each component and make it like class 
       function and it will be called at server side
    */
    components[0]
      .fetchData(req.query)
      .then((response) => {
        renderView(req, res, response);
      })
      .catch((error) => {
        console.log('***--- handleRender error ', error);
        renderView(req, res, {});
      });
  } else {
    renderView(req, res, {});
  }
}

module.exports = handleRender;
  1. By default it will be executing a handleRender function in the above code. In the handleRender function, we read a routesConfig file which is just for keeping track of respective component for each route path.
    import LandingComponent from '../pages/landing/components/LandingComponent';
    import AboutComponent from '../pages/about/components/AboutComponent';
    export default [
      {
        path: "/",
        component: LandingComponent,
        exact: true,
      },
      {
        path: '/about',
        component: AboutComponent,
        exact: true,
      }
    ];
  2. routesConfigs will be used by requestHandler to find dynamically which component needs to be rendered for the request. It also checks for fetchData, if fetchData is defined by the component then requestHandler will invoke it which internally invokes api. Note here is all this is happening at server side not on the browser, component object is created in server and fetchData action will be invoked in server. You can see the brief description of fetchData and how to use this in the component in the next step.
  3. When renderView is called, every times it creates is own redux store and a material ui theme provider, thats why we follow this code(which is also mention in the above code snip). 
    const theme = createMuiTheme({
        palette: {
          primary: green,
          accent: red,
          type: 'light',
        },
      });
    
      // STEP-1 CREATE A REDUX STORE ON THE SERVER
      const store = createStore(reducers, state, middleware);
      const sheetsRegistry = new SheetsRegistry();
      // Create a sheetsManager instance.
      const sheetsManager = new Map();
      const generateClassName = createGenerateClassName();
  4. Next major step is reading a build/index.html file which you will get by running npm run build,
    Here we will be injecting the component created at server side into index.html.

    const replacedData = data.replace(
            '<div id="root"></div>',
            `<div id="root">${reactComponent}</div>
            <style id="jss-server-side">${css}</style>
            <script>
              window.INITIAL_STATE = ${initialState}
            </script>`
     );

    where in index.html of public folder should compulsory has this tag

    <div id="root"></div>
  5. For facebook sharing, when you share the url a image and the title and description of the page has to be displayed, for that all those content has to be in the meta tag inside the head tag, hence we need to replaced meta tag with server generated meta tag code. 
    const replacedMetaTagData = replacedData
      .replace(`<meta id="reactMetaTags"/>`,
      `${reactMetaComponent}`);

    Where in index.html of public folder, meta tag with id is should be unchanged

    <meta id="reactMetaTags"/>
  6. Finally we will serve the requested page with updated meta tags and updated html for the first rendering cycle it self. 
    res.send(replacedMetaTagData);
    
    

    Step 7

  7. Every component should define an action which will be invoked from server side script, however in server side the request handler will be a generic script and we have to dynamically invoke an action at server side, to achieve that, each component has to define an action and assign action function pointer to fetchData, fetchData is a static class variable kept in component. Check the below code snippet , fetchData is defined at AboutComponent class level and a pointer to action is assigned to it.
    AboutComponent.fetchData = fetchAboutData;
    export default connect(mapStateToProps, null)(AboutComponent);
    
  8. You can refer to the fetchAboutData action in the aboutActions.js which will make the API call to some server, for testing iI am using the JSON placeholder get API which will get the list of posts as response, refer the code below 
    import axios from 'axios';
    export const fetchAboutData = (params) => {
      return new Promise((resolve, reject) => {
        const url = 'https://jsonplaceholder.typicode.com/posts';
        axios
          .get(url)
          .then(response => {
            resolve({
              about: {
                posts: response.data
              }
            });
          })
          .catch((error) => {
            console.log('Error while fetching posts from network', error);
            reject(null);
          });
      });
    }
  9. In the positive view, it goes to then block(success block) of the axios api call, you can observe that it’s not direct resolve, its resolving a reducer named about and that contain the posts as one of the key, this set up has to be same in both client side reducer as well in axios call in order to use it component (About Component), Observe the below codes, I have shown the code snips of axios call, aboutReducer to mapStateToProps in AboutComponent,
    In axios call 

    resolve({
        about: {
           posts: response.data
        }
    });

    In about reducer 

    const INITIAL_STATE = {
    posts: []
    };

    In about component

    const mapStateToProps = (state) => {
        return {
           posts:state.about.posts
        };
    }
  10. So in the render method, you can access the posts array like this.props.posts, in the return method of render function i have written one more function which will return the list of posts(only title) and it creates a html code
    getAllPosts = () => {
       const postView = this.props.posts.map(post =>
       <li>{post.title}</li>
     );
     return postView;
    }
  11. Once the html is ready, then its in the success block of the fetchData function in the handleRender function of requestHandler file , then followed by the code it calls the renderView method along with data(html) returned from the component.

Step8 :
Update the package.json start script to point to server side rendering beginning of the file, thats www under bin directory. Now server side rendering is really ready. 

  "scripts": {
    "start": "node bin.www",

Step9 : Running project:

  1. In the requestHandler file we will be pointing to index.html inside the build folder, hence we need to generate a build from react by running the command 
    npm run build
  2. Run the start command of your script by
    npm run start

        OR

    nodemon

        OR 

    node bin/www
  3. Since we are running this project on 5000 port, run http://localhost:5000 which is just a page without requesting for API, you simply see as like below
  4. I have made one more component with calling API and printing the results on screen,  run http://localhost:5000/about . I am using an open dummy api for printing list of posts,
    Ie: https://jsonplaceholder.typicode.com/posts

The output picture is shown below

For View Tutorial on Server Side Rendering using ReactJS, Material-ui and Redux with explanation of each code snippet click here

An Example Source Code is in Github project Link : https://github.com/pilleanand/ssr-react16/tree/master/ssr-react-16

Common issues faced in React SSR Applications 

Posted by:

Anand S,

Software Engineer, Soczen Technologies Pvt Ltd,

Developer: https://sociallygood.com

React Native Android Exception : App Crashes on Launch

How to check exception ? On crash it just shows Close app dialogue box. To check what is the crash open adb logs and check.

<User_home_directory>/Library/android/sdk/platform-tools/adb logcat

This command shows below exception

Exception : java.lang.RuntimeException: Unable to start activity ComponentInfo{/.MainActivity}: java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation

Fix For this :

Remove android:screenOrientation from your application manifest xml

ReactNative Firebase Application : Firebase App named ‘[DEFAULT]’ already exists (app/duplicate-app)

If by change you are getting following exception 

Firebase App named ‘[DEFAULT]’ already exists (app/duplicate-app)

Then do the following fix :

Check whether firebase is already initialised or not before calling firebase.initializeApp

if (!firebase.apps.length) {
  firebase.initializeApp(firebaseConfig);
}

 

How to Increase Upload Speed for GoogleCloudStorage in nodejs

How to Increase Upload Speed for GoogleCloudStorage in nodejs

Uploading Files to GCP : Google Cloud Storage In Nodejs

const Storage = require('@google-cloud/storage');
const config = require('./gcloudConfig');
const Multer = require('multer');

const CLOUD_BUCKET = config.get('CLOUD_BUCKET');

const storage = Storage({
  projectId: config.get('GCLOUD_PROJECT')
});
const bucket = storage.bucket(CLOUD_BUCKET);

// Returns the public, anonymously accessable URL to a given Cloud Storage
// object.
// The object's ACL has to be set to public read.
// [START public_url]
function getPublicUrl (filename) {
  return `https://storage.googleapis.com/${CLOUD_BUCKET}/${filename}`;
}

// Express middleware that will automatically pass uploads to Cloud Storage.
// req.file is processed and will have two new properties:
// * ``cloudStorageObject`` the object name in cloud storage.
// * ``cloudStoragePublicUrl`` the public url to the object.
// [START process]
function sendUploadToGCS (req, res, next) {
  if (!req.files) {
    return next();
  }
  const data = req.body;
  if (req.files.length === 0) {
    next();
  }
  data.accountNumber = '';
    for (let index = 0; index < req.files.length; index++) {
      const gcsname = `${data.accountNumber}/${Date.now()}${req.files[index].originalname}`;
      const file = bucket.file(gcsname);
      const stream = file.createWriteStream({
        metadata: {
          contentType: req.files[index].mimetype
        },
        resumable: false
      });
      stream.on('error', (err) => {
        req.files[index].cloudStorageError = err;
        next(err);
      });
    //  console.log(' upload in progress for file ', index);
      stream.on('finish', () => {
        req.files[index].cloudStorageObject = gcsname;
        file.makePublic().then(() => {
          req.files[index].cloudStoragePublicUrl = getPublicUrl(gcsname);
          console.log(' upload completed, public url is ', req.files[index].cloudStoragePublicUrl,
                     ' index ', index, ' total count ', req.files.length);
          if (index === (req.files.length - 1)) {
            next();
          }
        });
      });
      stream.end(req.files[index].buffer);
    }
}
// [END process]

// Multer handles parsing multipart/form-data requests.
// This instance is configured to store images in memory.
// This makes it straightforward to upload to Cloud Storage.
// [START multer]

const multer = Multer({
  storage: Multer.MemoryStorage,
  limits: {
    fileSize: 5 * 1024 * 1024 // no larger than 5mb
  }
});
// [END multer]

module.exports = {
  getPublicUrl,
  sendUploadToGCS,
  multer
};

 

The issue is the upload speed is very slow, finding a way to upload faster to google cloud storage