Configuring the Application - RESTful Web Services with Dropwizard (2014)

RESTful Web Services with Dropwizard (2014)

Chapter 3. Configuring the Application

Up until this point, we have created a simple template for a Dropwizard application. What our application does is print a message to the terminal during startup.

Generally, every modern application depends on a number of configuration settings that define the way it runs. For instance, once our application grows and needs to interact with a database, we should somehow use (at least) a username and password to establish a database connection. Of course, we can hardcode these settings inside the application, but that's not efficient, as even a small change would require rebuilding it. The appropriate way of storing such or similar information is by using an external configuration file.

Externalizing the application's configuration

Using a configuration file requires the appropriate application logic to load and parse it. Luckily, Dropwizard has built-in functionality that we will use in order to externalize our application's configuration.

How to do it…

1. Create a new YAML file named config.yaml in the same directory as the pom.xml file. This will be the configuration file of our application. We will add two configuration parameters: the message to be printed on startup and how many times to print it. In order to do so, add the following code to config.yaml:

2. message: This is a message defined in the configuration file config.yaml.

messageRepetitions: 3

3. Now we have a configuration file, but we need to parse it. Let's create a new class in the com.dwbook.phonebook package named PhonebookConfiguration by adding the following code:

4. package com.dwbook.phonebook;

5.

6. import com.fasterxml.jackson.annotation.JsonProperty;

7. import io.dropwizard.Configuration;

8.

9. public class PhonebookConfiguration extends Configuration {

10. @JsonProperty

11. private String message;

12.

13. @JsonProperty

14. private int messageRepetitions;

15.

16. public String getMessage() {

17. return message;

18. }

19.

20. public int getMessageRepetitions() {

21. return messageRepetitions;

22. }

}

Note

As you can see, it is a simple class, with two member properties named after our configuration settings along with their getter methods.

23. To use this class as our configuration proxy, modify the declaration of our main App class to extend the Application<PhonebookConfiguration> class instead of Application<Configuration>:

public class App extends Application<PhonebookConfiguration> {

24. Similarly, update configuration to PhonebookConfiguration in the declaration of the App#initialize() method:

25.@Override

26.

public void initialize(Bootstrap<PhonebookConfiguration> b) {}

27. The App#run() method will require the same modification in its definition, but we'll also modify this method further so it retrieves the message to print from the configuration class:

28.public void run(PhonebookConfiguration c, Environment e)

29. throws Exception {

30. LOGGER.info("Method App#run() called");

31. for (int i=0; i < c.getMessageRepetitions(); i++) {

32. System.out.println(c.getMessage());

33. }

}

34. Package (mvn package) and run the application and specify the configuration file as well:

$ java -jar target/dwbook-phonebook-1.0-SNAPSHOT.jar server config.yaml

You will see the message printed three times in your terminal during the application's startup, as shown in the following screenshot:

How to do it…

Apart from this, and as in the previous example, you will also see an exception stating that no resource classes could be located (the ResourceConfig instance does not contain any root resource classes). This is because we do not have any REST resources registered in our application yet. We will deal with this in the following chapter.

How it works…

You should see that our configuration file is automatically parsed. In fact, the PhonebookConfiguration class is instantiated with the values specified in the configuration file.

When a configuration file is passed as a command-line argument, Dropwizard parses it and creates an instance of your service's configuration class. We added the required configuration parameters as private members of the PhonebookConfiguration class and annotated them with @JsonProperty so Dropwizard can parse them. In order to make these properties accessible to our application's service class, we also need to add public getters for these parameters.

There's more…

Externalizing your application's configuration has many advantages. With Dropwizard, you can easily store and read any kind of properties (configuration settings) you wish to have for your application with minimum effort, just by mapping YAML properties to the properties of your configuration class.

Dropwizard's configuration parameters

Dropwizard has plenty of configuration parameters available, such as the port that the embedded Jetty listens to and the logging level. The list is quite large and cannot be covered here extensively, though it is available on the official Dropwizard website athttp://www.dropwizard.io/manual/core/#configuration-defaults.

YAML

The description of YAML according to its official website (http://www.yaml.org) is human-friendly data serialization standard. Its syntax is pretty straightforward, which is also the reason why YAML is widely accepted. YAML files are identified by the extensions .yamland .yml; both are valid, although .yml seems to be more popular lately.

Validating configuration settings

Although it is good to have the application's configuration externalized, we should not always rely on it as is. Dropwizard has got us covered, and we have the right tools in order to validate the configuration properties up on the application's startup. This is because we can use constraint annotations for our configuration properties, such as those included in the javax.validation.constraints or org.hibernate.validator.constraints packages.

We are going to limit the number of repetitions of the message to 10; if the number provided is larger than 10, then the input is considered invalid.

How to do it…

Let's go through the following steps required for validating the configuration settings:

1. Update the definition of the messageRepetitions property in PhonebookConfiguration, annotating the property with the @Max annotation (you will also need to import javax.validation.constraints.Max):

2. @JsonProperty

3. @Max(10)

private int messageRepetitions;

4. In a similar way, define that the message property should not be empty, annotating the property with the @NotEmpty (org.hibernate.validator.constraints.NotEmpty) annotation:

5. @JsonProperty

6. @NotEmpty

private String message;

7. Edit the Config.yaml file and specify a value greater than 10 for the messageRepetitions property.

8. Repackage and run the application again. The application will refuse to start, and you will see an error printed on your terminal as seen in the following screenshot:

How to do it…

How it works…

The validation-related annotations force Dropwizard to validate the values of each of the properties declared in our configuration file. If the validation constraints are not satisfied, the relevant error message will be printed on the terminal, and the application will not start.

There's more…

Now you have a working configuration file that is mapped on the configuration object during the startup of the application. Also, as well as checking the validity of the configuration parameters, you can also provide a default value for each one of them.

Specifying default parameters

You can specify the default values for configuration parameters as easily as initializing the variables on their declaration. This way, optional parameters can be omitted and can have a default value during runtime, even if they're not included in the application's configuration file.

Let's add an additional parameter, which we'll also initialize, named additionalMessage, along with its getter method:

@JsonProperty

private String additionalMessage = "This is optional";

public String getAdditionalMessage() {

return additionalMessage;

}

If you run the application specifying a configuration file that does not contain the additionalMessage property, then the default value of this property will be returned when you try to access it from another part of the code, for instance, if you use c.getAdditionalMessage()from inside the App#run() method. This way, you can have optional parameters for your application.