Ratpacked: Implement Custom Rendering With Renderable Interface
Ratpack uses renderers to render output. We can create our own renderer by implementing the Renderer
interface.
The renderer class needs to implement a render
method that has the object we want to render as argument.
Alternatively we can add the logic to render a object to the class definition of that object.
So instead of having a separate renderer class for a class, we add the render logic to the class itself.
To achieve this we must implement the Renderable
interface for our class.
Ratpack provides a RenderableRenderer
in the registry that knows how to render classes that implement the Renderable
interface.
In the following example we have a Recipe
class that implements the Renderable
interface:
package mrhaki.ratpack;
import ratpack.handling.Context;
import ratpack.render.Renderable;
import static ratpack.jackson.Jackson.json;
public class Recipe implements Renderable {
private final String name;
public Recipe(final String name) {
this.name = name;
}
public String getName() {
return name;
}
/**
* Render object as JSON.
*
* @param context Ratpack context.
*/
@Override
public void render(final Context context) throws Exception {
context.byContent(content -> content
.plainText(() -> context.render(this.toString()))
.json(() -> context.render(json(this))));
}
public String toString() {
return String.format("Recipe::name=%s", this.name);
}
}
Let’s write a specification to test how the Recipe
is rendered:
package mrhaki.ratpack
import groovy.json.JsonSlurper
import ratpack.test.embed.EmbeddedApp
import spock.lang.Specification
class RecipeRenderableSpec extends Specification {
def app = EmbeddedApp.fromHandler { ctx ->
ctx.render(new Recipe('macaroni'))
}
def httpClient = app.httpClient
void 'render Recipe as plain text'() {
when:
def response = httpClient.requestSpec { request ->
request.headers.set 'Accept', 'text/plain'
}.get()
then:
response.statusCode == 200
and:
response.body.text == 'Recipe::name=macaroni'
}
void 'render Recipe as JSON'() {
when:
def response = httpClient.requestSpec { request ->
request.headers.set 'Accept', 'application/json'
}.get()
then:
response.statusCode == 200
and:
def recipe = new JsonSlurper().parseText(response.body.text)
recipe.name == 'macaroni'
}
}
Written with Ratpack 1.4.5.