Groovy & Grails: Services and Validation

Site Admin · 11 Sep 2026 · 10 views

Services Hold Business Logic

Services are Grails classes that live in grails-app/services. They hold the business rules that should not sit inside controllers or domain classes. Grails wraps service methods in transactions automatically by default, so a failing method rolls back its database changes.

grails create-service library

This generates a service named LibraryService in grails-app/services. A service method that updates two tables in one call becomes one transaction: either both changes commit or neither does.

A Service in Action

Here a service checks stock before placing an order.

class OrderService {
    def placeOrder(Book book, int quantity) {
        if (book.stock < quantity) {
            throw new RuntimeException("Not enough stock")
        }
        book.stock = book.stock - quantity
        book.save(failOnError: true)
    }
}

Controllers stay thin by calling the service. Grails injects the service as a property named after the class, so the business rule lives in one testable place instead of being duplicated across actions.

Validation with Constraints

Domain constraints are the first line of validation. Grails also supports command objects, plain Groovy classes with their own constraints block, for validating standalone request data such as search filters.

class SearchCommand {
    String query

    static constraints = {
        query nullable: true, maxSize: 100
    }
}

In a controller action, binding the request params to the command triggers validation automatically.

def search(SearchCommand cmd) {
    if (cmd.hasErrors()) {
        render view: "index", model: [errors: cmd.errors]
        return
    }
    render view: "results", model: [query: cmd.query]
}

Grails binds the query string to the command object and runs the constraints. If anything fails, hasErrors returns true and the view can list the messages with the error tags.

Validation Messages

Errors render through the GSP tags so the user sees friendly, localized messages instead of raw exceptions. Combining service transactions, domain constraints, and command validation gives every layer a job: constraints protect data, commands protect request data, and services protect business rules.

Key Points

  • Services bundle business logic and run inside transactions by default.
  • Controllers stay thin by delegating to injected services.
  • Constraints validate domain classes and command objects.
  • Command objects validate standalone request data like searches.
Share this post:

Comments (0)

Please login or register to comment.