Dropwizard – Easy REST

Share

1.    What is Dropwizard

We’re all witnessing raising popularity of Microservices architecture. In Microservices architecture Dropwizard takes very important place. It is a framework for building RESTful Web Services, or better say – a set of tools and frameworks for building RESTful Web Services.

It allows a developer very quick project bootstrap. This helps you to package your applications that can be easily deployable in the production environment as a standalone service. If you have ever been in a situation to bootstrap a project in Spring framework for example, you probably know how painful it can be. With Dropwizard, it’s just a matter of adding one Maven dependency.

2.    Dropwizard Default Libraries

Instead of including all libraries needed for building REST service separately, and configuring each of them, Dropwizard does that for us. Here is the list of libraries that comes with Dropwizard by default.

Jetty : You would require HTTP for running a web application. Dropwizard embeds the Jetty servlet container for running the web applications. Instead of deploying your applications to an application server or web server, dropwizard defines a main method that invokes the Jetty server as a standalone process. As of now, dropwizard recommends only running the application with Jetty, no other web services like Tomcat is not officially supported.

Jersey : Jersey is one of the best REST API implementation out in the market. Also it follows the standard JAX-RS specification and it is the reference implementation for the JAX-RS specification. Dropwizard uses Jersey as the default framework for building the RESTful web applications.

Jackson : Jackson is the defacto standard for JSON format handling. It is one of the best object mapper API for the JSON format.

Metrics : Dropwizard has it’s own metrics module for exposing the application metrics through HTTP endpoints.

Guava : which, in addition to highly optimized immutable data structures, provides a growing number of classes to speed up development in Java.

Logback and Slf4j : These two are used for the better logging mechanisms.

Freemarker and Mustache : Choosing template engines for your application is one of the key decision. The chosen template engine has to be more flexible for writing the better scripts. Dropwizard uses the well known and popular template engines Freemarker and Mustache for building the user interfaces.
Apart from the above list, there are many other libraries like Joda Time, Liquibase, Apache HTTP Client and Hibernate Validadtor are used by dropwizard for building REST services.

3.    Maven Configuration

Dropwizard officially supports Maven. Even if you can use other build tools, most of the guides and documentation uses Maven, so we’re going to use it too here.
This is the first step in creating your Dropwizard application. Please add the following entry in your Maven’s pom.xml file:

<dependencies>
    <dependency>
        <groupId>io.dropwizard</groupId>
        <artifactId>dropwizard-core</artifactId>
        <version>${dropwizard.version}</version>
    </dependency>
</dependencies>

Before adding the above entry, you could add the dropwizard.version as below:

<properties>
    <dropwizard.version>1.1.0</dropwizard.version>
</properties>

That’s it. You have done with writing the Maven configuration. This will download all the required dependencies to your project. Current Dropwizard version is 1.1.0 so we will be using it here. Now, we will move on to writing our first real Dropwizard application.

4.    Define Configuration Class

Dropwizard stores configuration in YML files. You will need to have configuration.yml file in your application root folder. This file will be then deserialized to an instance of your application’s configuration class and validated. Your application’s configuration file is the subclass of the Dropwizard’s Configuration class (io.dropwizard.Configuration).
Let’s create simple configuration class:

import io.dropwizard.Configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.validator.constraints.NotEmpty;

public class DropwizardBlogConfiguration extends Configuration {
  @NotEmpty
  private String message;
  @NotEmpty
  private String defaultParam1;
  @NotEmpty
  private String defaultParam2;

  @JsonProperty
  public String getMessage() {
    return message;
  }

  @JsonProperty
  public void setMessage(String message) {
    this.message = message;
  }

  @JsonProperty
  public String getDefaultParam1() {
    return defaultParam1;
  }

  @JsonProperty
  public void setDefaultParam1(String defaultParam1) {
    this.defaultParam1 = defaultParam1;
  }

  @JsonProperty
  public String getDefaultParam2() {
    return defaultParam2;
  }

  @JsonProperty
  public void setDefaultParam2(String defaultParam2) {
    this.defaultParam2 = defaultParam2;
  }
}

The YAML configuration file would look like this:

message: Hello %s! You are learning %s!!
defaultParam1: Programmer
defaultParam2: Dropwizard

The above class will be deserialized from the YAML file and put the values from the YAML file to this object.

5.    Define an Application Class

We should now go and create the main application class. This class will bring all the bundles together and make the application up and running for the use.
Here is the example for application class:

import io.dropwizard.Application;
import io.dropwizard.setup.Environment;

import com.endava.blog.config.DropwizardBlogConfiguration;
import com.endava.blog.resource.DropwizardBlogResource;

public class DropwizardBlogApplication extends Application<DropwizardBlogConfiguration> {
  public static void main(String[] args) throws Exception {
    new DropwizardBlogApplication().run(args);
  }

  @Override
  public void run(DropwizardBlogConfiguration configuration,
                  Environment environment) {
      final DropwizardBlogResource resource = new DropwizardBlogResource (
          configuration.getMessage(),
          configuration.getDefaultParam1(),configuration.getDefaultParam2());
      environment.jersey().register(resource);
  }
}

6.    Define a Representation Class

Now we have to start thinking about our REST API and what will be the representation of our resource. We have to design the JSON format and the corresponding representation class that converts to the desired JSON format. Let’s look at the sample JSON format for this simple example:

{

  {"content":"Hello Programmer! You are learning Dropwizard!!"}

}

For the above JSON format, we would create the representation class as below:

import com.fasterxml.jackson.annotation.JsonProperty;

import org.hibernate.validator.constraints.Length;


public class Representation {

  @Length(max = 3)

  private String content;


  public Representation() {

    // Jackson deserialization

  }


  @JsonProperty

  public String getContent() {

    return content;

  }


  public void setContent(String content) {

    this.content = content;

  }


  public Representation(String content) {

    this.content = content;

  }

}

This is fairly simple POJO.

7.    Define a Resource Class

A resource is all REST service is about. It is nothing but an endpoint URI for accessing the resource on the server. In this example, we’ll have a resource class with few annotations for request URI mapping. Since Dropwizard uses the JAX-RS implementation, we will define the URI path using the @Path annotation.
Here is a resource class for our example tutorial:

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

import com.codahale.metrics.annotation.Timed;
import com.endava.blog.representation.Representation;
import com.google.common.base.Optional;

@Path("/our-endpoint")
@Produces(MediaType.APPLICATION_JSON)
public class DropwizardBlogResource {
  private final String message;
  private final String defaultParam1;
  private final String defaultParam2;

  public DropwizardBlogResource(String message, String defaultParam1, String defaultParam2) {
    this.message = message;
    this.defaultParam1 = defaultParam1;
    this.defaultParam2 = defaultParam2;
  }

  @GET
  @Timed
  public Representation sayHello(@QueryParam("param1") Optional<String> param1,
      @QueryParam("param2") Optional<String> param2) {
    final String value = String.format(message, param1.or(defaultParam1), param2.or(defaultParam2));
    return new Representation(value);
  }
}

8.    Registering a Resource

Now when we have created our resource class, we need to register this resource with the application class. As mentioned, application class is the starting point for the Dropwizard service, so any registration of classes has to be done in the application class. We need to add this to our Application class:

@Override
public void run(DropwizardBlogConfiguration configuration,
                Environment environment) {
    final DropwizardBlogResource resource = new DropwizardBlogResource (
        configuration.getMessage(),
        configuration.getDefaultParam1(),configuration.getDefaultParam2());
    environment.jersey().register(resource);
}

9.    Build Your Application

Best practice is to build the single FAT JAR file which contain all of the .class files required to run your application. The same JAR file can be deployed to the different environment from testing to the production without any change in the dependency libraries. To start building our example application as a fat JAR, we need to configure a Maven plugin called maven-shade. You have to add the following entries in the plugins section of your pom.xml file.
Here is the sample Maven configuration for building the JAR file.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.endava</groupId>
  <artifactId>dropwizard-blog</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>Dropwizard Blog example</name>

  <properties>
    <dropwizard.version>1.1.0</dropwizard.version>
  </properties>

  <dependencies>
    <dependency>
    <groupId>io.dropwizard</groupId>
    <artifactId>dropwizard-core</artifactId>
    <version>${dropwizard.version}</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-shade-plugin</artifactId>
      <version>2.3</version>
      <configuration>
        <createDependencyReducedPom>true</createDependencyReducedPom>
        <filters>
        <filter>
            <artifact>*:*</artifact>
          <excludes>
            <exclude>META-INF/*.SF</exclude>
            <exclude>META-INF/*.DSA</exclude>
            <exclude>META-INF/*.RSA</exclude>
          </excludes>
        </filter>
        </filters>
      </configuration>
      <executions>
        <execution>
        <phase>package</phase>
        <goals>
          <goal>shade</goal>
        </goals>
        <configuration>
          <transformers>
            <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                  <mainClass>com.endava.blog.DropwizardBlogApplication</mainClass>
                </transformer>
              </transformers>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

10.    Running Your Application

Now, we should be able to run the service. If you have successfully built your JAR file all you need to do is to open the command prompt and just run the following command to execute your JAR file:

java -jar target/dropwizard-blog-1.0.0.jar server configuration.yml

If all went OK, then you would see something like this:

INFO  [2017-04-17 13:16:07,657] org.eclipse.jetty.util.log: Logging initialized @742ms to org.eclipse.jetty.util.log.Slf4jLog
INFO  [2017-04-17 13:16:07,710] io.dropwizard.server.DefaultServerFactory: Registering jersey handler with root path prefix: /
INFO  [2017-04-17 13:16:07,711] io.dropwizard.server.DefaultServerFactory: Registering admin handler with root path prefix: /
INFO  [2017-04-17 13:16:07,713] io.dropwizard.server.DefaultServerFactory: Registering jersey handler with root path prefix: /
INFO  [2017-04-17 13:16:07,713] io.dropwizard.server.DefaultServerFactory: Registering admin handler with root path prefix: /
INFO  [2017-04-17 13:16:07,715] io.dropwizard.server.ServerFactory: Starting DropwizardBlogApplication
INFO  [2017-04-17 13:16:07,773] org.eclipse.jetty.setuid.SetUIDListener: Opened application@3531f3ca{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
INFO  [2017-04-17 13:16:07,773] org.eclipse.jetty.setuid.SetUIDListener: Opened admin@7fcf294e{HTTP/1.1,[http/1.1]}{0.0.0.0:8081}
INFO  [2017-04-17 13:16:07,775] org.eclipse.jetty.server.Server: jetty-9.4.z-SNAPSHOT
INFO  [2017-04-17 13:16:08,115] io.dropwizard.jersey.DropwizardResourceConfig: The following paths were found for the configured resources:

    GET     /our-endpoint (com.endava.blog.resource.DropwizardBlogResource)

INFO  [2017-04-17 13:16:08,116] org.eclipse.jetty.server.handler.ContextHandler: Started i.d.j.MutableServletContextHandler@70c0a3d5{/,null,AVAILABLE}
INFO  [2017-04-17 13:16:08,119] io.dropwizard.setup.AdminEnvironment: tasks =

    POST    /tasks/log-level (io.dropwizard.servlets.tasks.LogConfigurationTask)
    POST    /tasks/gc (io.dropwizard.servlets.tasks.GarbageCollectionTask)

WARN  [2017-04-17 13:16:08,120] io.dropwizard.setup.AdminEnvironment:
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!    THIS APPLICATION HAS NO HEALTHCHECKS. THIS MEANS YOU WILL NEVER KNOW      !
!     IF IT DIES IN PRODUCTION, WHICH MEANS YOU WILL NEVER KNOW IF YOU'RE      !
!    LETTING YOUR USERS DOWN. YOU SHOULD ADD A HEALTHCHECK FOR EACH OF YOUR    !
!         APPLICATION'S DEPENDENCIES WHICH FULLY (BUT LIGHTLY) TESTS IT.       !

Now you have your own Dropwizard application listening on ports 8080 for application requests and 8081 for administration requests.
Note that server employee-details.yml is used for starting the HTTP server and passing the YAML configuration file location to the server.
You should be able to access the applications at http://localhost:8080/our-endpoint or with parameters as http://localhost:8080/our-endpoint?param1=Peter&param2=Microservices.

Excellent!! Finally we have implemented a Microservices using Dropwizard framework. Now let’s go for a break and have a cup of tea, you have done really good job :).

11.    How to Change Context Path

By default, Dropwizard application will start and running in the /. For example, if you are not mentioning anything about the context path of the application, by default the application can be access from the URL http://localhost:8080/. If you want to configure your own context path for your application, then please add the following entries to your YAML file.

server:
      applicationContextPath: /application

12.    Resources for learning Dropwizard

Here is some of the useful Dropwizard tutorials and documentations that will help you to learn Dropwizrad framework.

•    Official Documentation
•    Dropwizard Metrics
•    Developing RESTful Web Services Using Dropwizard
•    Build a RESTful stub server with Dropwizard
•    Official YAML Site

Share

Sign in to get new blogs and news first:

Leave a Reply

Dušan Simonović

Senior Java Inzenjer @Endava
mm

Graduated and completed Master studies at Faculty of technical sciences in Novi Sad on Microcomputer electronics department. Has 7+ years of experience in Java development and System administration and architecture.

At the moment, working for Endava Belgrade on Adobe Social Project as Senior Java Engineer and Scrum master.

As for previous larger projects, worked on a software solution for monitoring competitor pricing on online shops, Phonogram broadcasts recognition and reporting software and on an Intranet portal for a leading Swiss Travel operator.

Sign in to get new blogs and news first.

Categories