Build a Ratpack application which uses GORM
Learn how to build a Ratpack application which uses GORM as data access toolkit
Authors: Sergio del Amo
Grails Version: 3.3.1
1 Grails Training
Grails Training - Developed and delivered by the folks who created and actively maintain the Grails framework!.
2 Getting Started
In this guide, you are going to build a Ratpack application using GORM.
2.1 What you will need
To complete this guide, you will need the following:
-
Some time on your hands
-
A decent text editor or IDE
-
JDK 1.8 or greater installed with
JAVA_HOME
configured appropriately
2.2 How to complete the guide
To get started do the following:
-
Download and unzip the source
or
-
Clone the Git repository:
git clone https://github.com/grails-guides/gorm-ratpack.git
The Grails guides repositories contain two folders:
-
initial
Initial project. Often a simple Grails app with some additional code to give you a head-start. -
complete
A completed example. It is the result of working through the steps presented by the guide and applying those changes to theinitial
folder.
To complete the guide, go to the initial
folder
-
cd
intograils-guides/gorm-ratpack/initial
and follow the instructions in the next sections.
You can go right to the completed example if you cd into grails-guides/gorm-ratpack/complete
|
3 Writing the Application
3.1 Configuring your Build
Edit build.gradle file to include GORM dependencies.
dependencies {
compile "org.grails:grails-datastore-gorm-hibernate5:6.1.6.RELEASE"
runtime "com.h2database:h2:1.4.192"
runtime "org.apache.tomcat:tomcat-jdbc:8.5.0"
runtime "org.apache.tomcat.embed:tomcat-embed-logging-log4j:8.5.0"
runtime "org.slf4j:slf4j-api:1.7.10"
}
For this guide, use H2; an in-memory database.
Read GORM documentation to learn more.
3.2 GORM Configuration
The Ratpack app developed during this guide uses Google Guice. Google Guice provides the concept of a module, which is a kind of recipe for providing object.
Create a module to configure GORM.
package demo
import com.google.inject.AbstractModule
import com.google.inject.Provides
import groovy.transform.CompileStatic
import org.grails.orm.hibernate.HibernateDatastore
@CompileStatic
class GormModule extends AbstractModule {
@Override
protected void configure() {}
@Provides
HibernateDatastore hibernateDatastore() {
Map<String, Object> configuration = [
'hibernate.hbm2ddl.auto':'create-drop',
'dataSource.url':'jdbc:h2:mem:myDB'
] as Map<String, Object>
new HibernateDatastore(configuration, getClass().getPackage())
}
}
GORM for Hibernate can be configured by passing a Map or instanceof the PropertyResolver
interface to the org.grails.orm.hibernate.HibernateDatastore
class when used standalone.
3.3 Creating the domain
Create two domain objects.
-
Manufacturer.groovy
-
Vehicle.groovy
Feel free to use your favorite IDE to create these or execute the following
$ cd complete/src/main/groovy/demo
$ touch Manufacturer.groovy
$ touch Vehicle.groovy
Now that all our class stubs are in place lets go ahead and edit them.
package demo
import grails.gorm.annotation.Entity
import groovy.transform.ToString
import org.grails.datastore.gorm.GormEntity
@ToString
@Entity
class Manufacturer implements GormEntity<Manufacturer> {
String name
static hasMany = [vehicles: Vehicle]
static constraints = {
name blank: false
}
}
package demo
import grails.gorm.annotation.Entity
import org.grails.datastore.gorm.GormEntity
import groovy.transform.ToString
@ToString
@Entity
class Vehicle implements GormEntity<Vehicle> {
String name
Integer year
static belongsTo = [manufacturer: Manufacturer]
static constraints = {
name nullable: false, blank: false
}
}
Manufacturer
and Vehicle
have a one-to-many relationship.
We are using GORM outside of Grails. Because of that, we need to annotate our domain classes with the grails.gorm.annotation.Entity
. Additionally we implement the GormEntity
trait. It is merely to aid IDE support of GORM outside of Grails.
3.4 Seed Data
Create a Service
to encapsulate the creation of sample data when the application starts.
package demo
import grails.gorm.transactions.Transactional
import groovy.transform.CompileStatic
import org.grails.orm.hibernate.HibernateDatastore
import ratpack.exec.Blocking
import ratpack.service.Service
import ratpack.service.StartEvent
@CompileStatic
class BootStrapService implements Service {
void onStart(StartEvent e) throws Exception {
e.getRegistry().get(HibernateDatastore)
Blocking.exec {
populateWithSampleData()
}
}
@Transactional
void populateWithSampleData() {
Manufacturer audi = new Manufacturer(name: 'audi')
audi.addToVehicles(new Vehicle(name: 'A3', year: 1996))
audi.addToVehicles(new Vehicle(name: 'A4', year: 1994))
audi.save()
Manufacturer ford = new Manufacturer(name: 'ford')
ford.addToVehicles(new Vehicle(name: 'Ford KA', year: 1996))
ford.save()
}
}
3.5 Creating a Handler
Create a Handler
. We handle two requests.
Requests to /
return a list of manufacturers. Requests to /audi/vehicles
returns a list of vehicles of the manufacturer named audi
package demo
import grails.gorm.transactions.ReadOnly
import groovy.transform.CompileStatic
import ratpack.exec.Blocking
import ratpack.groovy.handling.GroovyContext
import ratpack.groovy.handling.GroovyHandler
import static ratpack.jackson.Jackson.json
@CompileStatic
class ManufacturerHandler extends GroovyHandler {
@Override
protected void handle(GroovyContext context) {
String manufacturerName = context.pathTokens.id
Blocking.get {
manufacturerName ? findAllVehicleNameByManufacturerName(manufacturerName) : findAllManufacturerName()
} then { names ->
context.render(json(names))
}
}
@ReadOnly
List<String> findAllVehicleNameByManufacturerName(String manufacturerName) {
Vehicle.where { manufacturer.name == manufacturerName }.projections {
property('name')
}.list() as List<String>
}
@ReadOnly
List<String> findAllManufacturerName() {
Manufacturer.where {}.projections {
property('name')
}.list() as List<String>
}
}
3.6 Ratpack.groovy
Replace the content of src/ratpack/Ratpack.groovy
.
import demo.BootStrapService
import demo.GormModule
import demo.ManufacturerHandler
import static ratpack.groovy.Groovy.ratpack
ratpack {
bindings {
module GormModule
bindInstance new BootStrapService()
add(new ManufacturerHandler())
}
handlers {
get(":id/vehicles", ManufacturerHandler)
get(ManufacturerHandler)
}
}
The previous code registers the Module
which configures GORM, the Service
which populates the database on start-up and the Handler
.
Run the app:
./gradlew run
You should be able to call the endpoints:
curl "http://localhost:5050"
and get the response:
["audi","ford"]
Or retrieve the vehicles of a manufacturer:
curl "http://localhost:5050/audi/vehicles"
and get the response:
["A3","A4"]