eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – Summer Sale 2026 – NPI EA (cat= Baeldung)
announcement - icon

Yes, we're now running our only Summer Sale. All Courses are 30% off until 20th July, 2026:

>> EXPLORE ACCESS NOW

Course – Summer Sale 2026 – NPI (cat=Baeldung)
announcement - icon

Yes, we're now running our only Summer Sale. All Courses are 30% off until 20th July, 2026:

>> EXPLORE ACCESS NOW

1. Overview

Ratpack is a set of lightweight Java libraries for building scalable HTTP applications with reactive, asynchronous, and non-blocking features.

Additionally, Ratpack also provides integration with technologies and frameworks like Google Guice, Spring Boot, RxJava and Hystrix.

In this tutorial, we’ll explore how to use Ratpack with Groovy.

2. Why Groovy?

Groovy is a powerful, dynamic language that runs in the JVM.

Therefore, Groovy makes scripting and Domain Specific Languages really easy. With Ratpack, this provides for rapid web application development.

Ratpack provides easy integration with Groovy through the ratpack-groovy and ratpack-groovy-test libraries.

3. Ratpack Application Using Groovy Script

The Ratpack Groovy APIs are built in Java so they can easily integrate with both Java and Groovy applications. They’re available in the ratpack.groovy package.

Actually, in combination with Groovy’s scripting abilities and Grape dependency management, we can quickly create a Ratpack-powered web application in just a few lines:

@Grab('io.ratpack:ratpack-groovy:1.6.1')
import static ratpack.groovy.Groovy.ratpack

ratpack {
    handlers {
        get {
            render 'Hello World from Ratpack with Groovy!!'
        }    
    }
}

This is our first handler, handling a GET request. All we had to do was to add some basic DSL to enable the Ratpack server.

Let’s now run this as a Groovy script to start the application. By default, the application will be available on http://localhost:5050:

$ curl -s localhost:5050
Hello World from Ratpack with Groovy!!

We can also configure the port using ServerConfig:

ratpack {
    serverConfig {
        port(5056)
    }
}

Ratpack also provides a hot reloading feature, which means we can change Ratpack.groovy, and then see the changes the moment the application serves our next HTTP request.

4. Ratpack-Groovy Dependency Management

There are several ways to enable ratpack-groovy support.

4.1. Grape

We can use Groovy’s embedded dependency manager Grape.

It’s as simple as adding an annotation to our Ratpack.groovy script:

@Grab('io.ratpack:ratpack-groovy:1.6.1')
import static ratpack.groovy.Groovy.ratpack

4.2. Maven Dependency

For building in Maven, all we need is to add the dependency for the ratpack-groovy library:

<dependency>
    <groupId>io.ratpack</groupId>
    <artifactId>ratpack-groovy</artifactId>
    <version>${ratpack.version}</version>
</dependency>

4.3. Gradle

We can enable ratpack-groovy integration, by adding Ratpack’s Gradle plugin for Groovy in build.gradle:

plugins { 
  id 'io.ratpack.ratpack-groovy' version '1.6.1' 
}

5. Ratpack Handlers in Groovy

Handlers provide a way to handle web requests and responses. The request and response objects can be accessed in this closure.

We can handle web requests using HTTP methods like GET and POST:

handlers { 
    get("greet/:name") { ctx ->
        render "Hello " + ctx.getPathTokens().get("name") + " !!!"
    }
}      

We can test this web request through http://localhost:5050/greet/<name>:

$ curl -s localhost:5050/greet/Norman
Hello Norman!!!

In the code of the handler, ctx is the Context registry object which grants access to path variables, request and response objects.

Handlers also have support for dealing with JSON through Jackson.

Let’s return JSON, converted from a Groovy map:

get("data") {
    render Jackson.json([title: "Mr", name: "Norman", country: "USA"])
}
$ curl -s localhost:5050/data
{"title":"Mr","name":"Norman","country":"USA"}

Here, Jackson.json is used to make the conversion.

6. Ratpack Promises in Groovy

As we know, Ratpack enables the asynchronous and non-blocking features in the application. This is implemented with Ratpack Promises.

Promises are similar to those used in JavaScript and are a bit like a Java Future. We can think of a Promise as the representation of a value which will be available in the future:

post("user") {
    Promise<User> user = parse(Jackson.fromJson(User)) 
    user.then { u -> render u.name } 
}

The last action here is the then action, which determines what to do with the final value. In this case, we return it as a response to the POST.

Let’s understand this code in more detail. Here, Jackson.fromJson parses the JSON of the request body using the ObjectMapper User. Then, the inbuilt Context.parse method binds it to the Promise object.

The promise operates asynchronously. When the then operation is eventually performed, the response is returned:

curl -X POST -H 'Content-type: application/json' --data \
'{"id":3,"title":"Mrs","name":"Jiney Weiber","country":"UK"}' \
http://localhost:5050/employee

Jiney Weiber

We should note that the Promise library is quite rich, allowing us to chain actions using functions like map and flatMap.

7. Integration with a Database

Having asynchronous handlers is of most benefit when our handlers have to wait for services. Let’s demonstrate this by integrating our Ratpack application with an H2 database.

We can either use the Ratpack’s HikariModule class which is an extension of HikariCP JDBC connection pool, or Groovy Sql for database integration.

7.1. HikariModule

To add HikariCP support, let’s first add the following Hikari and H2 maven dependencies in our pom.xml:

<dependency>
    <groupId>io.ratpack</groupId>
    <artifactId>ratpack-hikari</artifactId>
    <version>${ratpack.version}</version>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>${h2.version}</version>
</dependency>

Or, we can add the following dependencies to our build.gradle:

dependencies {
  compile ratpack.dependency('hikari')
  compile "com.h2database:h2:$h2.version"
}

Now, we’ll declare HikariModule under the bindings closure for the connection pool:

import ratpack.hikari.HikariModule

ratpack {
    bindings {
        module(HikariModule) { config ->
            config.dataSourceClassName = 'org.h2.jdbcx.JdbcDataSource'
            config.addDataSourceProperty('URL', 
              "jdbc:h2:mem:devDB;INIT=RUNSCRIPT FROM 'classpath:/User.sql'")
        }
    }
}

Finally, we’re all set to use it for simple database operations using Java’s Connection and PreparedStatement:

get('fetchUserName/:id') { Context ctx ->
    Connection connection = ctx.get(DataSource.class).getConnection()
    PreparedStatement queryStatement = 
      connection.prepareStatement("SELECT NAME FROM USER WHERE ID=?")
    queryStatement.setInt(1, Integer.parseInt(ctx.getPathTokens().get("id")))
    ResultSet resultSet = queryStatement.executeQuery()
    resultSet.next()
    render resultSet.getString(1)  
}

Let’s check that the handler works as expected:

$ curl -s localhost:5050/fetchUserName/1
Norman Potter

7.2. Groovy Sql Class

We can use Groovy Sql for quick database operations, through methods like rows and executeInsert:

get('fetchUsers') {
    def db = [url:'jdbc:h2:mem:devDB']
    def sql = Sql.newInstance(db.url, db.user, db.password)
    def users = sql.rows("SELECT * FROM USER");
    render(Jackson.json(users))
}
$ curl -s localhost:5050/fetchUsers
[{"ID":1,"TITLE":"Mr","NAME":"Norman Potter","COUNTRY":"USA"},
{"ID":2,"TITLE":"Miss","NAME":"Ketty Smith","COUNTRY":"FRANCE"}]

Let’s write an HTTP POST example with Sql:

post('addUser') {
    parse(Jackson.fromJson(User))
        .then { u ->
            def db = [url:'jdbc:h2:mem:devDB']
            Sql sql = Sql.newInstance(db.url, db.user, db.password)
            sql.executeInsert("INSERT INTO USER VALUES (?,?,?,?)", 
              [u.id, u.title, u.name, u.country])
            render "User $u.name inserted"
        }
}
$ curl -X POST -H 'Content-type: application/json' --data \
'{"id":3,"title":"Mrs","name":"Jiney Weiber","country":"UK"}' \
http://localhost:5050/addUser

User Jiney Weiber inserted

8. Unit Testing

8.1. Setting up the Tests

As discussed, Ratpack also provides the ratpack-groovy-test library for testing a ratpack-groovy application.

To use it, we can add it as Maven dependency in our pom.xml:

<dependency>
    <groupId>io.ratpack</groupId>
    <artifactId>ratpack-groovy-test</artifactId>
    <version>1.6.1</version>
</dependency>

Alternatively, we can add the Gradle dependency in our build.gradle:

testCompile ratpack.dependency('groovy-test')

Then we need to create a Groovy main class RatpackGroovyApp.groovy to let us test the Ratpack.groovy script.

public class RatpackGroovyApp {
    public static void main(String[] args) {
        File file = new File("src/main/groovy/com/baeldung/Ratpack.groovy");
        def shell = new GroovyShell()  
        shell.evaluate(file)
    }
}

When running Groovy tests as JUnit tests, the class will invoke the Ratpack.groovy script using GroovyShell. In turn, it will start the Ratpack server for testing.

Now, let’s write our Groovy Test class RatpackGroovySpec.groovy along with the code to start the Ratpack server through the RatpackGroovyApp:

class RatpackGroovySpec {
    ServerBackedApplicationUnderTest ratpackGroovyApp = 
      new MainClassApplicationUnderTest(RatpackGroovyApp.class)
    @Delegate TestHttpClient client = 
      TestHttpClient.testHttpClient(ratpackGroovyApp)
}

Ratpack provides MainClassApplicationUnderTest to mock the application class for starting the server.

8.2. Writing Our Tests

Let’s write our tests, starting with a very basic test to check if the application can start:

@Test
void "test if app is started"() {
    when:
    get("")

    then:
    assert response.statusCode == 200
    assert response.body.text == 
      "Hello World from Ratpack with Groovy!!"
}

Let’s now write another test to verify the response of the fetchUsers get handler:

@Test
void "test fetchUsers"() {
    when:
    get("fetchUsers")
        
    then:
    assert response.statusCode == 200
    assert response.body.text == 
      '[{"ID":1,"TITLE":"Mr","NAME":"Norman Potter","COUNTRY":"USA"},{"ID":2,"TITLE":"Miss","NAME":"Ketty Smith","COUNTRY":"FRANCE"}]'
}

The Ratpack test framework takes care of starting and stopping the server for us.

9. Conclusion

In this article, we’ve seen a few ways to write HTTP handlers for Ratpack using Groovy. We also explored Promises and Database integration.

We’ve seen how Groovy closures, DSLs, and Groovy’s Sql make our code concise, efficient and readable. At the same time, Groovy’s test support makes unit and integration testing straightforward.

With these techniques, we can use Groovy’s dynamic language features, and expressive APIs, to rapidly develop high-performance, scalable HTTP applications with Ratpack.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

Course – Summer Sale 2026 – NPI EA (cat= Baeldung)
announcement - icon

Yes, we're now running our only Summer Sale. All Courses are 30% off until 20th July, 2026:

>> EXPLORE ACCESS NOW

Course – Summer Sale 2026 – NPI (All)
announcement - icon

Yes, we're now running our only Summer Sale. All Courses are 30% off until 20th July, 2026:

>> EXPLORE ACCESS NOW

eBook Jackson – NPI EA – 3 (cat = Jackson)