Showing posts with label NodeJS. Show all posts
Showing posts with label NodeJS. Show all posts

Web REST API Benchmark on a Real Life Application

Who are the candidates

  • Laravel 5, PHP 7.0, Nginx
  • Lumen 5, PHP 7.0, Nginx
  • Express JS 4, Node.js 8.1, PM2
  • Django, Python 2.7, Gunicorn
  • Spring 4, Java, Tomcat
  • .NET Core, Kestrel

What are we testing

We are interested in the number of requests per seconds each framework achieves on different server configurations alongside how clean or verbose the code looks like.

How server configurations look

We are also interested in how each framework scales its performance and what is the price of achieving such performance. This is why we’ll test them on 3 different server configurations using DigitalOcean:
  • 1 CPU, 512 MB - $5 / month
  • 4 CPU, 8 GB - $80 / month
  • 12 CPU, 32 GB - $320 / month

What are we building

We want to test a real life application example so we’ll basically build a Web REST API that exposes 4 endpoints, each one having a different complexity:
  1. Hello World - simply respond with a JSON containing Hello World string.
  2. Computation - compute the first 10.000 Fibonacci numbers.
  3. Simple Listing - we have a MySQL database containing a countries table and we’ll list all the countries.
  4. Complex Listing - we add a users table alongside a many-to-many mapping between users and countries and we want to list all users that visited France, alongside all countries each one visited.
For building the last two endpoints we’ll use the tools each framework provides to achieve our goal in the easiest possible way.

How are we testing them

For testing them we’ll use both wrk and ab HTTP benchmarking tools in order to check if we get similar results and also variate the concurrency of the requests so each technology can achieve its maximum potential.
These tools will run on their own droplet created on DigitalOcean so they don’t compete on server resources with the actual API application.
Also, the server used for placing the test requests and the one used to run the application are linked using their private IP so there won’t be any noticeable network latency.

Benchmark results

Below you can see the results grouped by each endpoint and also you can check on a single chart how each framework scaled on different server configurations.

Conclusions

Having in mind that in a real world application almost all the requests interact with the database, none of the choices are bad and all of them could handle the requirements of most web applications.
However, the performance of the Node.js with Express JS is quite remarkable. It competes with technologies such as Java and .NET Core or even outperforms them and combined with the simplicity of Javascript ES6 which you can natively use with Node.js 8, it provides so much power.
Regarding application scalability, the best performance per cost was gained on the middle size server. Adding 12 cores and 32 GB of memory didn’t help too much. Maybe, in this case, the bottle neck is somewhere else or it requires fine tunings to unlock the full server potential.

Why modern day startup heroes are choosing Node.js to develop their application?

From Netflix, PayPal, Medium to LinkedIn and Uber, major startups are leveraging the power of Node.JS.
What’s there in Node.JS, you must wonder!
Your curiosity will end today as we will share all the secrets and wonders of Node.JS with you. We will tell you-
  • Why startups love so much Node.JS?
  • How Node.JS can help your startup?
Let’s kick off-

Node.JS is a big breakthrough for the Java developers and your business too:

In most sunny or rainy day, your startup idea will be made into applications by the Java developers as it’s considered as the Lingua Franca or the most popular language of web.
  • But, before the existence of Node.JS, the JavaScript was primarily used for client-side scripting. Node.js breaks the jinx and enables JavaScript to be used for server-side scripting.
  • Before the Node.JS, the norm was to run scripts server-side to produce dynamic web page content before the page is sent to the user’s web browser.
  • The emergence of the Node.JS allows one to run scripts server-side to produce dynamic web page content before the page is sent to the user’s web browser.
For developers, this is a BIG news as they can develop application around a single programming language. Node.JS has set them free from their old misery of relying on a different language for writing server side scripts.

Faster development:

For any tech startup, faster application development is a must checkbox to fill in. Any delay in the process of “ideation to implementation” will push you out of the race.
Developers can build things quickly with the Node.JS giving your startups a massive advantage.
How?
Node.JS comes with module for all your project-needs. Big thanks to it’s NPM eco-system which saves a lot of time. Leveraging the NPM eco-system, the developers can use pre-created and pre-used modules.
Modules are provided for-
  • File system I/O
  • Networking (DNS, HTTP, TCP, TLS/SSL, or UDP)
  • Binary data (buffers)
  • Cryptography functions
  • Data streams

Robust and Scalable:

The concept of faster development is often misread and startups ruin themselves which is built fast but does not last.
Think of PayPal, think of Netflix who have massive user-base and yet they are able to provide uninterrupted service without a hiccup. Node.JS is one of the best options for the startups to ensure scalability as per one’s wish and maintain the hassle-free service for their target audience. The secret of scalability of Node.JS comes from the principle called the event loop.

Flexible solutions for both the development and solutions:

  • Cross-Platform Advantage: Applications built on Node.JS can run on Linux, macOS, Microsoft Windows, NonStop and Unix servers. Additionally, they can be written with the CoffeeScript[50] (a JavaScript alternative), Dart or TypeScript (strongly typed forms of JavaScript), or any other language that can compile to JavaScript.
  • RealTime: The big success pie of Node.JS goes to the advantage of building real-time application. WebSockets are the key here. They open the scope of building and running two-way communication channels between the client and the server which helps the developers to build real time applications like Games and Chat Engines.

Stable enough for your startup hustle:

Startup game is not free of risks. When you launch your applications or products in the market, there are lot of boxes to tick. Node.JS is a big help here. It’s no more the wonders in the world of tech stack, has seen a lot, got tested, faced challenges, is stable and now ready to scale you up.
Reading so far, if you consider Node.JS is a wonderful opportunity for you, then turn your ideas into great products with the Node.JS.

Building CRUD Web Application using MERN Stack

A comprehensive step by step tutorial of building create-read-update-delete (CRUD) web application from scratch using MERN (Mongo, Express, React, Node.js) stack. One of the most popular web application stack based on Node.js is MERN stack. MERN is the abbreviation of MongoDB, Express.js, React.js, and Node.js, almost the same with the MEAN stack except MEAN stack using Angular and MERN stack using React. This basic step by step tutorial of MERN stack is building CRUD (Create-Read-Update-Delete) web application. 


Table of Contents:



React can integrate with MERN stack as the front end that can access data from Express and MongoDB by consuming RESTful API. In this scenario of MERN Stack React will accessing data from Express and MongoDB by HTTP calls as default React component. We are using the same application for Express and React that run on the same IP and PORT. Before starting the tutorial, the following tools and framework are required:
Node.js (Stable build recommended)
Express.js
MongoDB
Mongoose.js
React.js
We assume that you have already Installed Node.js and MongoDB. Make sure Node.js command line is working (on Windows) or runnable in Linux/OS X terminal. You can run MongoDB in the different terminal or command line.


1. MERN Stack: Install and Create React App

Open the terminal or Node.js command line then go to your MERN projects folder. We will install React app creator for creating a React app easily. For that, type this command.
sudo npm install -g create-react-app
Now, create a React app by type this command.
create-react-app mern-crud
This command will create a new React app with the name `mern-crud` and this process can take sometimes because all dependencies and modules also installing automatically. Next, go to the newly created app folder.
cd ./mern-crud
Now, run the React app for the first time using this command.
npm start
It will automatically open the default browser the point to `http://localhost:3000`, so the landing page should be like this.
Building CRUD Web Application using MERN Stack - React Home Page


2. MERN Stack: Install and Configure Express.js

We have to replace the existing Node server that holds the default React application by Express.js as the backend. Stop the server by push keyboard Ctrl+C. Type this command to install Express.js and required dependencies.
npm install --save express body-parser morgan body-parser serve-favicon
Create a folder with the name "bin" and add a file with the name "www" on the root of the project.
mkdir bin
touch bin/www
Open and edit `bin/www` file then add this lines of codes.
#!/usr/bin/env node

/**
 * Module dependencies.
 */

var app = require('../app');
var debug = require('debug')('mean-app:server');
var http = require('http');

/**
 * Get port from environment and store in Express.
 */

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

/**
 * Create HTTP server.
 */

var server = http.createServer(app);

/**
 * Listen on provided port, on all network interfaces.
 */

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

/**
 * Normalize a port into a number, string, or false.
 */

function normalizePort(val) {
  var port = parseInt(val, 10);

  if (isNaN(port)) {
    // named pipe
    return val;
  }

  if (port >= 0) {
    // port number
    return port;
  }

  return false;
}

/**
 * Event listener for HTTP server "error" event.
 */

function onError(error) {
  if (error.syscall !== 'listen') {
    throw error;
  }

  var bind = typeof port === 'string'
    ? 'Pipe ' + port
    : 'Port ' + port;

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case 'EACCES':
      console.error(bind + ' requires elevated privileges');
      process.exit(1);
      break;
    case 'EADDRINUSE':
      console.error(bind + ' is already in use');
      process.exit(1);
      break;
    default:
      throw error;
  }
}

/**
 * Event listener for HTTP server "listening" event.
 */

function onListening() {
  var addr = server.address();
  var bind = typeof addr === 'string'
    ? 'pipe ' + addr
    : 'port ' + addr.port;
  debug('Listening on ' + bind);
}
Now, open and edit "package.json" then replace "start" value.
"scripts": {
  "start": "node ./bin/www",
  "build": "react-scripts build",
  "test": "react-scripts test --env=jsdom",
  "eject": "react-scripts eject"
}
Next, create "app.js" at the root of the project folder.
touch app.js
Open and edit app.js then add this lines of codes.
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var bodyParser = require('body-parser');

var book = require('./routes/book');
var app = express();

app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({'extended':'false'}));
app.use(express.static(path.join(__dirname, 'build')));

app.use('/api/book', book);

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

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;
Create routes for the book.
mkdir routes
touch routes/book.js
Open and edit “book.js" then add this lines.
var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  res.send('Express REST API');
});

module.exports = router;
Now, open and edit `src/registerServiceWorkers.js` then add to the register function this `fetch` event listener below `load` event listener.
window.addEventListener('fetch', (event) => {
  if ( event.request.url.match( '^.*(\/api\/).*$' ) ) {
    return false;
  }
});
So, the complete register function will look like this.
export default function register() {
  if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
    // The URL constructor is available in all browsers that support SW.
    const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
    if (publicUrl.origin !== window.location.origin) {
      // Our service worker won't work if PUBLIC_URL is on a different origin
      // from what our page is served on. This might happen if a CDN is used to
      // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
      return;
    }

    window.addEventListener('load', (event) => {
      const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;

      if (!isLocalhost) {
        // Is not local host. Just register service worker
        registerValidSW(swUrl);
      } else {
        // This is running on localhost. Lets check if a service worker still exists or not.
        checkValidServiceWorker(swUrl);
      }
    });

    window.addEventListener('fetch', (event) => {
      if ( event.request.url.match( '^.*(\/api\/).*$' ) ) {
        return false;
      }
    });
  }
}
Now, check the configuration by running again the Node server that handles by Express now.
npm start
Open the browser then go to `http://localhost:3000` then you will see the previous React home page. Then change the address to `http://localhost:3000/api/book`. You will see this response of web page.
Building CRUD Web Application using MERN Stack - Express RESTful API
That means it works.

3. MERN Stack: Install and Configure Mongoose

The part of MERN stack is MongoDB, to get connected to MongoDB from Node.js application we are usually using Mongoose.js as MongoDB object modeling. On the terminal type this command after stopping the running Express server.
npm install --save mongoose bluebird
Open and edit `app.js` then add this lines after another variable line.
var mongoose = require('mongoose');
mongoose.Promise = require('bluebird');
mongoose.connect('mongodb://localhost/mern-crud', { useMongoClient: true, promiseLibrary: require('bluebird') })
  .then(() =>  console.log('connection succesful'))
  .catch((err) => console.error(err));
You can test the connection to MongoDB by run again the Node application and you will see this message on the terminal.
connection succesful
If you are still using built-in Mongoose Promise library, you will get this deprecated warning on the terminal.
(node:42758) DeprecationWarning: Mongoose: mpromise (mongoose's default promise library) is deprecated, plug in your own promise library instead: http://mongoosejs.com/docs/promises.html
That's the reason why we added `bluebird` modules and register it as Mongoose Promise library.


4. MERN Stack: Create Mongoose.js Model

Add a models folder on the root of the project folder for hold Mongoose.js model files.
mkdir models
Create a new Javascript file that uses for Mongoose.js model. We will create a model of Book collection.
touch models/Book.js
Now, open and edit that file and add Mongoose require.
var mongoose = require('mongoose');
Then add model fields like this.

var BookSchema = new mongoose.Schema({
  isbn: String,
  title: String,
  author: String,
  description: String,
  published_date: { type: Date },
  publisher: String,
  updated_date: { type: Date, default: Date.now },
});
That Schema will mapping to MongoDB collections called book. If you want to know more about Mongoose Schema Datatypes you can find it here. Next, export that schema.
module.exports = mongoose.model('Book', BookSchema);


5. MERN Stack: Create Routes for Accessing Book Data via Restful API

Open and edit again "routes/book.js” then replace all codes with this.
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var Book = require('../models/Book.js');

/* GET ALL BOOKS */
router.get('/', function(req, res, next) {
  Book.find(function (err, products) {
    if (err) return next(err);
    res.json(products);
  });
});

/* GET SINGLE BOOK BY ID */
router.get('/:id', function(req, res, next) {
  Book.findById(req.params.id, function (err, post) {
    if (err) return next(err);
    res.json(post);
  });
});

/* SAVE BOOK */
router.post('/', function(req, res, next) {
  Book.create(req.body, function (err, post) {
    if (err) return next(err);
    res.json(post);
  });
});

/* UPDATE BOOK */
router.put('/:id', function(req, res, next) {
  Book.findByIdAndUpdate(req.params.id, req.body, function (err, post) {
    if (err) return next(err);
    res.json(post);
  });
});

/* DELETE BOOK */
router.delete('/:id', function(req, res, next) {
  Book.findByIdAndRemove(req.params.id, req.body, function (err, post) {
    if (err) return next(err);
    res.json(post);
  });
});

module.exports = router;
Run again the Express server then open the other terminal or command line to test the Restful API by type this command.
curl -i -H "Accept: application/json" localhost:3000/api/book
If that command return response like below then REST API is ready to go.
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 2
ETag: W/"2-l9Fw4VUO7kr8CvBlt4zaMCqXZ0w"
Date: Sat, 28 Oct 2017 22:39:59 GMT
Connection: keep-alive
Now, let's populate Book collection with initial data that sent from RESTful API. Run this command to populate it.
curl -i -X POST -H "Content-Type: application/json" -d '{ "isbn":"1783551623, 9781783551620","title":"React.js Essentials: A Fast-paced Guide to Designing and Building Scalable and Maintainable Web Apps With React.js","author": "Artemij Fedosejev","description":"A fast-paced guide to designing and building scalable and maintainable web apps with React.js.","published_date":"2015-08-27T16:00:00Z","publisher":"Packt Publishing" }' localhost:3000/api/book
You will see this response on the terminal if success.
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 459
ETag: W/"1cb-G9luzsvo07EKg3s00VUyB19WpA4"
Date: Thu, 02 Nov 2017 00:01:22 GMT
Connection: keep-alive

{"__v":0,"isbn":"1783551623, 9781783551620","title":"React.js Essentials: A Fast-paced Guide to Designing and Building Scalable and Maintainable Web Apps With React.js","author":"Artemij Fedosejev","description":"A fast-paced guide to designing and building scalable and maintainable web apps with React.js.","published_date":"2015-08-27T16:00:00.000Z","publisher":"Packt Publishing","_id":"59fa6052e245b0060c9aa5d5","updated_date":"2017-11-02T00:01:22.058Z"}


6. MERN Stack: Add React Router DOM

Our front end consists of Booklist, detail, create and edit. For navigating between that component, we need to create a route. First, install modules that required by the components.
npm install --save react-route-dom
npm install --save-dev bootstrap
npm install --save axios
Next, open and edit `src/index.js` then replace all codes with this.
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
import '../node_modules/bootstrap/dist/css/bootstrap-theme.min.css';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import Edit from './components/Edit';
import Create from './components/Create';
import Show from './components/Show';

ReactDOM.render(
  <Router>
      <div>
        <Route exact path='/' component={App} />
        <Route path='/edit/:id' component={Edit} />
        <Route path='/create' component={Create} />
        <Route path='/show/:id' component={Show} />
      </div>
  </Router>,
  document.getElementById('root')
);
registerServiceWorker();
You see that Edit, Create and Show added as the separate component. Bootstrap also included in the import to make the views better. Now, create the new edit, create and show files.
mkdir src/components
touch src/components/Create.js
touch src/components/Show.js
touch src/components/Edit.js


7. MERN Stack: Add List of Book to Existing App Component

As you see in the previous step that App component act as home or root page. This component handles the list of books. Open and edit `src/App.js` then replace all codes with this codes.
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Link } from 'react-router-dom';
import axios from 'axios';

class App extends Component {

  constructor(props) {
    super(props);
    this.state = {
      books: []
    };
  }

  componentDidMount() {
    axios.get('/api/book')
      .then(res => {
        this.setState({ books: res.data });
        console.log(this.state.books);
      });
  }

  render() {
    return (
      <div class="container">
        <div class="panel panel-default">
          <div class="panel-heading">
            <h3 class="panel-title">
              BOOK CATALOG
            </h3>
          </div>
          <div class="panel-body">
            <h4><Link to="/create"><span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span> Add Book</Link></h4>
            <table class="table table-stripe">
              <thead>
                <tr>
                  <th>ISBN</th>
                  <th>Title</th>
                  <th>Author</th>
                </tr>
              </thead>
              <tbody>
                {this.state.books.map(book =>
                  <tr>
                    <td><Link to={`/show/${book._id}`}>{book.isbn}</Link></td>
                    <td>{book.title}</td>
                    <td>{book.author}</td>
                  </tr>
                )}
              </tbody>
            </table>
          </div>
        </div>
      </div>
    );
  }
}

export default App;


8. MERN Stack: Add Create Components for Add New Book

For add a new book, open and edit `src/components/Create.js` then replace all codes with this codes.
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';
import { Link } from 'react-router-dom';

class Create extends Component {

  constructor() {
    super();
    this.state = {
      isbn: '',
      title: '',
      author: '',
      description: '',
      published_year: '',
      publisher: ''
    };
  }
  onChange = (e) => {
    const state = this.state
    state[e.target.name] = e.target.value;
    this.setState(state);
  }

  onSubmit = (e) => {
    e.preventDefault();

    const { isbn, title, author, description, published_year, publisher } = this.state;

    axios.post('/api/book', { isbn, title, author, description, published_year, publisher })
      .then((result) => {
        this.props.history.push("/")
      });
  }

  render() {
    const { isbn, title, author, description, published_year, publisher } = this.state;
    return (
      <div class="container">
        <div class="panel panel-default">
          <div class="panel-heading">
            <h3 class="panel-title">
              ADD BOOK
            </h3>
          </div>
          <div class="panel-body">
            <h4><Link to="/"><span class="glyphicon glyphicon-th-list" aria-hidden="true"></span> Book List</Link></h4>
            <form onSubmit={this.onSubmit}>
              <div class="form-group">
                <label for="isbn">ISBN:</label>
                <input type="text" class="form-control" name="isbn" value={isbn} onChange={this.onChange} placeholder="ISBN" />
              </div>
              <div class="form-group">
                <label for="title">Title:</label>
                <input type="text" class="form-control" name="title" value={title} onChange={this.onChange} placeholder="Title" />
              </div>
              <div class="form-group">
                <label for="author">Author:</label>
                <input type="text" class="form-control" name="author" value={author} onChange={this.onChange} placeholder="Author" />
              </div>
              <div class="form-group">
                <label for="description">Description:</label>
                <textArea class="form-control" name="description" onChange={this.onChange} placeholder="Description" cols="80" rows="3">{description}</textArea>
              </div>
              <div class="form-group">
                <label for="published_date">Published Date:</label>
                <input type="number" class="form-control" name="published_year" value={published_year} onChange={this.onChange} placeholder="Published Year" />
              </div>
              <div class="form-group">
                <label for="publisher">Publisher:</label>
                <input type="text" class="form-control" name="publisher" value={publisher} onChange={this.onChange} placeholder="Publisher" />
              </div>
              <button type="submit" class="btn btn-default">Submit</button>
            </form>
          </div>
        </div>
      </div>
    );
  }
}

export default Create;


9. MERN Stack: Add Show Component for Show Book Details

To show book details that listed on the home page, open and edit `src/components/Show.js` then add this lines of codes.
import React, { Component } from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom';

class Show extends Component {

  constructor(props) {
    super(props);
    this.state = {
      book: {}
    };
  }

  componentDidMount() {
    axios.get('/api/book/'+this.props.match.params.id)
      .then(res => {
        this.setState({ book: res.data });
        console.log(this.state.book);
      });
  }

  delete(id){
    console.log(id);
    axios.delete('/api/book/'+id)
      .then((result) => {
        this.props.history.push("/")
      });
  }

  render() {
    return (
      <div class="container">
        <div class="panel panel-default">
          <div class="panel-heading">
            <h3 class="panel-title">
              {this.state.book.title}
            </h3>
          </div>
          <div class="panel-body">
            <h4><Link to="/"><span class="glyphicon glyphicon-th-list" aria-hidden="true"></span> Book List</Link></h4>
            <dl>
              <dt>ISBN:</dt>
              <dd>{this.state.book.isbn}</dd>
              <dt>Author:</dt>
              <dd>{this.state.book.author}</dd>
              <dt>Description:</dt>
              <dd>{this.state.book.description}</dd>
              <dt>Publish Date:</dt>
              <dd>{this.state.book.published_year}</dd>
              <dt>Publisher:</dt>
              <dd>{this.state.book.publisher}</dd>
            </dl>
            <Link to={`/edit/${this.state.book._id}`} class="btn btn-success">Edit</Link>&nbsp;
            <button onClick={this.delete.bind(this, this.state.book._id)} class="btn btn-danger">Delete</button>
          </div>
        </div>
      </div>
    );
  }
}

export default Show;
In this component, there is two button for edit current book and for delete current book. Delete function included in this component.


10. MERN Stack: Add Edit Component for Edit a Book

After the show book details, we need to edit the book. For that open and edit, `src/components/Edit.js` then add this lines of codes.
import React, { Component } from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom';

class Edit extends Component {

  constructor(props) {
    super(props);
    this.state = {
      book: {}
    };
  }

  componentDidMount() {
    axios.get('/api/book/'+this.props.match.params.id)
      .then(res => {
        this.setState({ book: res.data });
        console.log(this.state.book);
      });
  }

  onChange = (e) => {
    const state = this.state.book
    state[e.target.name] = e.target.value;
    this.setState({book:state});
  }

  onSubmit = (e) => {
    e.preventDefault();

    const { isbn, title, author, description, published_year, publisher } = this.state.book;

    axios.put('/api/book/'+this.props.match.params.id, { isbn, title, author, description, published_year, publisher })
      .then((result) => {
        this.props.history.push("/show/"+this.props.match.params.id)
      });
  }

  render() {
    return (
      <div class="container">
        <div class="panel panel-default">
          <div class="panel-heading">
            <h3 class="panel-title">
              EDIT BOOK
            </h3>
          </div>
          <div class="panel-body">
            <h4><Link to={`/show/${this.state.book._id}`}><span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span> Book List</Link></h4>
            <form onSubmit={this.onSubmit}>
              <div class="form-group">
                <label for="isbn">ISBN:</label>
                <input type="text" class="form-control" name="isbn" value={this.state.book.isbn} onChange={this.onChange} placeholder="ISBN" />
              </div>
              <div class="form-group">
                <label for="title">Title:</label>
                <input type="text" class="form-control" name="title" value={this.state.book.title} onChange={this.onChange} placeholder="Title" />
              </div>
              <div class="form-group">
                <label for="author">Author:</label>
                <input type="text" class="form-control" name="author" value={this.state.book.author} onChange={this.onChange} placeholder="Author" />
              </div>
              <div class="form-group">
                <label for="description">Description:</label>
                <input type="text" class="form-control" name="description" value={this.state.book.description} onChange={this.onChange} placeholder="Description" />
              </div>
              <div class="form-group">
                <label for="published_date">Published Date:</label>
                <input type="number" class="form-control" name="published_year" value={this.state.book.published_year} onChange={this.onChange} placeholder="Published Year" />
              </div>
              <div class="form-group">
                <label for="publisher">Publisher:</label>
                <input type="text" class="form-control" name="publisher" value={this.state.book.publisher} onChange={this.onChange} placeholder="Publisher" />
              </div>
              <button type="submit" class="btn btn-default">Submit</button>
            </form>
          </div>
        </div>
      </div>
    );
  }
}

export default Edit;


11. MERN Stack: Run the MERN App

Now, we can test our completed app by type this command.
npm run build
npm start
On the browser go to `localhost:3000` then you will see this home page.
Building CRUD Web Application using MERN Stack - MERN Application Home
You can navigate and populate the books data.

The Ultimate XP Project

  (Bài chia sẻ của tác giả  Ryo Amano ) Trong  bài viết  số này, tôi muốn viết về dự án phát triển phần mềm có áp dụng nguyên tắc phát triển...