Ratpacked: Create a Partial Response
Suppose we want to support partial JSON responses in our Ratpack application. The user must send a request parameter with a list of fields that need to be part of the response. In our code we must use the value of the request parameter and output only the given properties of an object. We implement this logic using a custom renderer in Ratpack. Inside the renderer we can get access to the request parameters of the original request.
In our example Ratpack application we have a Course
class, which is a simple class withs some properties:
// File: src/main/groovy/mrhaki/ratpack/Course.groovy
package mrhaki.ratpack
import groovy.transform.Immutable
@Immutable
class Course {
String name
String teacher
Integer maxOccupation
}
Next we create a custom renderer for our Course
class.
We extend the RendererSupport
class and override the render
method:
// File: src/main/groovy/mrhaki/ratpack/CourseRenderer.groovy
package mrhaki.ratpack
import ratpack.handling.Context
import ratpack.render.RendererSupport
import static ratpack.jackson.Jackson.json
class CourseRenderer extends RendererSupport {
@Override
void render(final Context context, final Course course) throws Exception {
// Get request parameter fields with a comma separated list
// of field names to include in the output.
final String paramFields = context.request.queryParams.get('fields')
if (paramFields) {
// Transform comma separated property names to a Set.
final Set coursePropertyNames =
paramFields.tokenize(',').toSet()
// Create Map with only Course properties that need to
// be included.
final Map partialCourse =
filterProperties(course, coursePropertyNames)
// Render Map.
context.render(json(partialCourse))
} else {
// No fields request parameter so we can return
// the original Course object.
context.render(json(course))
}
}
/**
* Find all properties in the object that are in the collection
* of property names.
*
* @param object Object with properties to filter
* @param propertyNames Names of properties to find
* @return Map with properties
*/
private Map filterProperties(
final Object object,
final Set propertyNames) {
object.properties.findAll { property ->
property.key in propertyNames
}
}
}
Finally we need to add the CourseRenderer
to the Ratpack registry.
Ratpack will find the renderer when we want to render a Course
object. This happens automatically, we don't have to do anything ourselves.
The following Ratpack application configuration adds our CourseRenderer
with the bind
method.
We also add a endpoint to show the contents of a sample Course
object.
// File: src/ratpack/ratpack.groovy
import mrhaki.ratpack.Course
import mrhaki.ratpack.CourseRenderer
import ratpack.registry.Registry
import static ratpack.groovy.Groovy.ratpack
ratpack {
bindings {
// Add to registry, so Ratpack can use
// it to render a Course object.
bind CourseRenderer
}
handlers {
all {
final Course course =
new Course(
name: 'Ratpack rules 101',
teacher: 'mrhaki',
maxOccupation: 450)
next(Registry.single(course))
}
get('course') { Course course ->
render(course)
}
}
}
Let's try several requests using the fields
request parameter and without the fields
request parameter using HTTPie as client:
$ http -b http://localhost:5050/course
{
"maxOccupation": 450,
"name": "Ratpack rules 101",
"teacher": "mrhaki"
}
$ http -b http://localhost:5050/course fields==name,teacher
{
"name": "Ratpack rules 101",
"teacher": "mrhaki"
}
Written with Ratpack 1.3.3.