REST Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE
Java Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

1. Overview

Dropwizard is an open-source Java framework used for the fast development of high-performance RESTful web services. It gathers some popular libraries to create the light-weight package. The main libraries that it uses are Jetty, Jersey, Jackson, JUnit, and Guava. Furthermore, it uses its own library called Metrics.

In this tutorial, we'll learn how to configure and run a simple Dropwizard application. When we're done, our application will expose a RESTful API that allows us to obtain a list of stored brands.

2. Maven Dependencies

Firstly, the dropwizard-core dependency is all we need in order to create our service. Let's add it to our pom.xml:

<dependency>
    <groupId>io.dropwizard</groupId>
    <artifactId>dropwizard-core</artifactId>
    <version>2.0.0</version>
</dependency>

3. Configuration

Now, we'll create the necessary classes that are needed for every Dropwizard application to run.

Dropwizard applications store properties in YML files. Therefore, we'll create the introduction-config.yml file in the resource directory:

defaultSize: 5

We can access values in that file by creating a class that extends io.dropwizard.Configuration:

public class BasicConfiguration extends Configuration {
    @NotNull private final int defaultSize;

    @JsonCreator
    public BasicConfiguration(@JsonProperty("defaultSize") int defaultSize) {
        this.defaultSize = defaultSize;
    }

    public int getDefaultSize() {
        return defaultSize;
    }
}

Dropwizard uses Jackson to deserialize the configuration file into our class. Hence, we've used Jackson annotations.

Next, let's create the main application class, which is responsible for preparing our service for usage:

public class IntroductionApplication extends Application<BasicConfiguration> {

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

    @Override
    public void run(BasicConfiguration basicConfiguration, Environment environment) {
        //register classes
    }

    @Override
    public void initialize(Bootstrap<BasicConfiguration> bootstrap) {
        bootstrap.setConfigurationSourceProvider(new ResourceConfigurationSourceProvider());
        super.initialize(bootstrap);
    }
}

Firstly, the main method is responsible for running the application. We could either pass the args to the run method or fill it by ourselves.

The first argument can be either server or check. The check option validates the configuration, while the server option runs the application. The second argument is the location of the configuration file. 

Furthermore, the initialize method sets the configuration provider to the ResourceConfigurationSourceProvider, which allows the application to find a given configuration file in the resource directory. It isn't obligatory to override this method.

Lastly, the run method allows us to access both the Environment and the BaseConfiguration, which we'll use later in this article.

4. Resource

Firstly, let's create a domain class for our brand:

public class Brand {
    private final Long id;
    private final String name;

    // all args constructor and getters
}

Secondly, let's create a BrandRepository class that'll be responsible for returning brands:

public class BrandRepository {
    private final List<Brand> brands;

    public BrandRepository(List<Brand> brands) {
        this.brands = ImmutableList.copyOf(brands);
    }

    public List<Brand> findAll(int size) {
        return brands.stream()
          .limit(size)
          .collect(Collectors.toList());
    }

    public Optional<Brand> findById(Long id) {
        return brands.stream()
          .filter(brand -> brand.getId().equals(id))
          .findFirst();
    }
}

Additionally, we were able to use the ImmutableList from Guava because it's part of Dropwizard itself.

Thirdly, we'll create a BrandResource class. The Dropwizard uses JAX-RS by default with Jersey as implementation. Therefore, we'll make use of annotations from this specification to expose our REST API endpoints:

@Path("/brands")
@Produces(MediaType.APPLICATION_JSON)
public class BrandResource {
    private final int defaultSize;
    private final BrandRepository brandRepository;

    public BrandResource(int defaultSize, BrandRepository brandRepository) {
        this.defaultSize = defaultSize;
        this.brandRepository = brandRepository;
    }

    @GET
    public List<Brand> getBrands(@QueryParam("size") Optional<Integer> size) {
        return brandRepository.findAll(size.orElse(defaultSize));
    }

    @GET
    @Path("/{id}")
    public Brand getById(@PathParam("id") Long id) {
        return brandRepository
          .findById(id)
          .orElseThrow(RuntimeException::new);
    }
}

Additionally, we've defined size as Optional in order to use defaultSize from our configuration if the argument is not provided.

Lastly, we'll register BrandResource in the IntroductionApplicaton class. In order to do that, let's implement the run method:

@Override
public void run(BasicConfiguration basicConfiguration, Environment environment) {
    int defaultSize = basicConfiguration.getDefaultSize();
    BrandRepository brandRepository = new BrandRepository(initBrands());
    BrandResource brandResource = new BrandResource(defaultSize, brandRepository);

    environment
      .jersey()
      .register(brandResource);
}

All created resources should be registered in this method.

5. Running Application

In this section, we'll learn how to run the application from the command line.

First, we'll configure our project to build a JAR file using the maven-shade-plugin:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <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.baeldung.dropwizard.introduction.IntroductionApplication</mainClass>
                    </transformer>
                </transformers>
            </configuration>
        </execution>
    </executions>
</plugin>

This is the suggested configuration of the plugin. Additionally, we've included the path to our main class in the <mainClass> element.

Finally, we'll build the application with Maven. Once we have our JAR file, we can run the application:

java -jar target/dropwizard-0.0.1-SNAPSHOT.jar

There's no need to pass the parameters because we've already included them in the IntroductionApplication class.

After that, the console log should end with:

INFO  [2020-01-08 18:55:06,527] org.eclipse.jetty.server.Server: Started @1672ms

Now, the application is listening on port 8080, and we can access our brand endpoint at http://localhost:8080/brands.

6. Health Check

When starting the application, we were informed that the application doesn't have any health checks. Fortunately, Dropwizard provides an easy solution to add health checks to our application.

Let's start by adding a simple class that extends com.codahale.metrics.health.HealthCheck:

public class ApplicationHealthCheck extends HealthCheck {
    @Override
    protected Result check() throws Exception {
        return Result.healthy();
    }
}

This simple method will return information about the healthiness of our component. We could create multiple health checks, and some of them might fail in certain situations. For instance, we would return Result.unhealthy() if the connection to the database failed.

Lastly, we need to register our health check in the run method of our IntroductionApplication class:

environment
  .healthChecks()
  .register("application", new ApplicationHealthCheck());

After running the application, we can check the health check response under http://localhost:8081/healthcheck:

{
  "application": {
    "healthy": true,
    "duration": 0
  },
  "deadlocks": {
    "healthy": true,
    "duration": 0
  }
}

As we can see, our health check has been registered under the application tag.

7. Conclusion

In this article, we've learned how to set up the Dropwizard application with Maven.

We've discovered that the base setup of the application is really easy and fast. Additionally, Dropwizard includes every library that we need to run the high-performance RESTful web service.

As always, the code for these examples is available over on GitHub.

REST bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE
Java bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE
Comments are closed on this article!