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 is
class 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.yml
url: 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

  1. 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.
  1. Add the following to application.yml
grails:
	plugin.springsecurity.rest.token.storage.jwt.secret : '8Zz5tw0Ionm3XPZZfN0NOml3z9FMfmpgXwovR9fp6ryDIoGRM8EPHAB6iHsc0fb'
  1. 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

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}"