Grails Dropwizard Plugin

I’ve been seeing a lot of buzz about Dropwizard as a framework for creating REST services. I thought it would be interesting to integrate it with Grails, but it ended up being a lot more work than I expected since the two approaches are very different, and very opinionated. I have released an initial Grails plugin that integrates Dropwizard: dropwizard. The source is here and the docs are here.

To make thing more clear, I created a simple test application. You can download it here.

Available URLs

The application has a simple Person domain class with a dynamically scaffolded controller, so typical URLs like http://localhost:8080/dropwizardtest/person/list work as expected. The Dropwizard resources are mapped under the default “dropwizard” context path, so you can make a GET request (for example in a browser) for http://localhost:8080/dropwizard/people to see the JSON response for all Person instsances; there is one created in BootStrap.groovy and you can easily add more.

You can also view a single instance by id, for example http://localhost:8080/dropwizard/people/1 which should display

{"id":1,"fullName":"Person Jones","jobTitle":"Jefe Grande"}

Since there is only one user, a GET request for http://localhost:8080/dropwizard/people/42 should display

No such user.

You can create a new Person with a POST request to http://localhost:8080/dropwizard/people – do this with a REST client, or the Firefox Poster addon, or even using curl from the commandline:

curl -H "Content-Type: application/json" -H "Accept: application/json" -X POST -d '{"fullName":"Other Person","jobTitle":"Other Title"}' http://localhost:8080/dropwizard/people

Now if you view all instances with http://localhost:8080/dropwizard/people/ it should look like

[{"id":1,"fullName":"Person Jones","jobTitle":"Jefe Grande"},{"id":2,"fullName":"Other Person","jobTitle":"Other Title"}]

or you can use curl again:

curl http://localhost:8080/dropwizard/people/

There is a simple hello-world endpoint which replies with a hello message, and uses a specified name if provided. If you GET http://localhost:8080/dropwizard/hello-world you will see a response similar to

{"id":1,"content":"Hello, Stranger!"}

and if you add a name parameter – http://localhost:8080/dropwizard/hello-world?name=Ralph – you will see

{"id":2,"content":"Hello, Ralph!"}

You can also POST to /hello-world with the data for a Saying instance:

curl -H "Content-Type: application/json" -H "Accept: application/json" -X POST -d '{"id":123,"content":"test saying"}' http://localhost:8080/dropwizard/hello-world

and it will log the information using Logback:

INFO  [2013-03-05 08:35:28,334] grails.app.dropwizard.com.example.helloworld.resources.HelloWorldDropwizardResource: Received a saying: id: 123, content: test saying

The plugin comes with support for Freemarker and Mustache templates. GET http://localhost:8080/dropwizard/views/utf8.ftl to see a Freemarker response, and http://localhost:8080/dropwizard/views/utf8.mustache to see Mustache.

There is also a simple endpoint under http://localhost:8080/dropwizard/info that you can make GET requests for:

Application is running on port : 8080 connectorType : blocking

To test support for tasks, POST to http://localhost:8081/dropwizard/tasks/gc to run a garbage collection using the default “gc” task:

curl -H "Accept: application/json" -X POST http://localhost:8081/dropwizard/tasks/gc

and the response should be

Running GC...
Done!

You can run the sample HelloDropwizardTask too; send a POST request to http://localhost:8081/dropwizard/tasks/hello-task :

curl -H "Accept: application/json" -X POST http://localhost:8081/dropwizard/tasks/hello-task

and it should display

my task complete.

The admin URIs are available on port 8081. GET http://localhost:8081/dropwizard/metrics or http://localhost:8081/dropwizard/metrics?pretty=true to see current metrics:

   {
  "jvm" : {
    "vm" : {
      "name" : "Java HotSpot(TM) 64-Bit Server VM",
      "version" : "1.7.0_11-b21"
    },
    "memory" : {
    ...

GET http://localhost:8081/dropwizard/healthcheck to run all health checks:

* DataSource: OK
* deadlocks: OK
* template: OK

GET http://localhost:8081/dropwizard/threads to view a thread dump:

main id=1 state=WAITING
    - waiting on <0x38a13ac9> (a java.lang.Object)
    - locked <0x38a13ac9> (a java.lang.Object)
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:503)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.join(QueuedThreadPool.java:391)
    at org.eclipse.jetty.server.Server.join(Server.java:413)
    at grails.plugin.dropwizard.GrailsService.start(GrailsService.java:131)
    ...

And finally you can GET the simple http://localhost:8081/dropwizard/ping URL to check that everything is functional:

pong

Application notes

Dropwizard typically loads resources from the classpath, so there are a couple of ways to make files available. You can put files in src/java or grails-app/conf and non-source files will be copied to the classpath. This can clutter up those directories though, so you might want to add in a new folder for these files. The sample application has a src/resources folder for this, and adds an event callback in scripts/_Events.groovy to ensure that the files are available:

eventCompileStart = {
   ant.copy(todir: buildSettings.resourcesDir,
            failonerror: false,
            preservelastmodified: true) {
      fileset(dir: 'src/resources') {
         exclude(name: '*.groovy')
         exclude(name: '*.java')
      }
   }
}

You can put banner.txt there if you want a banner displayed and don’t set the Config.groovy property, the YAML config file, Freemarker and Mustache template files, and static resources mapped with AssetsBundles.

As mentioned in the plugin documentation, serialization of domain classes doesn’t work. The plugin explicitly converts Person instances to and from PersonDTO instances (e.g. see PeopleDropwizardResource). GORM isn’t required, so you’re free to use regular POJO/POGO based persistence. There is a somewhat old dto plugin that may or may not help here.

All of the test application’s classes (resources, health checks, etc.) are written in Groovy and are in grails-app/dropwizard, but as described in the docs you can write them in Java and register them yourself rather than using convention-over-configuration and letting them be auto-discovered. Classes in grails-app/dropwizard support dependency injection (for example the dataSource bean in DataSourceHealthCheck), and can conveniently access Config.groovy values with the ConfigValue annotation (see TemplateHealthCheck for an example of this).

7 Responses to “Grails Dropwizard Plugin”

  1. Anonymous says:

    Good work Burt! Just out of a meeting where Grails lost in favour of DropWizard but now it seems they are not quite the opposite ends of the spectrum as it seemed.

  2. Burt, this seems to be a fantastic start to what I hope will become better REST support in Grails. I don’t agree with the very opinionated choices that Dropwizard makes, but if the core REST functionality of Dropwizard could be pulled out and into a plugin that integrates well into Grails, I would be dancing in the streets, possibly literally.

    In particular, the Jetty, Logback, Metrics, YAML, and Hibernate Validator dependencies seem like they would be better off as individual plugins that adhere to an interface, so that people can use them if they like, or use something else they already have, or not use it at all and the REST plugin just ignores that part of itself.

    In any case, great work and I hope this is just the beginning of a much more REST-ful Grails.

  3. [...] plugin questa settimana che fornisce il supporto Dropwizard per Grails. Dai un’occhiata al post introduttivo che spiega suo utilizzo e il progetto di [...]

  4. Rafal Niedzialkowski says:

    Burt,

    Great post and thanks for putting the plugin together!

    How would you package and deploy an app that uses this plugin? My understanding was dropwizard bundles and embedded version of jetty, so building a grails WAR seemed backwards. Should we be able to just add a Main-Class to the WAR manifest and run it via:

    java -jar target/dropwizardtest-0.1.war server

    Rafal

    • Burt says:

      I haven’t had a chance to go back and look at running this in production, but in theory running ‘grails prod run-dropwizard’ would work. That doesn’t pre-compile GSPs, so you’d take a hit there with a slight delay loading each the first time, plus the added permgen.

      • Rafal Niedzialkowski says:

        What about running it completely standalone, outside of grails? Hence my attempt to run it directly w/ java and the war (which I thought should contain all the jar dependencies needed to run).

        • Burt says:

          Using run-dropwizard is very close to how regular DropWizard apps run. The big difference is that the Grails context is added to the embedded Jetty. But there’s no overhead there unless you make requests on the Grails side. If you just want to use DropWizard and take advantage of GORM, writing some classes in Groovy, etc. then I’d go with ‘grails prod run-dropwizard’.

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 License.