Comprehensive step by step by step tutorial on build Grails 3, MongoDB and Vue.js Profile CRUD (Create, Read, Update, Delete) Web Application. Previously we have to show you how to build CRUD Web Application with the famous Angular 5 and React.js. Now, we will use Vue.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 Vue.js as Client.
The scenario for this tutorial almost same as previous tutorial using Angular 5 or React.js profile. They are creating, read, update and delete Customer data. CRUD mechanism using RESTful API provided by Grails 3 and visualization using Vue.js as the front end.
The following tools, frameworks, and module are required for this tutorial achievement:
- JDK 8
- Grails 3.3.5
- Node.js (recommended stable version)
- Vue.js
- 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 the Vue.js profile.
grails create-app grails-vue --profile=vue
Go to the newly created Grails 3 application folder.
cd ./grails-vue
Now you have server and client folder inside this project folder.
drwxr-xr-x 17 didin staff 544 May 29 06:58 client
drwxr-xr-x 3 didin staff 96 May 29 06:58 gradle
-rwxr--r-- 1 didin staff 4971 May 29 06:58 gradlew
-rwxr--r-- 1 didin staff 2314 May 29 06:58 gradlew.bat
drwxr-xr-x 10 didin staff 320 May 29 06:58 server
-rw-r--r-- 1 didin staff 26 May 29 06:58 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. The vue.js application will run using port 3000 and Grails 3 using port 8080. Now, open the browser then point to `localhost:3000` then you will see this page.
You will get this response on the browser when you change the address to `localhost:8080`.
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-vue"
production:
grails:
mongodb:
host: "localhost"
port: 27017
username: ""
password: ""
databaseName: "grails-vue"
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.vue.Customer
Open and edit `server/grails-app/domain/grails/vue/Customer.groovy` file then Replace all codes with this.
package grails.vue
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 (Create, Read, Update, Delete) RESTful API
Now, it's a time for testing a CRUD (Create, Read, Update, Delete) 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.
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: Thu, 31 May 2018 00:11:33 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: Thu, 31 May 2018 00:12:16 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 Vue.js front-end application. Don't worry about the CORS for using the different port because it already enabled by Grails 3 default configuration.
4. Create Vue.js Component and Routing
Now, it's time for Vue.js or front end part. First, create or add the component of the customer list, show, edit and create. Create all of those files inside components folder after go to the Client folder.
cd ./client
touch src/components/CustomerList.vue
touch src/components/CreateCustomer.vue
touch src/components/EditCustomer.vue
touch src/components/ShowCustomer.vue
Now, open and edit `client/src/router/index.js` then add the import for all above new components.
import Vue from 'vue'
import Router from 'vue-router'
import CustomerList from '@/components/CustomerList'
import CreateCustomer from '@/components/CreateCustomer'
import ShowCustomer from '@/components/ShowCustomer'
import EditCustomer from '@/components/EditCustomer'
Add the router to each component or page.
export default new Router({
routes: [
{
path: '/',
name: 'CustomerList',
component: CustomerList
},
{
path: '/show-customer/:id',
name: 'ShowCustomer',
component: ShowCustomer
},
{
path: '/add-customer',
name: 'CreateCustomer',
component: CreateCustomer
},
{
path: '/edit-customer/:id',
name: 'EditCustomer',
component: EditCustomer
}
]
})
5. Add Module for RESTful API Access and Styling UI
Previously, the file for customer list component is created. For UI or styling, we are using Bootstrap Vue, to install it type this command on the terminal.
npm i [email protected] bootstrap-vue [email protected]
Open and edit `client/src/main.js` then add/replace the imports for Bootstrap-Vue.
import Vue from 'vue'
import App from './App'
import BootstrapVue from 'bootstrap-vue'
import router from './router'
import * as uiv from 'uiv'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
import './assets/css/grails.css'
import './assets/css/main.css'
Add this line after `Vue.config`.
Vue.use(BootstrapVue)
Next, we are using Axio for accessing RESTful API that provided by Grails. To install it, in the terminal type this command.
npm install axios --save
6. Modify Component of Customer List
Now, open and edit `client/src/components/CustomerList.vue` then add this lines of codes.
<template>
<b-row>
<b-col cols="12">
<h2>
Customer List
<b-link href="#/add-customer">(Add Customer)</b-link>
</h2>
<b-table striped hover :items="customers" :fields="fields">
<template slot="actions" scope="row">
<b-btn size="sm" @click.stop="details(row.item)">Details</b-btn>
</template>
</b-table>
<ul v-if="errors && errors.length">
<li v-for="error of errors">
{{error.message}}
</li>
</ul>
</b-col>
</b-row>
</template>
<script>
import axios from 'axios'
export default {
name: 'CustomerList',
data () {
return {
fields: {
name: { label: 'Name', sortable: true, 'class': 'text-center' },
city: { label: 'City', sortable: true },
actions: { label: 'Action', 'class': 'text-center' }
},
customers: [],
errors: []
}
},
created () {
axios.get(`http://localhost:8080/customer`)
.then(response => {
this.customers = response.data
})
.catch(e => {
this.errors.push(e)
})
},
methods: {
details (customer) {
this.$router.push({
name: 'ShowCustomer',
params: { id: customer.id }
})
}
}
}
</script>
There are template and script in one file. The template block contains HTML tags. Script block contains variables, page lifecycle and methods or functions.
7. Modify Component of Create Customer
Now, open and edit `client/src/components/CreateCustomer.vue` then add this lines of codes.
<template>
<b-row>
<b-col cols="12">
<h2>
Add Customer
<b-link href="#/">(Customer List)</b-link>
</h2>
<b-form @submit="onSubmit">
<b-form-group id="fieldsetHorizontal"
horizontal
:label-cols="4"
breakpoint="md"
label="Enter Customer Name">
<b-form-input id="name" :state="state" v-model.trim="customer.name"></b-form-input>
</b-form-group>
<b-form-group id="fieldsetHorizontal"
horizontal
:label-cols="4"
breakpoint="md"
label="Enter Customer Address">
<b-form-textarea id="address"
v-model="customer.address"
placeholder="Enter something"
:rows="2"
:max-rows="6">{{customer.address}}</b-form-textarea>
</b-form-group>
<b-form-group id="fieldsetHorizontal"
horizontal
:label-cols="4"
breakpoint="md"
label="Enter Customer City">
<b-form-input id="city" :state="state" v-model.trim="customer.city"></b-form-input>
</b-form-group>
<b-form-group id="fieldsetHorizontal"
horizontal
:label-cols="4"
breakpoint="md"
label="Enter Customer Postal Code">
<b-form-input id="postalCode" :state="state" v-model.trim="customer.postalCode"></b-form-input>
</b-form-group>
<b-form-group id="fieldsetHorizontal"
horizontal
:label-cols="4"
breakpoint="md"
label="Enter Phone">
<b-form-input id="phone" :state="state" v-model.trim="customer.phone"></b-form-input>
</b-form-group>
<b-button type="submit" variant="primary">Save</b-button>
</b-form>
</b-col>
</b-row>
</template>
<script>
import axios from 'axios'
export default {
name: 'CreateCustomer',
data () {
return {
customer: {}
}
},
methods: {
onSubmit (evt) {
evt.preventDefault()
axios.post(`http://localhost:8080/customer`, this.customer)
.then(response => {
this.$router.push({
name: 'ShowCustomer',
params: { id: response.data.id }
})
})
.catch(e => {
this.errors.push(e)
})
}
}
}
</script>
That code contains the template for customer form, the script that contains Vue.js 2 codes for hold customer model and methods for saving customer to RESTful API.
8. Modify Component of Show Customer
Open and edit `client/src/components/ShowCustomer.vue` then add this lines of codes.
<template>
<b-row>
<b-col cols="12">
<h2>
Edit Customer
<b-link href="#/">(Customer List)</b-link>
</h2>
<b-jumbotron>
<template slot="header">
{{customer.title}}
</template>
<template slot="lead">
Name: {{customer.name}}<br>
Address: {{customer.address}}<br>
City: {{customer.city}}<br>
Postal Code: {{customer.postalCode}}<br>
Phone: {{customer.phone}}<br>
</template>
<hr class="my-4">
<b-btn variant="success" @click.stop="editcustomer(customer.id)">Edit</b-btn>
<b-btn variant="danger" @click.stop="deletecustomer(customer.id)">Delete</b-btn>
</b-jumbotron>
</b-col>
</b-row>
</template>
<script>
import axios from 'axios'
export default {
name: 'ShowCustomer',
data () {
return {
customer: []
}
},
created () {
axios.get(`http://localhost:8080/customer/` + this.$route.params.id)
.then(response => {
this.customer = response.data
})
.catch(e => {
this.errors.push(e)
})
},
methods: {
editcustomer (customerid) {
this.$router.push({
name: 'EditCustomer',
params: { id: customerid }
})
},
deletecustomer (customerid) {
axios.delete('http://localhost:8080/customer/' + customerid)
.then((result) => {
this.$router.push({
name: 'CustomerList'
})
})
.catch(e => {
this.errors.push(e)
})
}
}
}
</script>
<style>
.jumbotron {
padding: 2rem;
}
</style>
Delete function also includes this component inside methods block.
9. Modify Component of Edit Customer
For editing customer that chooses from show customer page, open and edit `client/src/components/EditCustomer.vue` then add this lines of codes.
<template>
<b-row>
<b-col cols="12">
<h2>
Edit Customer
<router-link :to="{ name: 'ShowCustomer', params: { id: customer.id } }">(Show Customer)</router-link>
</h2>
<b-form @submit="onSubmit">
<b-form-group id="fieldsetHorizontal"
horizontal
:label-cols="4"
breakpoint="md"
label="Enter Customer Name">
<b-form-input id="name" :state="state" v-model.trim="customer.name"></b-form-input>
</b-form-group>
<b-form-group id="fieldsetHorizontal"
horizontal
:label-cols="4"
breakpoint="md"
label="Enter Customer Address">
<b-form-textarea id="address"
v-model="customer.address"
placeholder="Enter something"
:rows="2"
:max-rows="6">{{customer.address}}</b-form-textarea>
</b-form-group>
<b-form-group id="fieldsetHorizontal"
horizontal
:label-cols="4"
breakpoint="md"
label="Enter Customer City">
<b-form-input id="city" :state="state" v-model.trim="customer.city"></b-form-input>
</b-form-group>
<b-form-group id="fieldsetHorizontal"
horizontal
:label-cols="4"
breakpoint="md"
label="Enter Customer Postal Code">
<b-form-input id="postalCode" :state="state" v-model.trim="customer.postalCode"></b-form-input>
</b-form-group>
<b-form-group id="fieldsetHorizontal"
horizontal
:label-cols="4"
breakpoint="md"
label="Enter Phone">
<b-form-input id="phone" :state="state" v-model.trim="customer.phone"></b-form-input>
</b-form-group>
<b-button type="submit" variant="primary">Update</b-button>
</b-form>
</b-col>
</b-row>
</template>
<script>
import axios from 'axios'
export default {
name: 'EditCustomer',
data () {
return {
customer: {}
}
},
created () {
axios.get(`http://localhost:8080/customer/` + this.$route.params.id)
.then(response => {
this.customer = response.data
})
.catch(e => {
this.errors.push(e)
})
},
methods: {
onSubmit (evt) {
evt.preventDefault()
axios.put(`http://localhost:8080/customer/` + this.$route.params.id, this.customer)
.then(response => {
this.$router.push({
name: 'ShowCustomer',
params: { id: this.$route.params.id }
})
})
.catch(e => {
this.errors.push(e)
})
}
}
}
</script>
This component almost same as creating customer component, except for load customer data by id and method for update data using `PUT`.
10. Run The Grails 3, MongoDB and Vue.js Web Application
This time to test all complete the Grails 3, MongoDB and Vue.js Stack configuration. Type this command to run again this web application.
./gradlew bootRun --parallel
And here the application looks like, now you can test all CRUD functionality.
That's it, you can find the full source code on our GitHub.
That just the basic. If you need more deep learning about Groovy and Grails you can take the following cheap course:
Thanks!