Tuesday, June 18, 2019

Redux Saga - what if need to run multiple tasks in parallel

The yield statement is great for representing asynchronous control flow in a linear style, but we also need to do things in parallel. We can't write:

// wrong, effects will be executed in sequence
const users = yield call(fetch, '/users')
const repos = yield call(fetch, '/repos')

Because the 2nd effect will not get executed until the first call resolves. Instead we have to write:

import { all, call } from 'redux-saga/effects'

// correct, effects will get executed in parallel
const [users, repos] = yield all([
  call(fetch, '/users'),
  call(fetch, '/repos')
])

When we yield an array of effects, the generator is blocked until all the effects are resolved or as soon as one is rejected (just like how Promise.all behaves).

To note, the call inside the array need not be covered in yield call.


References:
https://redux-saga.js.org/docs/advanced/RunningTasksInParallel.html

Node Express, how to get the user agent and other requester details

The package express-useragent gives much of the details

npm install express-useragent

The usage is like below

var express = require('express');
var app = express();
var useragent = require('express-useragent');

app.use(useragent.express());
app.get('/', function(req, res){
    res.send(req.useragent);

});
app.listen(3000);


The result is like this below, pretty useful. In this sample, the geoIP is coming as empty however.


{ isAuthoritative: true,
  isMobile: false,
  isTablet: false,
  isiPad: false,
  isiPod: false,
  isiPhone: false,
  isAndroid: false,
  isBlackberry: false,
  isOpera: false,
  isIE: false,
  isEdge: false,
  isIECompatibilityMode: false,
  isSafari: false,
  isFirefox: false,
  isWebkit: false,
  isChrome: true,
  isKonqueror: false,
  isOmniWeb: false,
  isSeaMonkey: false,
  isFlock: false,
  isAmaya: false,
  isPhantomJS: false,
  isEpiphany: false,
  isDesktop: true,
  isWindows: false,
  isLinux: false,
  isLinux64: false,
  isMac: true,
  isChromeOS: false,
  isBada: false,
  isSamsung: false,
  isRaspberry: false,
  isBot: false,
  isCurl: false,
  isAndroidTablet: false,
  isWinJs: false,
  isKindleFire: false,
  isSilk: false,
  isCaptive: false,
  isSmartTV: false,
  isUC: false,
  isFacebook: false,
  isAlamoFire: false,
  silkAccelerated: false,
  browser: 'Chrome',
  version: '74.0.3729.169',
  os: 'macOS High Sierra',
  platform: 'Apple Mac',
  geoIp: {},
  source:
   'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36' }

References:
https://www.npmjs.com/package/express-useragent



Express Node JS, how do we get the requesting user's IP ?



The request-ip package seems to be very effective in this regard
npm install request-ip --save

Below is the usage for this

const requestIp = require('request-ip');
app.use(requestIp.mw())

app.use(function(req, res) {
    const ip = req.clientIp;
    res.end(ip);
});

It looks for specific headers in the request and falls back to some defaults if they do not exist.

The user ip is determined by the following order:

    X-Client-IP
    X-Forwarded-For (Header may return multiple IP addresses in the format: "client IP, proxy 1 IP, proxy 2 IP", so we take the the first one.)
    CF-Connecting-IP (Cloudflare)
    Fastly-Client-Ip (Fastly CDN and Firebase hosting header when forwarded to a cloud function)
    True-Client-Ip (Akamai and Cloudflare)
    X-Real-IP (Nginx proxy/FastCGI)
    X-Cluster-Client-IP (Rackspace LB, Riverbed Stingray)
    X-Forwarded, Forwarded-For and Forwarded (Variations of #2)
    req.connection.remoteAddress
    req.socket.remoteAddress
    req.connection.socket.remoteAddress
    req.info.remoteAddress

If an IP address cannot be found, it will return null.

References:
https://www.npmjs.com/package/request-ip


Express, node JS. How to get the local IP where the app runs

Below are the properties from the Connection where we get the IP address and the port info.

req.connection.localAddress
req.connection.localPort

However this was not giving the public


References:
https://stackoverflow.com/questions/38423930/how-to-retrieve-client-and-server-ip-address-and-port-number-in-node-js


Node Express, serving the static files

To serve static files, below is what to be done, pretty simple.

Define the folder which is to be used for serving the files from

app.use(express.static('public'))

Now, you can load the files that are in the public directory:

http://localhost:3000/images/kitten.jpg
http://localhost:3000/css/style.css
http://localhost:3000/js/app.js
http://localhost:3000/images/bg.png
http://localhost:3000/hello.html

To use multiple static assets directories, call the express.static middleware function multiple times:

app.use(express.static('public'))
app.use(express.static('files'))

To create a virtual path prefix (where the path does not actually exist in the file system) for files that are served by the express.static function, specify a mount path for the static directory, as shown below:

app.use('/static', express.static('public'))

http://localhost:3000/static/images/kitten.jpg
http://localhost:3000/static/css/style.css

http://localhost:3000/static/js/app.js
http://localhost:3000/static/images/bg.png
http://localhost:3000/static/hello.html


References:
https://expressjs.com/en/starter/static-files.html

Express, Node - How to send the files in the server response

Below is how to do it

app.get('/', function(req, res) {
    res.sendFile('index.html', { root: __dirname });
});

__dirname is a keyword which will help to get the directory name of the app that is currently running.
This way the file can be streamed as well.


References:
https://stackoverflow.com/questions/26079611/node-js-typeerror-path-must-be-absolute-or-specify-root-to-res-sendfile-failed


How to Enable CORS in node JS app on the server side

Simple thing will be to enable Core middleware, like the below

const cors = require('cors')

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

app.get('/', cors(), (request, response) => {
  response.send('OK, am up!')
})


References:
https://flaviocopes.com/express-cors/

Saturday, June 8, 2019

Material UI - Theme provider

Lets say we create an app with

It seems that you will need a couple of material-ui components:

An AppBar
2 Buttons

And the app.js look like below

import AppBar from 'material-ui/AppBar';
import Button from 'material-ui/Button';
import React, { PureComponent } from 'react';

export default class Header extends PureComponent {
  render() {
    return (
     
       

         
           
Button 1

         
         
           
Button 2

         
       
     
    );
  }
}

To customise the material theme, below to be done

First, create a file theme.js in your app folder. We would like to give some pinkful color to our app bar:

import { createMuiTheme } from 'material-ui/styles';
import indigo from 'material-ui/colors/indigo';
import pink from 'material-ui/colors/pink';
import red from 'material-ui/colors/red';

export default createMuiTheme({
  palette: {
    primary: pink,
    secondary: indigo // Indigo is probably a good match with pink
  }
});

Then, we have to provide the theme above to your app. In order to this, we will encapsulate our app in a MuiThemeProvider.

import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import theme from 'xx/xx/theme';

Encapsulate the app in it and pass your theme file in props
export default class Header extends PureComponent {
  render() {
    return (
     
       
         

           
             
Button 1

           
           
             
Button 2

           
         
       
     
    );
  }
}

One step further, what if we want to customise all instances of a component type?

To customize a specific kind of material UI components within our app, we will add an overrides property to our theme.js file as described below. You will need to provide to your theme object, the name and class of the component you want to customize. This will be found in the material-ui API documentation.


import { createMuiTheme } from 'material-ui/styles';
import indigo from 'material-ui/colors/indigo';
import pink from 'material-ui/colors/pink';
import red from 'material-ui/colors/red';

export default createMuiTheme({
  palette: {
    primary: pink,
    secondary: indigo
  },
  overrides: {
    MuiButton: {
      root: {
        color: 'white',
        '&:hover': {
          backgroundColor: 'purple'
        }
      }
    }
  }
});

And what if we need to override for a specific instance of a component ?

MaterialUI theme will not be of any help here anymore, and our best chance is to inline style our left Button.

export default class Header extends PureComponent {
  render() {
    return (
     
       
         

           
             
Button 1

           
           
             
Button 2

           
         
       
     
    );
  }
}


https://blog.bam.tech/developper-news/get-the-best-of-your-react-app-design-by-using-material-ui-theme