Groovy & Grails: Services and Validation
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 libraryThis 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.