The following document is a quick reference list for doing some of the common things in Grails. There can be better ways of doing the same things , but these are handy and will serve as a good reference to start with.
How to respond from a REST API Controller
From the controller action , do the following. This is for returning one object by name obj
if(res == null)
response.sendError 500
else
withFormat {
json { render obj as JSON }
}
How to inject a service into controller
Define the variable as the class name of the service. It will be injected automatically
For example if your service name isclass AtlantisService { }
then in the controller
class AtlantisController
{
// inject an instance of type AtlantisService
def atlantisService;
}
GROM how to find the max element from a table
In this example ModelClassName is the name of the model in which you are running the query. max("id")
id is the column that you are trying to find the max for.
def items = ModelClassName.withCriteria {
projections {
max("id")
}
}
GROM constraints quick look
id blank:false, nullable:false, unique : true
expiryDate blank:false, nullable : false
shortUrl blank:false, nullable: false, url : true
Add days to a date
Date newDate = new Date().plus(100); //current date + 100 days.
Date newDate = new Date().plus(-20); //current date - 20 dats.
Mark resource as readonly in a controller
UserApiController() {
super(User, true
/* read-only */``)
Enable CORS
grails:
cors:
enabled: true
Inject properties
import org.springframework.beans.factory.annotation.Value
class WidgetService {
@Value('${widget.width:50}')
int width;
def someServiceMethod() {
// this method may use the area property...
CURD default actions
class CrudController {
def index() {} //usually a "list" view
def save() {} //save new records
def show(Serializable id) {} //retrieve details on a specific record
def update(Serializable id) {} //update a specific record
def delete(Serializable id) {} //delete specific record
}
Verify mappings
package demo
import grails.testing.web.UrlMappingsUnitTest
import spock.lang.Specification
class ConferenceUrlMappingsSpec extends Specification implements UrlMappingsUnitTest<ConferenceUrlMappings> {
void setup() {
mockController(ConferenceController)
}
void "test conference mappings"() {
expect: "calls to /conference/talks to succeed"
verifyUrlMapping("/conf/talks", controller: 'conference', action: 'talks', method: 'GET')
verifyUrlMapping("/conf/talks/1", controller: 'conference', action: 'talks', method: 'GET') {
id = '1'
}
when: "calling /conf/speakers"
assertUrlMapping("/conf/speakers", controller: 'conference', action: 'speakers', method: 'GET')
then: "no exception is thrown"
noExceptionThrown()
}
}
Using Mysql
In build.gradle include the following
dependencies {
runtime 'mysql:mysql-connector-java:5.1.33'
In application.yml use the following
dbCreate: update
pooled: true
url: jdbc:mysql://127.0.0.1:3306/xxx
username: yyy
password: zzz
driverClassName: com.mysql.jdbc.Driver
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
Using newer version of connector might cause timezone issues and to fix that mention the url to db as follows in application.ymlurl: jdbc:mysql://127.0.0.1:3306/mydb?serverTimezone=UTC
Save with caution
It's also possible to call the validate method before save.
if (user.validate()) {
// do something with user
}
else {
user.errors.allErrors.each {
println it
}
}
Directly calling save will also run validations.
if(song.save())
{
println "Song was created!"
}
else
{
song.errors.allErrors.each { println it.defaultMessage }
}
The above snippet will let you know of any failures during save and any of the hooks that gets executed.
GORM Url Validation fails for localhost url's
https://github.com/grails/grails-core/issues/10249
Sharing constraints
class User {
String firstName
String lastName
String passwordHash
static constraints = {
firstName blank: false, nullable: false
lastName blank: false, nullable: false
passwordHash blank: false, nullable: false
}
}
You then want to create a command object, UserCommand
, that shares some of the properties of the domain class and the corresponding constraints. You do this with the importFrom()
method:
class UserCommand {
String firstName
String lastName
String password
String confirmPassword
static constraints = {
importFrom User
password blank: false, nullable: false
confirmPassword blank: false, nullable: false
}
}
Bind data from http request
To Bind request from url params
bindData(obj, params, [include: ['originalUrl', 'expiryDate']])
To bind from request body
/*
{
"urlEntry": {
"originalUrl": "https://news.ycombinator.com",
"expiryDate": "2020-08-29T07:05:45Z",
"dateCreated" : "2020-07-29T07:05:45Z",
"shortUrl" : "http://localhost:8080/u/1"
}
}
*/
bindData(obj, request.JSON.urlEntry, [include: ['originalUrl', 'expiryDate']])
Security concerns
This has a list of security concern on XSS, CSRF, SQLInj, Html/Url Inj, DoS.
https://docs.grails.org/latest/guide/security.html
Codecs
https://docs.grails.org/3.3.x/guide/security.html
JWT based Authentication using Spring Security REST for Grails 3.3.x
- Add the following to build.gradle.
compile 'org.grails.plugins:spring-security-core:3.2.3'
Note : Version 3.2.x of the spring security core is only compatible with Grails 3.3.x or higher.
- Add the following to application.yml
grails:
plugin.springsecurity.rest.token.storage.jwt.secret : '8Zz5tw0Ionm3XPZZfN0NOml3z9FMfmpgXwovR9fp6ryDIoGRM8EPHAB6iHsc0fb'
- Create the User, Role, UserRole domain classes to support authentication and authorization by running the following command from command line from the root directory
grails s2-quickstart atlantis User Role
| Creating User class 'User' and Role class 'Role' in package 'atlantis'
| Rendered template PersonWithoutInjection.groovy.template to destination grails-app/domain/atlantis/User.groovy
| Rendered template PersonPasswordEncoderListener.groovy.template to destination src/main/groovy/atlantis/UserPasswordEncoderListener.groovy
| Rendered template Authority.groovy.template to destination grails-app/domain/atlantis/Role.groovy
| Rendered template PersonAuthority.groovy.template to destination grails-app/domain/atlantis/UserRole.groovy
|
************************************************************
* Created security-related domain classes. Your *
* grails-app/conf/application.groovy has been updated with *
* the class names of the configured domain classes; *
* please verify that the values are correct. *
************************************************************
Masking Request Parameters From Stacktrace Logs
To mask out the values of secure request parameters, specify the parameter names in the file grails-app/conf/application.yaml
grails:
exceptionresolver:
params:
exclude:
- password
- creditCard
Request parameter logging may be turned off altogether by setting the grails.exceptionresolver.logRequestParameters
config property to false. The default value is true in DEVELOPMENT mode and false for all other environments.
grails-app/conf/application.yaml
grails:
exceptionresolver:
logRequestParameters: false
Database console for debugging development related work
It’s especially useful to have database console against an in-memory database. Access the console by navigating to http://localhost:8080/dbconsole in a browser.
The console is enabled by default in development mode and can be disabled or enabled in other environments by using the grails.dbconsole.enabled
attribute in application.yml
(or application.groovy
for Grails 2.x).
environments:
production:
grails:
serverUrl: "http://www.changeme.com"
dbconsole:
enabled: true
urlRoot: '/admin/dbconsole'
development:
grails:
serverUrl: "http://localhost:8080/${appName}"
test:
grails:
serverUrl: "http://localhost:8080/${appName}"