Build Grails 3, MongoDB and React Profile CRUD Web Application

by Didin J. on Mar 21, 2018 Build Grails 3, MongoDB and React Profile CRUD Web Application

Step by step tutorial on build Grails 3, MongoDB and React Profile CRUD Web Application.

Comprehensive step by step by step tutorial on build Grails 3, MongoDB and React Profile CRUD Web Application. Previously we have to show you how to build CRUD Web Application with the famous Angular 5. Now, we will use React.js as front-end framework that will be working together on the same project with Grails 3. Using this profile will create 2 application, they are Grails 3 as server and React.js as Client.

The scenario for this tutorial almost same as previous tutorial using Angular 5 profile. they are creating, read, update and delete Customer data. CRUD mechanism using RESTful API provided by Grails 3 and visualization using React.js as the front end.

The following tools, frameworks, and module are required for this tutorial achievement:

- JDK 8
- Grails 3.3.3
- Node.js (recommended stable version)
- Angular CLI
- MongoDB
- Terminal (Linux/Mac) or Command Line (Windows)
- Text Editor or IDE

Before moving to the steps of the tutorial, make sure you have installed above requirements.


1. Create New Grails 3 Application

Open the terminal or command line then go to your Grails projects folder. Type this command to create a new Grails 3 application with React profile.

grails create-app grails-react --profile=react

Go to the newly created Grails 3 application folder.

cd ./grails-react

Now you have server and client folder inside this project folder.

drwxr-xr-x   8 didin  staff   256 Mar 20 20:25 client
drwxr-xr-x   3 didin  staff    96 Mar 20 20:25 gradle
-rwxr--r--   1 didin  staff  4971 Mar 20 20:25 gradlew
-rwxr--r--   1 didin  staff  2314 Mar 20 20:25 gradlew.bat
drwxr-xr-x  10 didin  staff   320 Mar 20 20:25 server
-rw-r--r--   1 didin  staff    26 Mar 20 20:25 settings.gradle

You can run server or client only by type this command.

./gradlew server:bootRun
./gradlew client:bootRun

To run both of them together, use this command.

./gradlew bootRun --parallel

Node.js and its dependencies will be downloaded automatically. React application will run using port 3000 and Grails 3 using port 8080. React application will open in the default browser automatically.

Build Grails 3, MongoDB and React Profile CRUD Web Application - Grails React Profile Page

You will get this response on the browser when you change the address to `localhost:8080`.

Build Grails 3, MongoDB and React Profile CRUD Web Application - Grails Page


2. Create Grails 3 Domain Class

To save or populate MongoDB data, first, we have to add Gradle dependencies for MongoDB. Open and edit `server/build.gradle` file then comment out all Hibernate and H2 dependencies then add dependencies for MongoDB.

buildscript {
    ...
    dependencies {
        classpath "org.grails:grails-gradle-plugin:$grailsVersion"
        classpath "com.moowork.gradle:gradle-node-plugin:0.13"
        // classpath "org.grails.plugins:hibernate5:${gormVersion-".RELEASE"}"
        classpath "org.grails.plugins:views-gradle:1.1.6"
    }
}
...
dependencies {
    ...
    // compile "org.grails.plugins:hibernate5"
    // compile "org.hibernate:hibernate-core:5.1.5.Final"
    compile "org.grails.plugins:views-json"
    compile "org.grails.plugins:views-json-templates"
    console "org.grails:grails-console"
    profile "org.grails.profiles:react"
    runtime "org.glassfish.web:el-impl:2.1.2-b03"
    // runtime "com.h2database:h2"
    runtime "org.apache.tomcat:tomcat-jdbc"
    compile 'org.grails.plugins:mongodb'
    ...
}

Compile Grails 3 application by typing this command inside Server folder.

cd ./server
grails compile

Next, open and edit `server/grails-app/conf/application.yml` then remove or replace in-memory H2 database and Hibernate configuration with this.

...
environments:
    development:
        grails:
            mongodb:
                host: "localhost"
                port: 27017
                username: ""
                password: ""
                databaseName: "grails-react"
    production:
        grails:
            mongodb:
                host: "localhost"
                port: 27017
                username: ""
                password: ""
                databaseName: "grails-react"

Now, we are ready to create a domain class for Customer data. In the terminal or command line inside Server folder type this command to enter Grails 3 interactive console.

grails

Create a new Grails 3 domain class by typing this command.

create-domain-class grails.react.Customer

Open and edit `server/grails-app/domain/grails/react/Customer.groovy` file then Replace all codes with this.

package grails.react

import grails.rest.*

@Resource(uri='/customer')
class Customer {

  String name
  String address
  String city
  String postalCode
  String phone

  static constraints = {
      name blank:false
      address blank:false
      city blank:false
      postalCode blank:false
      phone blank:false
  }

  String toString() {
    name
  }
}

That it's, just modify a domain class we have a RESTful API for Customer data CRUD operation.


3. Test CRUD RESTful API

Now, it's a time for testing a CRUD operation. We will use `CURL` command for this. Open the other terminal or command line tab then run MongoDB server if there's no currently running MongoDB server.

mongod

Run again the Server by using this command in previous terminal tab after type `exit` in the Grails 3 interactive console.

cd ../
./gradlew server:bootRun

Open another terminal or command line tab again then type this command to get Customer data/list.

curl -i -H "Accept: application/json" localhost:8080/customer

The correct response should be like this.

HTTP/1.1 200
X-Application-Context: application:development
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 21 Mar 2018 00:48:40 GMT

[]

Next, save or post a single data to the Customer endpoint.

curl -i -X POST -H "Content-Type: application/json" -d '{"name":"John Doe","address":"accross the river behind the mountain","city":"the hight mount","postalCode":"11111","phone":"123123123"}' localhost:8080/customer

You will get this response when data saved successfully to MongoDB database.

HTTP/1.1 201
X-Application-Context: application:development
Location: http://localhost:8080/customer/1
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 21 Mar 2018 00:51:05 GMT

{"id":1,"phone":"123123123","address":"accross the river behind the mountain","postalCode":"11111","name":"John Doe","city":"the hight mount"}

Now you have your RESTful API ready to access from the React front-end application. Don't worry about the CORS for using the different port because it already enabled by Grails 3 default configuration.


4. Add React Router DOM for CRUD Front End

This React front end consists of the Customer list, 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-router-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 App from './App';
import './css/App.css';
import './css/grails.css';
import './css/main.css';
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')
);

You see that Edit, Create and Show added as the separate component. Bootstrap also included in the import for 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


5. Add List of Customer to Existing App Component

To get the list of Customer and display to the page, open and edit `client/src/App.js` file then replace with this lines of 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 = {
      customers: []
    };
  }

  componentDidMount() {
    axios.get('http://localhost:8080/customer')
      .then(res => {
        this.setState({ customers: res.data });
        console.log(this.state.customers);
      });
  }

  render() {
    return (
      <div class="container">
        <div class="panel panel-default">
          <div class="panel-heading">
            <h3 class="panel-title">
              CUSTOMER LIST
            </h3>
          </div>
          <div class="panel-body">
            <h4><Link to="/create"><span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span> Add Customer</Link></h4>
            <table class="table table-stripe">
              <thead>
                <tr>
                  <th>Name</th>
                  <th>Address</th>
                </tr>
              </thead>
              <tbody>
                {this.state.customers.map(cust =>
                  <tr>
                    <td><Link to={`/show/${cust.id}`}>{cust.name}</Link></td>
                    <td>{cust.address}</td>
                  </tr>
                )}
              </tbody>
            </table>
          </div>
        </div>
      </div>
    );
  }
}

export default App;


6. Add a Components for Create a New Customer

For add a new Customer, open and edit `client/src/components/Create.js` then replace all codes with this lines of 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 = {
      name: '',
      address: '',
      city: '',
      postalCode: '',
      phone: ''
    };
  }
  onChange = (e) => {
    const state = this.state
    state[e.target.name] = e.target.value;
    this.setState(state);
  }

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

    const { name, address, city, postalCode, phone } = this.state;

    axios.post('http://localhost:8080/customer', { name, address, city, postalCode, phone })
      .then((result) => {
        this.props.history.push("/")
      });
  }

  render() {
    const { name, address, city, postalCode, phone } = this.state;
    return (
      <div class="container">
        <div class="panel panel-default">
          <div class="panel-heading">
            <h3 class="panel-title">
              ADD CUSTOMER
            </h3>
          </div>
          <div class="panel-body">
            <h4><Link to="/"><span class="glyphicon glyphicon-th-list" aria-hidden="true"></span> Customer List</Link></h4>
            <form onSubmit={this.onSubmit}>
              <div class="form-group">
                <label for="isbn">Name:</label>
                <input type="text" class="form-control" name="name" value={name} onChange={this.onChange} placeholder="Name" />
              </div>
              <div class="form-group">
                <label for="title">Address:</label>
                <input type="text" class="form-control" name="address" value={address} onChange={this.onChange} placeholder="Address" />
              </div>
              <div class="form-group">
                <label for="author">City:</label>
                <input type="text" class="form-control" name="city" value={city} onChange={this.onChange} placeholder="City" />
              </div>
              <div class="form-group">
                <label for="published_date">Postal Code:</label>
                <input type="number" class="form-control" name="postalCode" value={postalCode} onChange={this.onChange} placeholder="Postal Code" />
              </div>
              <div class="form-group">
                <label for="publisher">Phone:</label>
                <input type="tetx" class="form-control" name="phone" value={phone} onChange={this.onChange} placeholder="Phone Number" />
              </div>
              <button type="submit" class="btn btn-default">Submit</button>
            </form>
          </div>
        </div>
      </div>
    );
  }
}

export default Create;


7. Add a Component for Show Customer Details

To show customer details that listed on the home page, open and edit `client/src/components/Show.js` then replace all codes with 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 = {
      customer: {}
    };
  }

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

  delete(id){
    console.log(id);
    axios.delete('http://localhost:8080/customer/'+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">
              Customer Details
            </h3>
          </div>
          <div class="panel-body">
            <h4><Link to="/"><span class="glyphicon glyphicon-th-list" aria-hidden="true"></span> Customer List</Link></h4>
            <dl>
              <dt>Name:</dt>
              <dd>{this.state.customer.name}</dd>
              <dt>Address:</dt>
              <dd>{this.state.customer.address}</dd>
              <dt>City:</dt>
              <dd>{this.state.customer.city}</dd>
              <dt>Postal Code:</dt>
              <dd>{this.state.customer.postalCode}</dd>
              <dt>Phone Number:</dt>
              <dd>{this.state.customer.phone}</dd>
            </dl>
            <Link to={`/edit/${this.state.customer.id}`} class="btn btn-success">Edit</Link>&nbsp;
            <button onClick={this.delete.bind(this, this.state.customer.id)} class="btn btn-danger">Delete</button>
          </div>
        </div>
      </div>
    );
  }
}

export default Show;

In this component, there is two button for edit current customer and for delete current customer. Delete function included in this component.


8. Add a Component for Edit a Customer

After show customer details, we need to edit the customer. For that open and edit, `client/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 = {
      customer: {}
    };
  }

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

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

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

    const { name, address, city, postalCode, phone } = this.state.customer;

    axios.put('http://localhost:8080/customer/'+this.props.match.params.id, { name, address, city, postalCode, phone })
      .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 CUSTOMER
            </h3>
          </div>
          <div class="panel-body">
            <h4><Link to={`/show/${this.state.customer.id}`}><span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span> Customer List</Link></h4>
            <form onSubmit={this.onSubmit}>
              <div class="form-group">
                <label for="name">Name:</label>
                <input type="text" class="form-control" name="name" value={this.state.customer.name} onChange={this.onChange} placeholder="Name" />
              </div>
              <div class="form-group">
                <label for="title">Address:</label>
                <input type="text" class="form-control" name="address" value={this.state.customer.address} onChange={this.onChange} placeholder="Address" />
              </div>
              <div class="form-group">
                <label for="author">City:</label>
                <input type="text" class="form-control" name="city" value={this.state.customer.city} onChange={this.onChange} placeholder="City" />
              </div>
              <div class="form-group">
                <label for="description">Postal Code:</label>
                <input type="number" class="form-control" name="postalCode" value={this.state.customer.postalCode} onChange={this.onChange} placeholder="Postal Code" />
              </div>
              <div class="form-group">
                <label for="published_date">Phone Number:</label>
                <input type="number" class="form-control" name="phone" value={this.state.customer.phone} onChange={this.onChange} placeholder="Phone Number" />
              </div>
              <button type="submit" class="btn btn-default">Submit</button>
            </form>
          </div>
        </div>
      </div>
    );
  }
}

export default Edit;


9. Run and Test Grails 3 and React Profile CRUD Web Application

It's time for running the server and client side and test all CRUD functionality. Type this command from the root of the project directory.

./gradlew bootRun --parallel

If there's some wrong with the client. You can run the client using the standard Node.js command in the other terminal tab.

cd ./client
npm start

Now, here the whole application looks like.

Build Grails 3, MongoDB and React Profile CRUD Web Application - Customer List
Build Grails 3, MongoDB and React Profile CRUD Web Application - Add Customer
Build Grails 3, MongoDB and React Profile CRUD Web Application - Customer List
Build Grails 3, MongoDB and React Profile CRUD Web Application - Customer Details
Build Grails 3, MongoDB and React Profile CRUD Web Application - Edit Customer

That it's, if you need the full working source code, you can find it on our GitHub.

That just the basic. If you need more deep learning about Groovy and Grails you can take the following cheap course:

  • Mastering Grails. A Comprehensive Grails Course.
  • Groovy Scripting for Developers / Testers
  • Introduction to JVM Languages Clojure, Kotlin, and Groovy
  • Thanks!

    Loading…