Dropwizard Tutorial: Develop RESTful Web Services Faster

What is Dropwizard?

Dropwizard is an open source Java framework used for the fast development of RESTful web services. Or better, it's a light-weight best-in-class set of tools and frameworks for building RESTful web services.

It's pretty easy to use, very maintainable and it has worked extremely well in many different cases and according to the official documentation:

"Its goal is to provide performant, reliable implementations of everything a production-ready web application needs. Because this functionality is extracted into a reusable library, your application remains lean and focused, reducing both time-to-market and maintenance burdens."

Dropwizard allows a developer to build an initial project very fast - a so-called quick bootstrap project. This helps the application to be packaged in a way that allows it to be easily installed on the production environment as a stand-alone service.

If you've ever been in a situation to develop a REST service in Spring for example, you probably know how hard it can be to set up a skeleton service (We will compare Dropwizard and Spring Boot approaches later on). With Dropwizard, it is a matter of literally adding one of the Maven dependency configurations.

Although, Dropwizard is not everyone's cup of tea, some people don't like using the components and libraries it provides, and that's perfectly fine.

Default Dropwizard Components

Dropwizard comes with the basic package of components or libraries needed to develop RESTful web services, so you don't need to include and configure each of them separately:

  • Jetty HTTP library: As we know, we need an HTTP server to start the Web application. Dropwizard uses the Jetty HTTP library to inject a tuned HTTP server directly into your project. 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. Dropwizard recommends the use of Jetty server to run applications, other servers such as Tomcat are not officially supported.

  • Jersey: is one of the best REST API implementations on the market. This allows you to create clean classes which map HTTP request to simple java objects. Also, it follows standard JAX-RSX specification, and Dropwizard uses it as the default tool for developing RESTful web applications.

  • Jackson: has certainly become a standard when it comes to data mapping objects to and from JSON. It is one of the best object mapping APIs for JSON format.

  • Metrics: Dropwizard has its own library, that allows us to read the application metrics through HTTP endpoints.

  • Guava: is Google's utility library that gives us a large number of classes to speed up development in Java.

  • Logback and Slf4j: These two libraries are used for logging, similar to JDK logging (java.util.logging)

  • Freemarker and Mustache: Choosing a template processor is one of the more important decisions. Dropwizard uses well-known and popular and processors to create user interfaces. 

  • Apache HttpClient: Provides the ability to interact with other web services.

  • Hibernate Validator: Used for validating user input.

  • Jdbi: Database access classes which have Hibernate support.

  • Joda time: Library for handling dates and time.

  • Liquidbase: Open source database-independent library for tracking, managing and applying database schema changes.

These are sort of the very core ingredients if you want to make a nice RESTful JSON serving Java service. Dropwizard combines it very nicely from an operations perspective. The Metrics piece is really important because not only does it provide metrics but it also alerts you if you're not implementing best operational practices, such as creating health checks.

Health checks are registered as part of application creation. Iif you don't register a health check, the startup will warn you and complain every single time you start up. I'll include this in an example later on.

Maven Configuration

Dropwizard officially supports Maven. You can use other build tools as well, although most of the guides and documentation use Maven. Maven is a project management tool, based on the concept of project object model (POM).

POM.xml contains all of the information about your project (project description, attributes, license, version, list of dependencies etc.)

We will define dropwizard.version, before adding the dependencies, in the <properties> tag in our "pom.xml":

<properties>  
  <dropwizard.version>1.3.5</dropwizard.version>
</properties>  

Add following dependencies to your pom.xml file:

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

You can add version number directly into <version> section for example:

<version>1.3.5<version>  

Upon successfully configuring Maven, we can start making our Dropwizard application.

Creating a Configuration Class

Each Dropwizard application stores the configuration in YAML files. We must create the "config.yml" file in the root directory of our application. This "yml" file will be deserialized to an instance of the Configuration class of our application. The configuration class of our application is a subclass of the Dropwizard configuration class (io.dropwizard.Configuration).

Configuration class:

public class DemoConfiguration extends Configuration {

    @NotEmpty
    private String message;

    @NotEmpty
    private String firstParameter;

    @NotEmpty
    private String secondParameter;

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

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

    public String getFirstParameter() {
        return firstParameter;
    }

    public void setFirstParameter(String firstParameter) {
        this.firstParameter = firstParameter;
    }

    public String getSecondParameter() {
        return secondParameter;
    }

    public void setSecondParameter(String secondParameter) {
        this.secondParameter = secondParameter;
    }
}

Now, for the "config.yml" file in the root directory of our application:

message: Hi %s!, now you will learn about %s from Stack Abuse!  
firstParameter: Friend  
secondParameter: Dropwizard  

The DemoConfiguration class will be deserialized from the YML file and the field values will be filled in as they are configured in it.

Creating an Application Class

The main application class should now be created. This class will pick up all the necessary modules and prepare our service for use. 

Here's a simple example of the application class:

DemoApplication:

public class DemoApplication extends Application<DemoConfiguration> {

    public static void main(String[] args) throws Exception {
        new DemoApplication().run(new String[] {"server", "config.yml"});
    }

    public void run(DemoConfiguration configuration, Environment environment) {
        // code to register module
    }
}

Creating a Representation Class

Now we should consider our REST API service and how the resources will be represented. We need to design the JSON format and define the appropriate representation class to ensure that the data is in the desired format:

{
    "content": "Hi Friend! Now you will learn about Dropwizard from Stack Abuse!"
}

To achieve this format, we will use the following implementation of the Representation class:

Representation:

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 a simple POJO model. Our class uses the Java Bean standard for the content property. This allows Jackson to serialize it to the JSON we need.

The Jackson object mapping code will populate the content field of the JSON object with the return value of getContent().

Creating a Resource Class

Resources are the essence of Dropwizard. The resources are actually the definitions of the endpoint URI of our service that can be accessed via the HTTP protocol. In this example, we will create a resource class with a pair of annotations for mapping HTTP requests.

Since Dropwizard uses the JAX-RS implementation, we will use the @Path annotation to define the path:

DemoResource:

@Path("/v1/resource")
@Produces(MediaType.APPLICATION_JSON)
public class DemoResource {

    private final String message;
    private final String firstParameter;
    private final String secondParameter;

    public DemoResource(String message, String firstParameter, String secondParameter) {
        this.message = message;
        this.firstParameter = firstParameter;
        this.secondParameter = secondParameter;
    }

    @GET
    @Timed
    public Representation getMessage(@QueryParam("first") Optional<String> first, @QueryParam("second") Optional<String> second) {
        final String value = String.format(message, first.or(firstParameter), second.or(secondParameter));
        return new Representation(value);
    }
}

@Timed is used for automatically recording the duration and rate of its invocations as a Metrics Timer.

Registering a Resource

It is now necessary to register the class above in the main class of the application. As mentioned above, the application class serves to initialize our service and all necessary modules, so all resources need to be registered here to be initialized with the service.

In the main application class, add the following:

@Override
public void run(DemoConfiguration configuration, Environment environment) {  
    final DemoResource resource = new DemoResource(configuration.getMessage(),
            configuration.getFirstParameter(), configuration.getSecondParameter());
    environment.jersey().register(resource);
}

Building a Dropwizard Application

It is a good idea to create a so-called FAT JAR that will contain all the necessary ".class" files needed to run the application. This JAR can be deployed to the different environment from testing to production without any changes.

To make our JAR we need to configure the Maven plugin maven-shade. The following configuration should be added to our "pom.xml", under the dependencies section:

    <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.dropwizard.DemoApplication</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

Running your Application

Now we should be able to launch our application. If you have successfully build your JAR, you can run from the command line:

$ java –jar target/dropwizard-demo-1.0.SNAPSHOT.jar server config.yml

or direct from your IDE - by running the DemoApplication main class:

mainClass

If everything started correctly, you should be prompted with something like this:

outputLog

Now, your Dropwizard application is listening on port 8080 for application requests and port 8081 for administration requests. You will notice that we used the arguments server and config.yml to run the service, telling the server what configuration file to use.

This can also be done in the main method of DemoApplication class, like in the example above.

You can access your application at http://localhost:8080/v1/resource or with parameters http://localhost:8080/v1/resource?first=John&second=everything.

You should receive a message with or without forwarded parameters, depending on your call.

Changing the Context Path

By default, the Dropwizard app will run its endpoints on /path. Therefore, if you do not mention any context path for your application, it is assumed that the application can be accessed at http://localhost:8080. However, if you want to change this, you can configure a different path by adding the following to your YML file:

server:  
    applicationContextPath: /application

Adding a Health Check

Regarding the earlier statement about the Metrics framework enforcing health checks:

Health Checks are simply just HTTP endpoints that iterate over various hooks that you create. While some give in to the temptation to return a Health Check that always returns a "healthy" status, as long as the service is running, this is really bad practice.

Health Checks should be used to improve code, for an example: If you have a database, you must be able to provide a connection to the database. Put a health check there, make sure that the database doesn't have too many client connections, or any thread dead locks, etc.

Let's create our HealthCheck class:

DemoHealthCheck:

For the sake of the tutorial, we'll keep this simple. In working environments, these checks would look different, but they mostly revolve around checking cases, similar to this:

public class DemoHealthCheck extends HealthCheck {

    @Override
    protected Result check() throws Exception {
        final String field = "Dropwizard";
        if (field.equalsIgnoreCase("Dropwizard")) {
            return Result.healthy();
        }
        return Result.unhealthy("Error, not Healthy!");
    }
}

Like before, we now register our HealthCheck class in the main class of the application.

DemoApplication:

@Override
public void run(DemoConfiguration configuration, Environment environment) {  
    final DemoResource resource = new DemoResource(configuration.getMessage(),
            configuration.getFirstParameter(), configuration.getSecondParameter());
    final DemoHealthCheck healthCheck = new DemoHealthCheck();
    environment.healthChecks().register("Dropwizard", healthCheck);
    environment.jersey().register(resource);
}

Now, when you start your application your console log output won't complain to you about the health checks.

Differences Between Dropwizard and Spring Boot Approaches

Both are really easy to learn and get started within hours of writing your first application.

/ Dropwizard Spring Boot
HTTP Jetty Tomcat
REST Jersey Spring, JAX-RS
JSON Jackson Jackson, GSON, json-simple
Metrics Dropwizard metrics Spring
Health Checks Dropwizard Spring
Logging Logback, slf4j Logback, Log4j, slf4j, Apache commong-logging
Testing dropwizard-testing (Junit, Mockito) spring-boot-starter-test (JUnit, Mockito)
Official Integrations Hibernate validator, Guava, Apache HttpClient, Jersey client, JDBI, Liquibase, Mustache, Freemaker, Joda time 40+ official Starter POM for any purpose

Conclusion

With our application up and running, we can give some key notes of using Dropwizard for developing RESTful web services.

Dropwizard is production-focused, easy to use, simple to deploy, simple to monitor, develop and set-up a high-performance REST framework.

Maybe one of the biggest advantages is that offers an incredibly fast bootstrap setup for your project. With an included set of tools and libraries to satisfy the need for most developers, you don't have to worry about adding and configuring each of them separately.

Some disadvantages would be that you are kind of restricted to using what Dropwizard offers or supports (losing freedom), but also by adding too many third-party libraries can cause unnecessary complexity in the development.

Author image
About Vuk Skobalj