Loading...

January 7, 2016

Ratpacked: Add Common Handlers Via The Registry

In our Ratpack application we can have handlers that need to be invoked for every request. For example the handler needs to set a response header and will use the Context.next() method to continue with the rest of the handlers. When we have such a handler we can use the all method of a Chain instance. This happens in the handlers section of our application definition. We can also register such handlers directly in the registry. We can even use a Module to register the handler implementation. To register a handler in the registry we must use the HandlerDecorator interface. The interface has a method prepend that will encapsulate a Handler implementation and makes it available before any other handlers.

In the following sample we have a Handler implementation that checks if the RequestId object is available. If so then the value is set as a response header:

// File: src/main/groovy/com/mrhaki/ratpack/RequestIdHeader.groovy
package com.mrhaki.ratpack

import ratpack.handling.Context
import ratpack.handling.Handler
import ratpack.handling.RequestId

/**
 * Handler that adds the value of
 * the {@link RequestId} instance, if
 * available, to the response header.
 */
class RequestIdHeader implements Handler {
    
    private static final String HEADER_KEY = 
            'X-Ratpack-Request-Identifier'

    @Override
    void handle(final Context context) throws Exception {
        // Optinally get RequestId from the registry.
        final Optional<String> requestId = 
                context.maybeGet(RequestId)
        
        if (requestId.present) {
            // If RequestId is set then add it to the 
            // response header.
            context.response.headers.set(
                    HEADER_KEY, 
                    requestId.get())
        }
        
        // Continue with the rest of the handlers.
        context.next()
    }
    
}

In our Ratpack application uses the HandlerDecorator.prepend method to register our handler in the bindings section:

import com.mrhaki.ratpack.RequestIdHeader
import ratpack.handling.HandlerDecorator

import static ratpack.groovy.Groovy.ratpack

ratpack {
    bindings {
        // We use multiBindInstance so multiple
        // implementations of HandlerDecorator
        // can be added to the registry.
        multiBindInstance( 
            HandlerDecorator, 
            HandlerDecorator.prepend(new RequestIdHeader()))
    }

    handlers {
        get {
            render 'Ratpack is awesome'
        }
    }
}

Alternatively we can create a module:

// File: src/main/groovy/com/mrhaki/RequestIdModule.groovy
package com.mrhaki.ratpack

import com.google.inject.AbstractModule
import com.google.inject.multibindings.Multibinder
import ratpack.handling.HandlerDecorator

/**
 * Module to register the {@link RequestIdHeader}
 * handler with the registry.
 */
class RequestIdModule extends AbstractModule {
    
    @Override
    protected void configure() {
        // We need the Multibinder, because other modules
        // can also register HandlerDecorator implementations.
        Multibinder
                .newSetBinder(binder(), HandlerDecorator)
                .addBinding()
                .toInstance(
                    HandlerDecorator.prepend(new RequestIdHeader()))
    }
    
}

We change our Ratpack application to use the module:

import com.mrhaki.ratpack.RequestIdHeader
import com.mrhaki.ratpack.RequestIdModule
import ratpack.handling.HandlerDecorator

import static ratpack.groovy.Groovy.ratpack

ratpack {
    bindings {
        // Register module.
        module RequestIdModule
    }

    handlers {
        get {
            render 'Ratpack is awesome'
        }
    }
}

Written with Ratpack 1.1.1.