Translate

Tuesday, August 27, 2019

Microservices Interview Questions and Answers for Beginners and Experienced

Source: https://www.janbasktraining.com/blog/microservices-interview-questions/

Q1). What are the advantages of Microservices Architecture?

Here are a few advantages of Microservices architecture that you should know.
  • All microservices can be developed independently.
  • Once they are developed, they are deployed independently for a particular application.
  • Even if one of the services will not work, the system still continues to work.
  • Different technologies or languages in Microservices can be used to build multiple services of an application.
  • You can scale individual component one by one instead of scaling all components together.

Q2). How will you define the concept of Microservices?

In an architectural style, Microservices structures an application as a collection of small autonomous services that are modeled around a business domain. They usually start with a small block and can be arranged together to build a larger application. These cells then will be arranged in a pattern that will structure a stronger section of beehive later.
Each cell is connected but independent in its own way that can be scaled based on the requirements. It means damage to one cell will not affect the productivity of another cell. In this way, damaged cell can be reconstructed quickly and an application would behave the same way.

Q3). What are the Features of Microservices?

  • Services within a system can be largely decoupled. So, an application as a whole can be built quickly.
  • Each microservice is considered as an individual component and it can be replaced or reconstructed quickly.
  • Microservices are quite easier and simpler. They usually focus on one capability at a particular time.
  • Developers and teams can work independently, thus increasing the speed.
  • It allows the frequent release of a software application through systematic operations.
  • Microservices consider applications as a product for which they are responsible.
  • They are usually able to identify the right tool for the right job. It means there is no standardized pattern and you may choose the best useful tools as per your convenience.
  • Microservices follow the agile development and it can be developed quickly and discarded again.

Q4). When designing Microservices, what are best practices to follow?

Here are the best practices that every developer should follow when designing Microservices.
  • The data store should always be kept separated from each Microservice.
  • The code should be arranged at a similar level of maturity.
  • A separate build should be designed for each Microservice.
  • Each build should be deployed into containers.
  • The server should always be treated as stateless.

Q5). Explain the major components of a Microservices Architecture.

The major components of a Microservice architecture are given as below.

  • Clients: Different users will send requests from different devices.
  • Identity Providers: They will authenticate user details and offer service tokens to users.
  • Static Content: It helps in storing all the content of a system for longer time.
  • API Gateway: This gateway handles multiple requests together.
  • Management: it will balance the services over nodes and identifies failures as well.
  • CDNs: The content delivery network is a distributed network of proxy servers and their respective data centers.
  • Service Discovery: it will find the route how different Microservices communicate together.
  • Remote Services: it will enable the remote access to information stored on a network or other IT devices.

Q6). List down the pros and cons of a Microservice Architecture.

What are the pros?
  • It has the freedom to use different technologies.
  • Each Microservices will focus on single capability only.
  • It supports individual deployable units.
  • It allows frequent releases of a software application.
  • It gives maximum security to each of the services.
  • It is possible developing and deploying multiple services together.
What are the cons?
  • The troubleshooting challenges will increase.
  • It will increase delays due to remote calls.
  • The configuration options are not possible to manage.
  • It is difficult to maintain transaction safety.
  • Data cannot be tracked across different boundaries.
  • There is a tough coding between multiple microservices.

Q7). Are there any challenges faced during Implementation of Microservices Architecture?

They are tough automating components as they are very small. For each component, you have to follow stages – Build, Deploy, and Monitor. When a large number of components are deployed together, they become difficult to be deployed and maintained.
Here, it needs more perceptibility around components. It is tough maintaining configuration sometimes across multiple environments and also to identify bugs in each of the services. So, you have to be extra careful here.

Q8). How SOA, monolithic, and Microservices Architectures are different from each other?

  • SOA (Service-Oriented Architecture): This is a wide collection of services that could communicate together.
  • Monolithic: This is highly similar to the big container where all software components of an application are assembled and packed together.
  • Microservices: Microservices can be defined as the architectural style that structures an application as a collection of small autonomous services that are modeled around a business domain.

Q9). How will you define the domain driven design?

A domain-driven design focused more on core domain logic. It helps to identify complex designs on models of the domain. It can constantly collaborate with domain experts to improve the domain model and resolve all issues related to the domain.

Q10). Why there is a need for DDD (Domain Driven Design)?

A domain-driven design is necessary for the following reasons.
  • Maintainability and Testability
  • Reducing Complexity
  • Knowledge-Rich Designs
  • More focused on context
  • Following the ubiquitous language
  • Mapping with domains.
  • Bringing business and domains together.

Microservices Interview Questions and Answers for Experienced

Q11). How can you define the Ubiquitous Language for Microservices?

This is a specific language that can be used by developers or users to define every domain in detail. This is a crystal-clear language that brings all the team members together on the same page and translated so well that a machine can understand quickly.

Q12). How will you define coupling?

The measure of the strength of dependencies among components is said to be coupling. For a good design, cohesion is high and coupling is low.

Q13). What is the meaning of Cohesion in Microservices?

The degree to which how components bind together within a module is called the Cohesion.

Q14). What is the meaning of Spring Boot?

Spring becomes more and more complex when new features are added to an application. When you have to start a new Spring project, you should add paths and dependencies. Also, you have to define the configuration for servers, and define everything from scratch.
Spring Boot is the solution to this problem. With this feature, you can always avoid the boilerplate code and tough configurations. Basically, Spring is like an ingredient here that is needed to make a cake and Spring Boot is the complete cake in your hand.

Q15). What are RESTful web services and explain their benefits too?

RESTful web services or Representation State Transfer web services can be defined as the architectural style helping computer systems to communicate together over the internet. The REST web services make it easy to understand and implement the Microservices.
Microservices can always be implemented with or without REST APIs. For easy implementation, this is always recommended using REST APIs.

Q16). What is Spring Cloud?

This is a tool for the developers helping to quickly build some of the common patterns within distributed systems.

Q17). How will define an actuator in Spring Boot?

It helps in checking the current state of an application within the production environment. With the help of actuators, it is always easy monitoring matrices and checking your application.

Q18). What problems can be solved with the Spring Cloud?

Here are a few issues that can be resolved with the Spring Cloud.
  • It reduces the complexity associated with distributed systems.
  • It is able to handle service delivery.
  • It can solve redundancy issues too.
  • It helps in load balancing.
  • It reduces performance issues.

Q19). What are different types of tests for Microservices?

These are – Technology-facing tests, Exploratory Testing, and Acceptable Testing.

Q20). How will you define the Distributed Transactions?

This is the situation where a single event results in the mutation of two or more sources of separate data that cannot be committed automatically.

Thursday, May 30, 2019

Create a Simple Shopping Cart Using React and Node

Source: https://dzone.com/articles/create-a-simple-shopping-cart-using-react-and-node
by George Anderson
Web development has never been more exciting than now, with the introduction of new technologies and techniques, thanks to the dynamism and evolution of JavaScript. Now a web application can be configured using only JavaScript. This is made possible through the introduction of Node.js, which can be used on the server-side to manage data, and also the creation of several JavaScript frameworks, such as React.js, Angular, and Vue.js, which manage and control the client-side of the application.
In this article, we will be learning how to build a simple shopping cart app, using React.js as the front-end framework, and a backend server built using Node.js and Express.js.
Below is a preview of what we will be building:

Configuring the Development Environment

For this tutorial, I will be using the Eclipse IDE with the CodeMix plugin installed.

Creating a React Project Using CodeMix

We can now create our application using the CodeMix Project Wizard. We'll be using the latest version of all the tech libraries and stacks as at the time of this writing. To create a new React Project Navigate to File> New > Project > CodeMix > React Project.
Now click Next and enter your project name on the next screen. Finally, click Finish to continue with the React project creation.
Let's install some modules which we will need in building the application. Open the integrated Terminal+ in CodeMix 2.0. Alternatively, it can be opened using the command Ctrl + Shift + P, as shown below, to run the following command:
npm i -S express react-route-dom axios jsonwebtoken cors body-parser boostrap
These are the technologies we will be using for our app:
  • Cors: it provides a middleware to handle cross-origin resource sharing.
  • Axios: it is a Promise-based HTTP client used to communicate with the Node server.
  • Express: it is a Node.js module that simplifies the creation of a node server.
  • JSON Web Token (JWT): it is a compact and self-contained way for securely transmitting information between parties as a JSON object.
  • React Router: it is used in handling the application routing.
  • Bootstrap: it is a CSS framework.

Setting Up the Backend Server

In this section, we will be building the Application Programming Interface (API) for the application. First, we create an api folder in the root folder of our project. This folder will contain the express backend. Next, we proceed with creating a server.js file which will contain the server configuration.
'use strict';
const express = require('express');
const app = express();
const jwt = require('jsonwebtoken');
const cors = require('cors');
const bodyParser = require('body-parser');
const data = require('./data');
const middleware = require('./middleware');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cors());
app.get('/api/products', (req, res) => { //lists all  available products
  return res.json(data.products);
});
app.post('/api/products', (req, res) => { //generates the list of products in the cart
  let products = [], id = null;
  let cart = JSON.parse(req.body.cart);
  if (!cart) return res.json(products)
  for (var i = 0; i < data.products.length; i++) {
    id = data.products[i].id.toString();
    if (cart.hasOwnProperty(id)) {
      data.products[i].qty = cart[id]
      products.push(data.products[i]);
    }
  }
  return res.json(products);
});
app.post('/api/auth', (req,res) => { //signs in user
  let user = data.users.filter((user) => {
    return user.name == req.body.name && user.password == req.body.password;
  });
  if (user.length){
    // create a token using user name and password vaild for 2 hours
    let token_payload = {name: user[0].name, password: user[0].password};
    let token = jwt.sign(token_payload, "jwt_secret_password", { expiresIn: '2h' });
    let response = { message: 'Token Created, Authentication Successful!', 
                     token: token };
      // return the information including token as JSON
      return res.status(200).json(response);
  } else {
      return res.status("401").json("Authentication failed. admin not found.");
  }
});
app.get('/api/pay', middleware, (req, res) => { //checkout route for signed in users
  return res.json("Payment Successful!");
});
const PORT = 5000;
app.listen(PORT);
console.log('api runnging on port ' + PORT + ': ');
This server.js file contains four routes, the first of which returns an array of products loaded from the data.js module (which also contains an array of valid users).
const products = [
  {
    id: 01,
    name: 'Cool Vex',
    available_quantity: 5,
    price: 450,
    description: 'Lorem ipsum dolor sit amet, iusto appellantur vix te, nam affert feugait menandri eu. Magna simul ad est. Nostrum neglegentur ius at, at pertinax repudiare vel. Vim an adolescens quaerendum.'
  },
  {
The second route is a post route that accepts a cart string, parses it, and generates the list products on the cart, along with their quantities.
The third is the login route that authenticates the user, i.e. verifies the user is valid (registered). It generates a JSON web token that expires in two hours. The generated token is used to bypass the login middleware (which we will create next).
The fourth route is a get route guarded by a middleware. This route requires the request to be authenticated, i.e. it provides a valid token. This middleware checks that the token was generated using a valid user. It also checks to confirm that the token is not expired. To create the middleware, we make a middleware.js file in the api folder, as shown below:
const jwt = require('jsonwebtoken');
const JWT_SECRET = "jwt_secret_password";
module.exports = (req, res, next) => {
    // check header or url parameters or post parameters for token
    var token = req.body['x-access-token'] || req.query['x-access-token'] || req.headers['x-access-token'];
    // decode token
    if (token) {
        // verifies secret and checks exp
        jwt.verify(token, JWT_SECRET, function(err, decoded) {
            if (err) {
                return res.status(403).send({ 
                    success: false, 
                    message: 'Failed to authenticate token.' 
                });
            } else {
                // if everything is good, save to request for use in other routes
                req.decoded = decoded;
                next();
            }
        });
    } else {
        // if there is no token, return an error
        return res.status(401).send({
            success: false,
            message: 'No token provided.'
        });
    }
};
If a request is made to a guarded route without a valid token, the middleware intercepts the request and returns a 401 (Unauthorized) error.
Next, we include a script in the scripts object in the package.json file, which we will use to start up the application API:
{
  "name": "shopping-cart",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "axios": "^0.18.0",
    "body-parser": "^1.18.3",
    "cors": "^2.8.5",
    "express": "^4.16.4",
    "jsonwebtoken": "^8.4.0",
    "react": "^16.7.0",
    "react-dom": "^16.7.0",
    "react-router-dom": "^4.3.1",
    "react-scripts": "2.1.3"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "api": "node api/server.js"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ]
}
With that, we have completed the development of the API server, which we can then run using the command below in the integrated terminal:
npm run api

Setting Up the Front-End

Now that we have the application's backend running, let's begin developing its front-end.
From the root of the project, we will open a new terminal using the Ctrl + Shift + P command. In the terminal, we will run the following command to start the React application:
npm start
This application will be styled using Bootstrap. This can be achieved in several ways, one of which is to install the React bootstrap module, as we had previously done. We then import it into the root React component, i.e. the index.js, as shown below:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';
import 'bootstrap/dist/css/bootstrap.min.css';
ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();
Let’s create a repository.js file which will contain all the interactions with the backend server, using the axios module.
import axios from 'axios';
const BASE_URL = 'http://localhost:5000';
export function getProducts() {
        return axios.get(`${BASE_URL}/api/products`)
                .then(response => response.data);
}
export function getCartProducts(cart) {
        return axios.post(`${BASE_URL}/api/products`, {cart})
                .then(response => response.data);
}
export function login (data) {
  return axios.post(`${BASE_URL}/api/auth`, 
                    { name: data.name, password: data.password })
    .then(response => {
       localStorage.setItem('x-access-token', response.data.token);
       localStorage.setItem('x-access-token-expiration', 
                            Date.now() + 2 * 60 * 60 * 1000);
      return response.data})
    .catch(err => Promise.reject('Authentication Failed!'));
}
export function pay (data) {
        return axios.get(`${BASE_URL}/api/pay`, 
            { params: { 'x-access-token': localStorage.getItem('x-access-token')} })
                .then(response => response.data)
                .catch(err => Promise.reject(err));
}
export function isAuthenticated(){
        return localStorage.getItem('x-access-token') && localStorage.getItem('x-access-token-expiration') > Date.now()
}
The getProducts method fetches all the available products from the server. The getCartProducts fetches all the products in the cart by passing the cart string to the server. This cart string is parsed to an object, with its keys as the product ID, and the values as the requested quantities. The login method submits the user credentials to the backend server. It also stores the generated token along with the token's expiration time in the local storage of the browser upon a successful request. The pay method is only available for authenticated users because it requires a valid access token. The final method is used to verify that the user is authenticated by checking to see if there is a valid token that is not expired.

Creating Components

Let's proceed with creating a src/components folder which will contain the application's components.
In the application, we will be creating six other components which include Login, ProductItem, ProductList, CartItem, Cart, and Checkout, in addition to the root App component.
The JSX editing capabilities in CodeMix make it easy to work with React code. Just take a look at the GIFs below to see how you can take advantage of the editing capabilities in CodeMix, as you work your way through these components.
First, let's create the Login component.
   import React from 'react';
    import { login } from '../repository';
    export default class Login extends React.Component{
      constructor() {
        super();
        this.state = { name: '', password: '' };
      }
      handleInputChange = (event) => 
                this.setState({[event.target.name]: event.target.value})
      submitLogin = (event) => {
        event.preventDefault();
        login(this.state)
          .then(token => window.location = '/').catch(err => console.log(err));
      }
      render() {
         return (
          <div className="container">
          <hr/>
            <div className="col-sm-8 col-sm-offset-2">
              <div className="panel panel-primary">
                <div className="panel-heading"><h3>Log in </h3></div>
                <div className="panel-body">
                  <form onSubmit={this.submitLogin}>
                    <div className="form-group">
                      <label>Name:</label>
                      <input type="text" className="form-control" 
                          name="name" onChange={this.handleInputChange}/>
                    </div>
                    <div className="form-group">
                      <label>Password:</label>
                      <input type="password" className="form-control" 
                          name="password" onChange={this.handleInputChange}/>
                    </div>
                    <button type="submit" className="btn btn-success">Submit</button>
                  </form>
                </div>
              </div>
            </div>
          </div>
        );
      }
    }
This component gets the username and password, passes it on to the backend server when the form is submitted, using the login method from the repository module, and redirects the user to the home URL upon a successful request.
Let's create the ProductItem component, which we will be used to render each product on the product list.
  import React from 'react';
    export default class ProductItem extends React.Component {
      constructor(props) {
        super(props);
        this.state = {quantity: 1}
      }
      handleInputChange = event => 
          this.setState({[event.target.name]: event.target.value})
      addToCart = () => {
        let cart = localStorage.getItem('cart') 
                      ? JSON.parse(localStorage.getItem('cart')) : {};
        let id = this.props.product.id.toString();
        cart[id] = (cart[id] ? cart[id]: 0);
        let qty = cart[id] + parseInt(this.state.quantity);
        if (this.props.product.available_quantity < qty) {
          cart[id] = this.props.product.available_quantity; 
        } else {
          cart[id] = qty
        }
        localStorage.setItem('cart', JSON.stringify(cart));
      }
      render(){
        const { product } = this.props;
        return (
         <div className="card" style={{ marginBottom: "10px"}}>
           <div className="card-body">
             <h4 className="card-title">{product.name}</h4>
             <p className="card-text">{product.description}</p>
             <h5 className="card-text"><small>price: </small>${product.price}</h5>
             <span className="card-text">
               <small>Available Quantity: </small>{product.available_quantity}
             </span>
             { product.available_quantity > 0 ?
              <div>
                 <button className="btn btn-sm btn-warning float-right" 
                    onClick={this.addToCart}>Add to cart</button>
                 <input type="number" value={this.state.quantity} name="quantity" 
                    onChange={this.handleInputChange} className="float-right" 
                    style={{ width: "60px", marginRight: "10px", borderRadius: "3px"}}/>
              </div> : 
              <p className="text-danger"> product is out of stock </p>
            }
          </div>
        </div>
       )
     }
    }
The addToCart method adds the given product to the cart which is an object stored in localStorage as a string using the JSON.stringify method. This method converts the string back to object using the JSON.parse method or creates a new object if no item is found. The product is then added, and the cart is saved back in localStorage.
Let's create the Product List which uses the ProductItem component to render the list of products.
 import React from 'react';
    import ProductItem from './ProductItem';
    import { getProducts } from '../repository';
    import { Link } from 'react-router-dom';
    export default class ProductList extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
        products: []
        }
      }
      componentDidMount() {
        getProducts().then((products) =>this.setState({ products }));
      }
      render() {
        const { products } =  this.state;
        return (
          <div className=" container">
            <h3 className="card-title">List of Available Products</h3><hr/>
          {products.map((product, index) => <ProductItem product={product} key={index}/>)}
            <hr/>
            <Link to="/checkout">
              <button className="btn btn-success float-right">Checkout</button>
            </Link>
            <Link to="/cart">
              <button className="btn btn-primary float-right" 
                  style={{  marginRight: "10px" }}>View Cart</button>
            </Link><br/><br/><br/>
          </div>
        );
      }
    }
This component fetches the array of available products using the getProducts from the repository module in the componentDidMount lifecycle provided by React.
Let's create the CartItem component which will be used to render each product on the cart.
    import React from 'react';
    export default class CartItem extends React.Component {
      constructor(props) {
        super(props);
        this.state = {quantity: 1}
      }
      render(){
        const { product } = this.props;
        return (
          <div className="card" style={{ marginBottom: "10px"}}>
            <div className="card-body">
              <h4 className="card-title">{product.name}</h4>
              <h5 className="card-text"><small>price: </small>${product.price}</h5>
              <span className="card-text text-success">
                  <small>Quantity: </small>{product.qty}</span>
              <button className="btn btn-sm btn-warning float-right" 
                  onClick={() => this.props.remove(product)}>Remove from cart</button>
            </div>
          </div>
         )
      }
    }
This component uses the remove method provided as a prop to remove the item from the cart completely. The remove method is provided by the parent Cart component which we will be creating next.
  import React from 'react';
    import { Link } from 'react-router-dom';
    import { getCartProducts } from '../repository';
    import CartItem from './CartItem';
    export default class Cart extends React.Component {
      constructor(props) {
        super(props);
        this.state = { products: [], total: 0 }
      }
      componentDidMount() {
        let cart = localStorage.getItem('cart');
        if (!cart) return; 
        getCartProducts(cart).then((products) => {
          let total = 0;
          for (var i = 0; i < products.length; i++) {
            total += products[i].price * products[i].qty;
          }
          this.setState({ products, total });
          });
      }
      removeFromCart = (product) => {
        let products = this.state.products.filter((item) => item.id !== product.id);
        let cart = JSON.parse(localStorage.getItem('cart'));
        delete cart[product.id.toString()];
        localStorage.setItem('cart', JSON.stringify(cart));
        let total = this.state.total - (product.qty * product.price) 
        this.setState({products, total});
      }
      clearCart = () => {
        localStorage.removeItem('cart');
        this.setState({products: []});
      }
      render() {
        const { products, total } =  this.state;
        return (
          <div className=" container">
            <h3 className="card-title">Cart</h3><hr
            {
              products.map((product, index) => 
                <CartItem product={product} remove={this.removeFromCart} key={index}/>)
            } <hr/>
            { products.length ? 
              <div><h4>
                <small>Total Amount: </small>
                <span className="float-right text-primary">${total}</span>
              </h4><hr/></div>: ''}
            { !products.length ?<h3 className="text-warning">No item on the cart</h3>: ''}
            <Link to="/checkout">
                <button className="btn btn-success float-right">Checkout</button></Link>
            <button className="btn btn-danger float-right" onClick={this.clearCart} 
                style={{ marginRight: "10px" }}>Clear Cart</button><br/><br/><br/>
          </div>
        );
      }
    }
The removeFromCart method in this component is passed to the CartItem component. It deletes the product from the cart on the localStorage and removes the product from the list products to be rendered. The Cart component also provides a clearCart method which removes all the items on the cart (this is done by deleting the cart from the localStorage).
Let's create the Checkout component. This component will only be rendered if the user authenticated (logged in).
   import React from 'react';
    import { isAuthenticated, getCartProducts, pay } from '../repository';
    import {  Redirect, Link } from 'react-router-dom';
    export default class Checkout extends React.Component {
      constructor(props) {
      super(props);
        this.state = { products: [], total: 0 }
      }
      componentDidMount() {
        let cart = localStorage.getItem('cart');
        if (!cart) return; 
        getCartProducts(cart).then((products) => {
          let total = 0;
          for (var i = 0; i < products.length; i++) {
            total += products[i].price * products[i].qty;
          }
          this.setState({ products, total });
        });
      }
      pay = () => pay().then(data => alert(data)).catch(err => console.log(err))
      render() {
        if (!isAuthenticated()) return (<Redirect to="/login" />);
        const { products, total } =  this.state;
        return (
        <div className=" container">
          <h3 className="card-title">Checkout</h3><hr/>
          { products.map((product, index) => 
              <div key={index}>
              <p>{product.name} <small> (quantity: {product.qty})</small>
                 <span className="float-right text-primary">${product.qty * product.price}
              </span></p><hr/>
              </div>
          )} <hr/>
          { products.length ? 
          <div><h4><small>Total Amount:</small><span className="float-right text-primary">
                ${total}</span></h4><hr/></div>: ''}
          { !products.length ? <h3 className="text-warning">No item on the cart</h3>: ''}
          { products.length ? <button className="btn btn-success float-right" 
                onClick={this.pay}>Pay</button>: '' }
          <Link to="/"><button className="btn btn-danger float-right" 
            style={{ marginRight: "10px" }}>Cancel</button></Link><br/><br/><br/>
        </div>
        );
      }
    }
This component loads and renders all the products on the cart, much like the Cart component. It also provides a pay button which will in this case alert a message to proceed to payment after accessing a secured route on the backend server. This is made possible by the access token attached to the request in the pay method in the repository module. It also redirects unauthenticated users to the login page.
Now that we have all the required components, we can proceed with editing the root App component:
 import React, { Component } from 'react';
    import Login from './components/Login';
    import Products from './components/ProductList';
    import Cart from './components/Cart';
    import Checkout from './components/Checkout';
    import {  BrowserRouter as Router, Link, Route } from 'react-router-dom';
    import { isAuthenticated } from './repository';
    class App extends Component {
      logOut(){
        localStorage.removeItem('x-access-token');
      }
      render() {
        const auth = isAuthenticated();
        return (
          <Router>
            <div>
              <nav className="navbar navbar-expand-lg navbar-dark bg-dark">
                <div className="container">
                  <Link className="navbar-brand" to="/">ShoppingCart</Link>
                  <button className="navbar-toggler" type="button" 
                    data-toggle="collapse" data-target="#navbarNavAltMarkup" 
                    aria-controls="navbarNavAltMarkup" aria-expanded="false" 
                    aria-label="Toggle navigation">
                    <span className="navbar-toggler-icon"></span>
                  </button>
                  <div className="collapse navbar-collapse" id="navbarNavAltMarkup">
                    <div className="navbar-nav">
                      <Link className="nav-item nav-link" to="/">Products</Link>
                      <Link className="nav-item nav-link" to="/cart">Cart</Link>
                      { (auth) ? <Link className="nav-item nav-link" to="/checkout">
                              Checkout</Link>: ''}
                      { ( auth ) ? 
                          ( <a className="nav-item nav-link" href="/" 
                              onClick={this.logOut}>Log out</a>) : 
                          ( <Link className="nav-item nav-link float-right" 
                              to="/login">Log in</Link> )
                      }
                    </div>
                  </div>
                </div>
              </nav>
              <div className="container">
                <br/>
                <Route exact path="/" component={Products} />
                <Route exact path="/cart" component={Cart} />
                <Route exact path="/checkout" component={Checkout} />
                { (!auth) ? <Route exact path="/login" component={Login} /> : '' }
              </div>
            </div>
          </Router>
        );
      }
    }
    export default App;
In this component, we create, control, and manage the application's navigation. Here, we render the navigation bar which in turn renders several links using the Link tag provided by react-router-dom, which is roughly equivalent to the HTML "a" tag. It renders the Login link when the user is not logged in, and renders Checkout and Log out links if otherwise. The log out button triggers the logOut method which deletes the access token and renders the application with the user logged out. This component also manages the application routing, i.e. it chooses which component to render for each route or link. To enable the use of react-router-dom components in the application, we need to wrap the app component in a BrowserRouter component.
Congratulations! We have just successfully built the entire application!
To recap the application start-up process, to run the application, we need to run both the backend and front-end of the application. To start the backend API server of the application, we use the command:
npm run api
To start the front end, use the command below:
npm start
After those have been successfully started, we can visit http://localhost:3000 in our browser to view the application.

In Closing

Over the course of this article, we've built a simple shopping cart with an Express backend and a React front-end. We've kept this application simple to demonstrate core Express and React concepts. Next steps would be to change the backend to interact with a database instead of static data, and use technologies, such as Flux, Redux, Mobx, etc., to make the front-end more efficient and modular.
The code for this application is available here.