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: 4
1 Grails Training
Apache Grails Training
Apache Grails is now part of the Apache Software Foundation. The community-maintained training catalog is being migrated; in the meantime see the Learning page for current resources, recorded talks, and links to other community-supplied training material.
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 11 or greater installed with
JAVA_HOMEconfigured 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:
-
initialInitial project.
The initial contains a Ratpack app.
// missing snippet: ../initial/build.gradle
with a GET / endpoint returning hello world.
// missing snippet: ../initial/src/ratpack/Ratpack.groovy
-
completeA completed example. It is the result of working through the steps presented by the guide and applying those changes to theinitialfolder.
To complete the guide, go to the initial folder
-
cdintograils-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.
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 static ratpack.groovy.Groovy.ratpack
ratpack {
handlers {
get {
render "Hello World"
}
}
}
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"]
4 Do you need help with GORM or Grails?
Help with Apache Grails
Apache Grails is supported by an active community of contributors and the Apache Software Foundation. If you need help working through a guide, want to discuss the framework, or have run into something that looks like a bug, the channels below are the right place to start.
-
Slack - real-time conversation with the Apache Grails community.
-
dev@grails.apache.org">Developer mailing list - design discussions and contributor coordination.
-
users@grails.apache.org">Users mailing list - end-user questions and answers.
-
Issue tracker on GitHub - file a bug or feature request against the framework.
For Grails plugins, see the matching project on the apache org or the plugin’s own GitHub repository.