Hello World

Now that we have our Dropwizard microservice template ready to go, let’s add a REST endpoint. We want to expose an HTTP/REST endpoint at /api/hola that will return “Hola Dropwizard from X” where X is the IP address where the service is running. To do this, navigate to src/main/java/com/redhat/examples/dropwizard/resources (remember, this is the convention that Dropwizard follows for where to put REST resources) and create a new Java class called HolaRestResource. We’ll add a method named hola() that returns a string along with the IP address of where the service is running, as shown in Example 3-5.

Example 3-5. src/main/java/com/redhat/examples/dropwizard/ resources/HolaRestResource.java

public class HolaRestResource {

public String hola() throws UnknownHostException {

String hostname = null;

try {

hostname = InetAddress.getLocalHost() .getHostAddress();

} catch (UnknownHostException e) { hostname = "unknown";

}

return "Hola Dropwizard de " + hostname; }

}

Add the HTTP Endpoints

If this is familiar to what we did with Spring Boot, it’s for a reason. We want to be able to create REST endpoints and services with POJO code where possible, and a Hello World application is the perfect place to do that. To expose this as a REST service, we’re going to leverage good old JAX-RS annotations (see Example 3-6):

@Path

Tell JAX-RS what the context path for this service should be.

@GET

Add a GET HTTP service.

Example 3-6. src/main/java/com/redhat/examples/dropwizard/ HolaRestResource.java

@Path("/api")

public class HolaRestResource {

@Path("/hola")

@GET

public String hola() throws UnknownHostException {

String hostname = null;

try {

hostname = InetAddress.getLocalHost() .getHostAddress();

} catch (UnknownHostException e) { hostname = "unknown";

}

return "Hola Dropwizard de " + hostname;

}

}

Now, in our HolaDropwizardApplication class, let’s give the run() method an implementation to add our new REST resource to our microservice (Example 3-7).

Example 3-7. src/main/java/com/redhat/examples/dropwizard/

HolaDropwizardApplication.java

@Override

public void run(HolaDropwizardConfiguration configuration,

Environment environment) {

environment.jersey().register(new HolaRestResource()); }

Now we should be able to build and run our Dropwizard microservice:

$ mvn clean package exec:java

When we go to the endpoint at http://localhost:8080/api/holawe should see the following:

Externalize Configuration

Dropwizard has many options for configuring the built-in components (like the servlet engine or data sources for databases) as well as creating entirely new commands that you can run and configure with a configurations file. We can also inject environment variables and system properties for those types of configurations that expect to change based on the environment in which they’re running. Just like with Spring Boot, we can bind entire classes of properties to specific objects. In this example, let’s bind all of the helloapp.* properties to our HolaRestResource class. With Spring Boot we had the options to write our configs in property files with key-value tuples. We could have also used YAML. With Dropwizard, we only have the YAML option.

So let’s create a file in the root of our project called conf/application.yml (note, you’ll need to create the conf directory if it doesn’t exist). We put our configuration files in the conf folder to help us organize our project’s different configuration files (the naming of the directory is not significant (i.e., it does not have any conventional meaning to Dropwizard). Let’s add some configuration to our conf/application.yml file:

configurations for our sayingFactory helloapp: saying: Hola Dropwizard de

In this case, we’re setting the property to a specific value. What if we wanted to be able to override it based on some environment conditions? We could override it by passing in a Java system variable like this -Ddw.helloapp.saying=Guten Tag. Note that the dw.* part of the system property name is significant; it tells Dropwizard to apply the value to one of the configuration settings of our application. What if we wanted to override the property based on the value of an OS environment variable? That would look like Example 3-8.

Example 3-8. conf/application.yml

# configurations for our sayingFactory helloapp:

saying:${HELLOAPP_SAYING:-Guten Tag aus}

The pattern for the value of the property is to first look at an environment variable if it exists. If the environment variable is unset, then use the default value provided. We also need to tell our application specifically that we want to use environment-variable substitution. In the HolaDropwizardApplication class, edit the initialize() method to look like Example 3-9.

Example 3-9. src/main/java/com/redhat/examples/dropwizard/ HolaDropwizardApplication.java

@Override

public void initialize( Bootstrap<HolaDropwizardConfiguration> bootstrap) {

// Enable variable substitution with environment variables

bootstrap.setConfigurationSourceProvider( new SubstitutingSourceProvider(

bootstrap.getConfigurationSourceProvider(), new EnvironmentVariableSubstitutor(false)

)

);

}

Now we’ve set up our configuration, let’s build the backing object for it. We purposefully created a subconfiguration named helloapp which allows us to namespace our configs to organize them. We could have left it as a top-level configuration item, but since we didn’t, let’s see how we bind our application.yml file to our Dropwizard configuration objects.

Let’s create a new class called HelloSayingFactory in src/main/ java/com/redhat/examples/dropwizard/resources directory. Fill it out like this:

public class HelloSayingFactory {

@NotEmpty private String saying;

@JsonProperty public String getSaying() { return saying; }

@JsonProperty

public void setSaying(String saying) {

this.saying = saying;

}

}

This is a simple Java Bean with some validation (@NotEmpty, from the hibernate validators library) and Jackson (@JsonProperty) annotations. This class wraps whatever configurations are under our helloapp configuration in our YAML file; at the moment, we only have “saying.” When we first created our application, a HolaDropwi zardConfiguration class was created. Let’s open that class and add our new HelloSayingFactory, as shown in Example 3-10.

Example 3-10. src/main/java/com/redhat/examples/dropwizard/ HolaDropwizardConfiguration.java

public class HolaDropwizardConfiguration extends Configuration {

private HelloSayingFactory sayingFactory;

@JsonProperty("helloapp")

public HelloSayingFactory getSayingFactory() {

return sayingFactory; }

@JsonProperty("helloapp") public void setSayingFactory(

HelloSayingFactory sayingFactory) { this.sayingFactory = sayingFactory;

}

}

Lastly, we need to inject the configuration into our HolaRestRe source (Example 3-11).

Example 3-11. src/main/java/com/redhat/examples/dropwizard/ resources/HolaRestResource.java

@Path("/api")

public class HolaRestResource {

private String saying;

public HolaRestResource(final String saying) {

this.saying = saying; }

@Path("/hola")

@GET

public String hola() throws UnknownHostException {

String hostname = null;

try {

hostname = InetAddress.getLocalHost() .getHostAddress();

} catch (UnknownHostException e) { hostname = "unknown";

}

return saying + " " + hostname;

}

}

Since there is no magic dependency injection framework that you’re forced to use, you’ll need to update our HolaDropwizardApplica tion to inject the configurations to our REST Resource (Example 3-12).

Example 3-12. src/main/java/com/redhat/examples/dropwizard/

HolaDropwizardApplication.java

@Override

public void run(HolaDropwizardConfiguration configuration, Environment environment) {

environment.jersey().register( new HolaRestResource(configuration

.getSayingFactory()

.getSaying()));

}

Now we should have a fairly sophisticated configuration injectioncapability available to us. In this example, we purposefully made it slightly more complicated to cover what you’d probably do in a realworld use case. Also note, although the mechanics of hooking all of this up is more boilerplate, there’s a very clear pattern here: bind our Java objects to a YAML configuration file and keep everything very simple and intuitive without leveraging complex frameworks.

Let’s run our application. To do this, let’s update our pom.xml to pass our new conf/application.yml file, as shown in Example 3-13.

Example 3-13. pom.xml

<plugin>

<groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId>

<configuration>

<mainClass>

com.redhat.examples.dropwizard.HolaDropwizardApplication

</mainClass>

<arguments>

<argument>server</argument>

<argument>conf/application.yml</argument>

</arguments>

</configuration>

</plugin>

From the command line, we can now run:

$ mvn clean package exec:java

When you navigate to http://localhost:8080/api/hola, we should see one of the sayings:

If we stop the microservice, and export an environment variable, we should see a new saying:

$ export HELLOAPP_SAYING='Hello Dropwizard from'

$ mvn clean package exec:java

Expose Application Metrics and Information

The great thing about Dropwizard is metrics are first-class citizens, not an afterthought, and are already there! Metrics are enabled by default on the admin port (8081, by default) but how does Dropwizard know anything specific about our application? Let’s sprinkle a couple declarative annotations on our HolaRestResource (Example 3-14).

Example 3-14. src/main/java/com/redhat/examples/dropwizard/ resources/HolaRestResource.java

@Path("/hola")

@GET

@Timed

public String hola() throws UnknownHostException {

String hostname = null;

try {

hostname = InetAddress.getLocalHost().getHostAddress();

} catch (UnknownHostException e) { hostname = "unknown";

}

return saying + " " + hostname; }

We’ve added the @Timed annotation which tracks how long invocations to our service take. Other annotations for gathering metrics include: @Metered

The rate at which the service is called

@ExceptionMetered

The rate at which exceptions are thrown

Build and restart your microservice and try hitting your service at http://localhost:8080/api/holaa couple times. Then if you navigate to http://localhost:8081/metrics?pretty=true and scroll toward the bottom (may be different for yours), you should see the metrics for our service:

com.redhat.examples.dropwizard.resources.HolaRestResource.hola{

count: 3,

max: 0.0060773830000000004, mean: 0.002282724632345539, min: 0.000085167, p50: 0.0007421190000000001, p75: 0.0060773830000000004, p95: 0.0060773830000000004, p98: 0.0060773830000000004, p99: 0.0060773830000000004, p999: 0.0060773830000000004, stddev: 0.002676717391830948,

m15_rate: 0, m1_rate: 0, m5_rate: 0,

mean_rate: 0.12945390398989548, duration_units: "seconds", rate_units: "calls/second"

}

How to Run This Outside of Maven?

Dropwizard packages our microservice as a single executable uber JAR. All we have to do is build our application and run it like this:

$ mvn clean package

$ java -jar target/hola-dropwizard-1.0.jar \ server conf/application.yml

results matching ""

    No results matching ""