Java: Basic Dropwizard Project

This entry is part 1 of 5 in the series Dropwizard

This tutorial will guide you through how to create a bare bones Dropwizard app. Ensure you have Eclipse installed or whatever IDE you are deciding to use. You can use their documentation as a guide. This is the first tutorial in the dropwizard series.

Setup Eclipse Archetype:

Select new Maven Project then in the select Archetype if dropwizard isn’t there you can add it by using the below settings.

Filter for Dropwizard Archetype:

Set Project Settings:

POM:

Ensure the pom has the correct “dropwizard.version” and that the dependency “dropwizard-core” is there.

Our Configuration:

Now that the project is created let’s have a look at what our configuration looks like. Pretty basic but that’s all we need right now.

package ca.gaudreault.mydropwizardapp;

import io.dropwizard.Configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.hibernate.validator.constraints.*;
import javax.validation.constraints.*;

public class MyDropwizardAppConfiguration extends Configuration {
    
}

Our Application:

This is what our application class looks like. It’s empty nothing yet.

package ca.gaudreault.mydropwizardapp;

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

public class MyDropwizardAppApplication extends Application {

    public static void main(final String[] args) throws Exception {
        new MyDropwizardAppApplication().run(args);
    }

    @Override
    public String getName() {
        return "MyDropwizardApp";
    }

    @Override
    public void initialize(final Bootstrap bootstrap) {

    }

    @Override
    public void run(final MyDropwizardAppConfiguration configuration,
                    final Environment environment) {

    }
}

Config.yml:

This is what our config.yml file looks like at the start.

logging:
  level: INFO
  loggers:
    ca.gaudreault: DEBUG

Setup Debug Configuration:

Setup your debug configuration like the below setup.

Running:

Once you run it you will be running two sites.

  1. http://localhost:8080
    1. Your main site
  2. http://localhost:8081
    1. Your operational site (health, etc)

Dropwizard: Guice Bundle

This entry is part 2 of 5 in the series Dropwizard

In this tutorial I will show you how to add Guice to your Dropwizard app. This will be a very basic implementation. Some things you should note is that I didn’t put in any docstrings. You should always do that!

Now there are a few Dropwizard Guice integrations available but the most active is the one I will show you today called “dropwizard-guicey“.

POM.xml

<dependency>
	<groupId>ru.vyarus</groupId>
	<artifactId>dropwizard-guicey</artifactId>
	<version>4.1.0</version>
</dependency>

Model

Now we create a model to use with our service

package ca.gaudreault.mydropwizardapp.models;

import java.io.Serializable;

import javax.validation.constraints.NotNull;

public class MyModel implements Serializable {
	private static final long serialVersionUID = 1L;
	private Integer value;
	
	public Integer getValue() {
		return value;
	}
	public void setValue(Integer value) {
		this.value = value;
	}
}

Service

Here you will create your service interface and class so that you can bind it in the guice module.

Interface

package ca.gaudraeult.mydropwizardapp.services;

import ca.gaudreault.mydropwizardapp.models.MyModel;

public interface MyService {
	MyModel runTest();
}

Implementation

package ca.gaudraeult.mydropwizardapp.services;

import ca.gaudreault.mydropwizardapp.models.MyModel;

public class MyServiceImpl implements MyService {
	
	public MyServiceImpl() { }

	@Override
	public MyModel runTest() {
		final MyModel myModel = new MyModel();
		myModel.setValue(123123);
		return myModel;
	}
}

ServerModule

Now when we create our module class you can bind the interface to the implementation. Note that if your implementation does not implement the interface this will not work.

package ca.gaudreault.mydropwizardapp;

import com.google.inject.AbstractModule;

import ca.gaudraeult.mydropwizardapp.services.MyService;
import ca.gaudraeult.mydropwizardapp.services.MyServiceImpl;

public class ServerModule extends AbstractModule  {

	@Override
	protected void configure() {
		bind(MyService.class).to(MyServiceImpl.class);
	}
}

Dropwizard Application

If you remember from part 1 of this series you created the based Dropwizard app. So you should have a class called “MyDropwizardAppApplication”. Open that now and modify the “initialize” like the below. Baseically here we are registering our ServerModule class to Dropwizard.

@Override
public void initialize(final Bootstrap bootstrap) {
	bootstrap.addBundle(GuiceBundle.builder()
		.enableAutoConfig(this.getClass().getPackage().getName())
		.modules(new ServerModule())
		.build());
}

And that is it you have configured a very basic Dropwizard Guice configuration.

Dropwizard: Command

This entry is part 3 of 5 in the series Dropwizard

In this tutorial I will give a brief demonstration on how to write a custom dropwizard command.

MyCommand

So below you will see the command class and how we are creating and registering a command line param called “test” which is a Boolean.

package ca.gaudreault.mydropwizardapp;

import io.dropwizard.cli.Command;
import io.dropwizard.setup.Bootstrap;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;

public class MyCommand extends Command {

	protected MyCommand() {
		super("myCommand", "This is a sample command");
	}

	@Override
	public void configure(Subparser subparser) {
	    subparser.addArgument("-test").required(true).type(Boolean.class).dest("test").help("Does something really awesome");
	}

	@Override
	public void run(Bootstrap<?> bootstrap, Namespace namespace) throws Exception {
		System.out.println("MyCommand " + namespace.getBoolean("test"));
	}
}

MyDropwizardAppApplication

If you remember from part 1 of this series you created the based Dropwizard app. So you should have a class called “MyDropwizardAppApplication”. Open that now and modify the “initialize” like the below. Note that we are only adding the “addCommand”.

@Override
public void initialize(final Bootstrap bootstrap) {
	bootstrap.addCommand(new MyCommand());
}

Executing Command

Basically now we can just call our JAR file and pass the following arguments to it.

myCommand -test false

You will see once it runs that following

MyCommand false

Dropwizard: Resource

This entry is part 4 of 5 in the series Dropwizard

In this tutorial I will give a basic example of a resource endpoint. If you haven’t configured Guice yet please do so before continuing.

So basically now that you have Guice configured and working you can now create an api endpoint. For this we will just use a GET but you can also do POST, PUT, DELETE.

package ca.gaudreault.mydropwizardapp.resources;

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

import com.codahale.metrics.annotation.Timed;
import com.google.inject.Inject;

import ca.gaudraeult.mydropwizardapp.services.MyService;
import ca.gaudreault.mydropwizardapp.models.MyModel;

@Timed
@Path("/my-resource")
public class MyResource {
	MyService myService;

	@Inject
	public MyResource(final MyService myService) {
		this.myService = myService;
	}

	@GET
	@Timed
	@Produces(MediaType.APPLICATION_JSON)
	public MyModel runTest() {
		return this.myService.runTest();
	}
}

Once you run your application you can view the endpoint by going to http://localhost:8080/my-resource.

The output will be as follows.

{"value":123123}

If you noticed we added the “@Timed” annotation. You can now go to http://localhost:8081/metrics?pretty=true to view the metrics on our “runTest” method. The output will look like the below.

{
	"ca.gaudreault.mydropwizardapp.resources.MyResource.runTest": {
		"count": 0,
		"max": 0.0,
		"mean": 0.0,
		"min": 0.0,
		"p50": 0.0,
		"p75": 0.0,
		"p95": 0.0,
		"p98": 0.0,
		"p99": 0.0,
		"p999": 0.0,
		"stddev": 0.0,
		"m15_rate": 0.0,
		"m1_rate": 0.0,
		"m5_rate": 0.0,
		"mean_rate": 0.0,
		"duration_units": "seconds",
		"rate_units": "calls/second"
}

Dropwizard: Swagger Integration

This entry is part 5 of 5 in the series Dropwizard

In this tutorial I will show you how to use Swagger in your Maven application. I will also show you how to configure it with Swagger UI so when you start your application you can see the Swagger UI from your generated JSON.

POM.xml

Dependencies

<dependency>
	<groupId>io.dropwizard</groupId>
	<artifactId>dropwizard-assets</artifactId>
	<version>1.3.2</version>
</dependency>

<dependency>
	<groupId>io.swagger</groupId>
	<artifactId>swagger-jaxrs</artifactId>
	<version>1.5.19</version>
</dependency>

Plugins

maven-jar-plugin

If you followed creating a basic Dropwizard app then you should have this already installed. If so then just add the following two configs under “manifest” section.

<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
maven-clean-plugin

Because we are pulling the latest Swagger-UI code on each build we must clean the old build.

<plugin>
	<artifactId>maven-clean-plugin</artifactId>
	<version>3.1.0</version>
	<configuration>
		<filesets>
			<fileset>
				<directory>${basedir}/src/main/resources/swagger-ui</directory>
				<followSymlinks>false</followSymlinks>
			</fileset>
		</filesets>
	</configuration>
</plugin>
download-maven-plugin

We are downloading the latest Swagger-UI code from github. Notice how lifecycle phase “generate-resources” is used. This is important due to build getting the proper code before beginning build.

<plugin>
	<groupId>com.googlecode.maven-download-plugin</groupId>
	<artifactId>download-maven-plugin</artifactId>
	<version>1.4.0</version>
	<executions>
		<execution>
			<id>swagger-ui</id>
			<phase>generate-resources</phase>
			<goals>
				<goal>wget</goal>
			</goals>
			<configuration>
				<url>
					https://github.com/swagger-api/swagger-ui/archive/master.tar.gz
				</url>
				<unpack>true</unpack>
				<outputDirectory>
					${project.build.directory}
				</outputDirectory>
			</configuration>
		</execution>
	</executions>
</plugin>
replacer

This updates the code downloaded from github to have your swagger.json content instead of the petstore swagger content. Notice how lifecycle phase “generate-resources” is used. This is important due to build getting the proper code before beginning build.

<plugin>
	<groupId>com.google.code.maven-replacer-plugin</groupId>
	<artifactId>replacer</artifactId>
	<version>1.5.3</version>
	<executions>
		<execution>
			<phase>generate-resources</phase>
			<goals>
				<goal>replace</goal>
			</goals>
		</execution>
	</executions>
	<configuration>
		<includes>
			<include>${project.build.directory}/swagger-ui-master/dist/index.html</include>
			<include>${project.build.directory}/swagger-ui-master/dist/swagger-ui-bundle.js</include>
			<include>${project.build.directory}/swagger-ui-master/dist/swagger-ui-bundle.js.map</include>
			<include>${project.build.directory}/swagger-ui-master/dist/swagger-ui-standalone-preset.js</include>
			<include>${project.build.directory}/swagger-ui-master/dist/swagger-ui-standalone-preset.js.map</include>
			<include>${project.build.directory}/swagger-ui-master/dist/swagger-ui.js</include>
			<include>${project.build.directory}/swagger-ui-master/dist/swagger-ui.js.map</include>
		</includes>
		<replacements>
			<replacement>
				<token>http://petstore.swagger.io/v2/swagger.json</token>
				<value>/swagger.json</value>
			</replacement>
		</replacements>
	</configuration>
</plugin>
maven-resources-plugin

This will copy the content that you just downloaded and modified into your resources folder. Notice how lifecycle phase “generate-resources” is used. This is important due to build getting the proper code before beginning build.

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-resources-plugin</artifactId>
	<version>3.1.0</version>
	<executions>
		<execution>
			<id>copy-resources</id>
			<phase>generate-resources</phase>
			<goals>
				<goal>copy-resources</goal>
			</goals>
			<configuration>
				<outputDirectory>
					${basedir}/src/main/resources/swagger-ui
				</outputDirectory>
				<resources>
					<resource>
						<directory>
							${project.build.directory}/swagger-ui-master/dist
						</directory>
					</resource>
				</resources>
			</configuration>
		</execution>
	</executions>
</plugin>

Now if you run the following command you will see that the swagger-ui copied to your resources folder.

mvn clean install

MyDropwizardAppApplication

initialize

Now we need to configure our Dropwizard app to host the swagger-ui that we recently downloaded and modified. In our “MyDropwizardAppApplication” class that we created in the initial Dropwizard tutorial we must add the AssetsBundle for our swagger-ui.

@Override
public void initialize(final Bootstrap bootstrap) {
	bootstrap.addBundle(GuiceBundle.builder().enableAutoConfig(this.getClass().getPackage().getName())
			.modules(new ServerModule()).build());

	// This allows you to host swagger ui on this dropwizard app's host
	final AssetsBundle assetsBundle = new AssetsBundle("/swagger-ui", "/swagger-ui", "index.html");
	bootstrap.addBundle(assetsBundle);
	bootstrap.addCommand(new MyCommand());
}
run

Now we need to setup our Swagger scanners for our api and our models.

@Override
public void run(final MyDropwizardAppConfiguration configuration, final Environment environment) {
	this.initSwagger(configuration, environment);
}

private void initSwagger(MyDropwizardAppConfiguration configuration, Environment environment) {
	// Swagger Resource
	// The ApiListingResource creates the swagger.json file at localhost:8080/swagger.json
	environment.jersey().register(new ApiListingResource());
	environment.jersey().register(SwaggerSerializers.class);

	Package objPackage = this.getClass().getPackage();
	String version = objPackage.getImplementationVersion();

	// Swagger Scanner, which finds all the resources for @Api Annotations
	ScannerFactory.setScanner(new DefaultJaxrsScanner());

	//This is what is shown when you do "http://localhost:8080/swagger-ui/"
	BeanConfig beanConfig = new BeanConfig();
	beanConfig.setVersion(version);
	beanConfig.setSchemes(new String[] { "http" });
	beanConfig.setHost("localhost:8080");
	beanConfig.setPrettyPrint(true);
	beanConfig.setDescription("The drpowizard apis");
	beanConfig.setResourcePackage("ca.gaudreault.mydropwizardapp");
	beanConfig.setScan(true);
}

Now if we were to run our app we would be able to go to http://localhost:8080/swagger-ui/ and we would see our content but since we didn’t update any model or api then we wouldn’t see much of anything. So remember the previous tutorials on Dropwizard Guice and Dropwizard Resource. We will update those now.

Model

If you compare this to the one we did in the guice tutorial there are only a few differences. Notice we import the swagger annotations. We then add “ApiModel” annotation to the class and “ApiModelProperty” to the variable “value” and set it to be “NotNull”.

package ca.gaudreault.mydropwizardapp.models;

import java.io.Serializable;

import javax.validation.constraints.NotNull;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

@ApiModel(description = "My Example Model.")
public class MyModel implements Serializable {
	private static final long serialVersionUID = 1L;
	@NotNull
	@ApiModelProperty(required = true, notes = "My value")
	private Integer value;
	
	public Integer getValue() {
		return value;
	}
	public void setValue(Integer value) {
		this.value = value;
	}
}

Resource

If you compare this to the one we did in the guice tutorial there are only a few differences. Notice our class has “@SwaggerDefinition” and “@API” defined. This will help the Swagger-UI  group your end points together using the tags. Also notice how our “runTest” end point has “@Path”, “@ApiResponses” and “@ApiOperation” now.

package ca.gaudreault.mydropwizardapp.resources;

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

import org.eclipse.jetty.http.HttpStatus;

import com.codahale.metrics.annotation.Timed;
import com.google.inject.Inject;

import ca.gaudreault.mydropwizardapp.models.MyModel;
import ca.gaudreault.mydropwizardapp.services.MyService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponses;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.SwaggerDefinition;
import io.swagger.annotations.Tag;

@SwaggerDefinition(tags = { @Tag(name = "MyResource", description = "My Example Resource") })
@Api(value = "MyResource")
@Timed
@Path("/my-resource")
public class MyResource {
	private MyService myService;

	@Inject
	public MyResource(final MyService myService) {
		this.myService = myService;
	}

	@GET
	@Path("/runTest")
	@ApiOperation(value = "Run test and returns myModel", notes = "Run test and returns myModel", response = MyModel.class, tags = {
			"MyResource" })
	@ApiResponses(value = {
			@ApiResponse(code = HttpStatus.OK_200, message = "Successfully Tested", response = MyModel.class) })
	@Timed
	@Produces(MediaType.APPLICATION_JSON)
	public MyModel runTest() {
		return this.myService.runTest();
	}
}

Run our Project

If we run our project and we hit the following rest end point http://localhost:8080/my-resource/runTest we will get back the below. This shows us our rest end point is working as expected still.

{"value":123123}

Checking Swagger-UI

Now that we have started our project we can now check to see what was generated. Go to Swagger-UI. You will see the below. You are now well on your way in using Swagger.

Model Expanded

Resource Expanded

 

 

 

 

References

The following helped me build this tutorial.

  • https://robferguson.org/blog/2016/12/11/resteasy-embedded-jetty-fat-jars-swagger-and-swagger-ui/
  • https://itazuramono.com/2015/12/07/automatic-swagger-documentation-for-dropwizard-using-maven/
  • http://mikelynchgames.com/software-development/adding-swagger-to-your-dropwizard-application/