Binding, Blocking and Configuration

Learn binding, blocking, and configuration operations in Ratpack.

We'll cover the following

Bindings

Bindings in Ratpack make objects available to the handlers. If you are familiar with Spring, Ratpack uses a Registry, which is similar to the application context in Spring. It can also be thought of as a simple map from class-types to instances. Ratpack-groovy uses Guice by default, although other direct-injection frameworks can be used (or none at all).

Instead of a formal plugin system, reusable functionality can be packaged as modules. You can create your own modules to properly decouple and organize your application into components. For example, you might want to create a MongoModule or a JdbcModule. Alternatively, you could break your application into services. Either way, the registry is where you put them.

Anything in the registry can be automatically used in a handler and gets wired in by class-type from the registry. The following is an example of bindings in action:

bindings {
    bindInstance(MongoModule, new MongoModule())
    bind(DragonService, DefaultDragonService)
}
handlers {
    get('dragons') {
        DragonService dService - >
            dService.list().then {
                dragons - >
                    render(toJson(dragons))
            }
    }
}

Blocking

Blocking operations should be handled by using the “blocking” API. A blocking operation is anything that is IO-bound, such as querying the database.

The Blocking class is located at ratpack.exec.Blocking. For example, the following handler calls a method on the database:

get("deleteOlderThan/:days") {
    int days = pathTokens.days as int
    Blocking.get { database.deleteOlderThan(days)}
        .then { int i - > render("$i records deleted")}
}

You can chain multiple blocking calls using the then method. The result of the previous closure is passed as the parameter to the next closure (an int above).

Ratpack handles the thread scheduling for you and then joins with the original computation thread. This way, you can rejoin with the original HTTP request thread and return a result.

get("deleteOlderThan/:days") {
  int days = pathTokens.days as int
  int result
  Blocking.get { database.deleteOlderThan(days) }
     .then { int count -> result = count }
  render("$result records deleted")
}

If no return value is required, use the Blocking.exec method.

Configuration

Any self-respecting web application should allow configuration to come from multiple locations: the application, the file-system, environment variables, and system properties. This is a good practice in general but especially for cloud-native apps.

Ratpack includes a built-in configuration API. The ratpack.config.ConfigData class allows you to layer multiple sources of configuration. Using the of method with a passed closure allows you to define a factory of sorts for configuration from JSON, YAML, and other sources.

First, you define your configuration classes. These class properties will define the names of your configuration properties. For example:

class Config {
    DatabaseConfig database
}
class DatabaseConfig {
    String username = "root"
    String password = ""
    String hostname = "localhost"
    String database = "myDb"
}

In this case, your JSON configuration might look like the following:

{
 "database": {
   "username": "user",
   "password": "changeme",
   "hostname": "myapp.dev.company.com"
  }
}

Later, in the binding declaration, add the following to bind the configuration defined by the above classes:

serverConfig {
 json(getResource("/config.json"))
 yaml(getResource("/config.yml"))
 sysProps()
 env()
}

Each declaration overrides the previous declarations. So, in this case, the order would be: “class definition,” config.json, config.yml, system-properties, and then environment variables. This way, you could override properties at runtime.

System property and environment variable configuration must be prefixed with the ratpack and RATPACK_ prefixes accordingly. For example, the hostname property above would be ratpack.database.hostname as a system property and RATPACK_DATABASE__HOSTNAME for an environment variable.

Get hands-on with 1400+ tech skills courses.