Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

A Dropwizard Tutorial : How to Hire Dropwizard Developers

We’re all witnessing a rise in the popularity of microservice architectures. In a microservice architecture, Dropwizard commands a very important place. It is a framework for building RESTful web services or, more precisely, a set of tools and frameworks for building RESTful web services.
It allows developers quick project bootstrapping. This helps you package your applications to be easily deployable in a production environment as standalone services. If you have ever been in a situation where you need to bootstrap a project in the Spring framework, for example, you probably know how painful it can be.
In this blog, I will guide you through the complete process of writing a simple Dropwizard RESTful service. After we’re done, we will have a service for basic CRUD operations on “parts.” It doesn’t really matter what “part” is; it can be anything. It just came to mind first.
We will store the data in a MySQL database, using JDBI for querying it, and will use following endpoints:
  • GET /parts -to retrieve all parts from DB
  • GET /part/{id} to get a particular part from DB
  • POST /parts -to create new part
  • PUT /parts/{id} -to edit an existing part
  • DELETE /parts/{id} -to delete the part from a DB
We will use OAuth to authenticate our service, and finally, add some unit tests to it.

Default Dropwizard Libraries

Instead of including all libraries needed to build a REST service separately and configuring each of them, Dropwizard does that for us. Here is the list of libraries that come with Dropwizard by default:
  • Jetty: You would require HTTP for running a web application. Dropwizard embeds the Jetty servlet container for running web applications. 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. As of now, Dropwizard recommends only running the application with Jetty; other web services like Tomcat are not officially supported.
  • Jersey: Jersey is one of the best REST API implementations on the market. Also, it follows the standard JAX-RS specification, and it’s the reference implementation for the JAX-RS specification. Dropwizard uses Jersey as the default framework for building RESTful web applications.
  • Jackson: Jackson is the de facto standard for JSON format handling. It is one of the best object mapper APIs for the JSON format.
  • Metrics: Dropwizard has its own metrics module for exposing the application metrics through HTTP endpoints.
  • Guava: In addition to highly optimized immutable data structures, Guava provides a growing number of classes to speed up development in Java.
  • Logback and Slf4j: These two are used for better logging mechanisms.
  • Freemarker and Mustache: Choosing template engines for your application is one of the key decisions. The chosen template engine has to be more flexible for writing better scripts. Dropwizard uses well-known and popular template engines Freemarker and Mustache for building the user interfaces.
Apart from the above list, there are many other libraries like Joda Time, Liquibase, Apache HTTP Client, and Hibernate Validator used by Dropwizard for building REST services.

Maven Configuration

Dropwizard officially supports Maven. Even if you can use other build tools, most of the guides and documentation uses Maven, so we’re going to use it too here. If you’re not familiar with Maven, you could check out this Maven tutorial.
This is the first step in creating your Dropwizard application. Please add the following entry in your Maven’s pom.xml file:


io.dropwizard
dropwizard-core
${dropwizard.version}


Before adding the above entry, you could add the dropwizard.version as below:

1.1.0

That’s it. You’re done writing the Maven configuration. This will download all the required dependencies to your project. The current Dropwizard version is 1.1.0, so we will be using it this guide.
Now, we can move on to writing our first real Dropwizard application.

Define Configuration Class

Dropwizard stores configurations in YAML files. You will need to have the file configuration.yml in your application root folder. This file will then be deserialized to an instance of your application’s configuration class and validated. Your application’s configuration file is the subclass of the Dropwizard’s configuration class (io.dropwizard.Configuration).
Let’s create a simple configuration class:
import javax.validation.Valid;
import javax.validation.constraints.NotNull;

import com.fasterxml.jackson.annotation.JsonProperty;

import io.dropwizard.Configuration;
import io.dropwizard.db.DataSourceFactory;

public class DropwizardBlogConfiguration extends Configuration {
private static final String DATABASE = "database";

@Valid
@NotNull
private DataSourceFactory dataSourceFactory = new DataSourceFactory();

@JsonProperty(DATABASE)
public DataSourceFactory getDataSourceFactory() {
return dataSourceFactory;
}

@JsonProperty(DATABASE)
public void setDataSourceFactory(final DataSourceFactory dataSourceFactory) {
this.dataSourceFactory = dataSourceFactory;
}
}
The YAML configuration file would look like this:
database:
driverClass: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost/dropwizard_blog
user: dropwizard_blog
password: dropwizard_blog
maxWaitForConnection: 1s
validationQuery: "SELECT 1"
validationQueryTimeout: 3s
minSize: 8
maxSize: 32
checkConnectionWhileIdle: false
evictionInterval: 10s
minIdleTime: 1 minute
checkConnectionOnBorrow: true
The above class will be deserialized from the YAML file and put the values from the YAML file to this object.

Define an Application Class

We should now go and create the main application class. This class will bring all the bundles together and bring the application up and get it running for use.
Here is an example of an application class in Dropwizard:
import io.dropwizard.Application;
import io.dropwizard.auth.AuthDynamicFeature;
import io.dropwizard.auth.oauth.OAuthCredentialAuthFilter;
import io.dropwizard.setup.Environment;

import javax.sql.DataSource;

import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature;
import org.skife.jdbi.v2.DBI;

import com.toptal.blog.auth.DropwizardBlogAuthenticator;
import com.toptal.blog.auth.DropwizardBlogAuthorizer;
import com.toptal.blog.auth.User;
import com.toptal.blog.config.DropwizardBlogConfiguration;
import com.toptal.blog.health.DropwizardBlogApplicationHealthCheck;
import com.toptal.blog.resource.PartsResource;
import com.toptal.blog.service.PartsService;

public class DropwizardBlogApplication extends Application {
private static final String SQL = "sql";
private static final String DROPWIZARD_BLOG_SERVICE = "Dropwizard blog service";
private static final String BEARER = "Bearer";

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

@Override
public void run(DropwizardBlogConfiguration configuration, Environment environment) {
// Datasource configuration
final DataSource dataSource =
configuration.getDataSourceFactory().build(environment.metrics(), SQL);
DBI dbi = new DBI(dataSource);

// Register Health Check
DropwizardBlogApplicationHealthCheck healthCheck =
new DropwizardBlogApplicationHealthCheck(dbi.onDemand(PartsService.class));
environment.healthChecks().register(DROPWIZARD_BLOG_SERVICE, healthCheck);

// Register OAuth authentication
environment.jersey()
.register(new AuthDynamicFeature(new OAuthCredentialAuthFilter.Builder()
.setAuthenticator(new DropwizardBlogAuthenticator())
.setAuthorizer(new DropwizardBlogAuthorizer()).setPrefix(BEARER).buildAuthFilter()));
environment.jersey().register(RolesAllowedDynamicFeature.class);

// Register resources
environment.jersey().register(new PartsResource(dbi.onDemand(PartsService.class)));
}
}
What’s actually done above is override the Dropwizard run method. In this method, we’re instantiating a DB connection, registering our custom health check (we’ll talk about it later), initializing OAuth authentication for our service, and finally, registering a Dropwizard resource.
All of these will be explained later on.

Define a Representation Class

Now we have to start thinking about our REST API and what will be the representation of our resource. We have to design the JSON format and the corresponding representation class that converts to the desired JSON format.
Let’s look at the sample JSON format for this simple representation class example:
{
"code": 200,
"data": {
"id": 1,
"name": "Part 1",
"code": "PART_1_CODE"
}
}
For the above JSON format, we would create the representation class as below:
import org.hibernate.validator.constraints.Length;

import com.fasterxml.jackson.annotation.JsonProperty;

public class Representation {
private long code;

@Length(max = 3)
private T data;

public Representation() {
// Jackson deserialization
}

public Representation(long code, T data) {
this.code = code;
this.data = data;
}

@JsonProperty
public long getCode() {
return code;
}

@JsonProperty
public T getData() {
return data;
}
}
This is fairly simple POJO.

Defining a Resource Class

A resource is what REST services are all about. It is nothing but an endpoint URI for accessing the resource on the server. In this example, we’ll have a resource class with few annotations for request URI mapping. Since Dropwizard uses the JAX-RS implementation, we will define the URI path using the @Path annotation.
Here is a resource class for our Dropwizard example:
import java.util.List;

import javax.annotation.security.RolesAllowed;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
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.toptal.blog.model.Part;
import com.toptal.blog.representation.Representation;
import com.toptal.blog.service.PartsService;

@Path("/parts")
@Produces(MediaType.APPLICATION_JSON)
@RolesAllowed("ADMIN")
public class PartsResource {
private final PartsService partsService;;

public PartsResource(PartsService partsService) {
this.partsService = partsService;
}

@GET
@Timed
public Representation> getParts() {
return new Representation>(HttpStatus.OK_200, partsService.getParts());
}

@GET
@Timed
@Path("{id}")
public Representation getPart(@PathParam("id") final int id) {
return new Representation(HttpStatus.OK_200, partsService.getPart(id));
}

@POST
@Timed
public Representation createPart(@NotNull @Valid final Part part) {
return new Representation(HttpStatus.OK_200, partsService.createPart(part));
}

@PUT
@Timed
@Path("{id}")
public Representation editPart(@NotNull @Valid final Part part,
@PathParam("id") final int id) {
part.setId(id);
return new Representation(HttpStatus.OK_200, partsService.editPart(part));
}

@DELETE
@Timed
@Path("{id}")
public Representation deletePart(@PathParam("id") final int id) {
return new Representation(HttpStatus.OK_200, partsService.deletePart(id));
}
}
You can see all of the endpoints are actually defined in this class.

Registering a Resource

I would go back now to the main application class. You can see at the end of that class that we have registered our resource to be initialized with the service run. We need to do so with all resources we might have in our application. This is the code snippet responsible for that:
// Register resources
environment.jersey().register(new PartsResource(dbi.onDemand(PartsService.class)));

Service Layer

For proper exception handling and the ability to be independent of the data storage engine, we will introduce a “mid-layer” service class. This is the class we will be calling from our resource layer, and we don’t care what is underlying. That’s why we have this layer in between of resource and DAO layers. Here is our service class:
import java.util.List;
import java.util.Objects;

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response.Status;

import org.skife.jdbi.v2.exceptions.UnableToExecuteStatementException;
import org.skife.jdbi.v2.exceptions.UnableToObtainConnectionException;
import org.skife.jdbi.v2.sqlobject.CreateSqlObject;

import com.toptal.blog.dao.PartsDao;
import com.toptal.blog.model.Part;

public abstract class PartsService {
private static final String PART_NOT_FOUND = "Part id %s not found.";
private static final String DATABASE_REACH_ERROR =
"Could not reach the MySQL database. The database may be down or there may be network connectivity issues. Details: ";
private static final String DATABASE_CONNECTION_ERROR =
"Could not create a connection to the MySQL database. The database configurations are likely incorrect. Details: ";
private static final String DATABASE_UNEXPECTED_ERROR =
"Unexpected error occurred while attempting to reach the database. Details: ";
private static final String SUCCESS = "Success...";
private static final String UNEXPECTED_ERROR = "An unexpected error occurred while deleting part.";

@CreateSqlObject
abstract PartsDao partsDao();

public List getParts() {
return partsDao().getParts();
}

public Part getPart(int id) {
Part part = partsDao().getPart(id);
if (Objects.isNull(part)) {
throw new WebApplicationException(String.format(PART_NOT_FOUND, id), Status.NOT_FOUND);
}
return part;
}

public Part createPart(Part part) {
partsDao().createPart(part);
return partsDao().getPart(partsDao().lastInsertId());
}

public Part editPart(Part part) {
if (Objects.isNull(partsDao().getPart(part.getId()))) {
throw new WebApplicationException(String.format(PART_NOT_FOUND, part.getId()),
Status.NOT_FOUND);
}
partsDao().editPart(part);
return partsDao().getPart(part.getId());
}

public String deletePart(final int id) {
int result = partsDao().deletePart(id);
switch (result) {
case 1:
return SUCCESS;
case 0:
throw new WebApplicationException(String.format(PART_NOT_FOUND, id), Status.NOT_FOUND);
default:
throw new WebApplicationException(UNEXPECTED_ERROR, Status.INTERNAL_SERVER_ERROR);
}
}

public String performHealthCheck() {
try {
partsDao().getParts();
} catch (UnableToObtainConnectionException ex) {
return checkUnableToObtainConnectionException(ex);
} catch (UnableToExecuteStatementException ex) {
return checkUnableToExecuteStatementException(ex);
} catch (Exception ex) {
return DATABASE_UNEXPECTED_ERROR + ex.getCause().getLocalizedMessage();
}
return null;
}

private String checkUnableToObtainConnectionException(UnableToObtainConnectionException ex) {
if (ex.getCause() instanceof java.sql.SQLNonTransientConnectionException) {
return DATABASE_REACH_ERROR + ex.getCause().getLocalizedMessage();
} else if (ex.getCause() instanceof java.sql.SQLException) {
return DATABASE_CONNECTION_ERROR + ex.getCause().getLocalizedMessage();
} else {
return DATABASE_UNEXPECTED_ERROR + ex.getCause().getLocalizedMessage();
}
}

private String checkUnableToExecuteStatementException(UnableToExecuteStatementException ex) {
if (ex.getCause() instanceof java.sql.SQLSyntaxErrorException) {
return DATABASE_CONNECTION_ERROR + ex.getCause().getLocalizedMessage();
} else {
return DATABASE_UNEXPECTED_ERROR + ex.getCause().getLocalizedMessage();
}
}
}
The last part of it is actually a health check implementation, which we will be talking about later.

DAO layer, JDBI, and Mapper

Dropwizard supports JDBI and Hibernate. It’s separate Maven module, so let’s first add it as a dependency as well as the MySQL connector:

io.dropwizard
dropwizard-jdbi
${dropwizard.version}


mysql
mysql-connector-java
${mysql.connector.version}

For a simple CRUD service, I personally prefer JDBI, as it is simpler and much faster to implement. I have created a simple MySQL schema with one table only to be used in our example. You can find the init script for the schema within the source. JDBI offers simple query writing by using annotations such as @SqlQuery for reading and @SqlUpdate for writing data. Here is our DAO interface:
import java.util.List;

import org.skife.jdbi.v2.sqlobject.Bind;
import org.skife.jdbi.v2.sqlobject.BindBean;
import org.skife.jdbi.v2.sqlobject.SqlQuery;
import org.skife.jdbi.v2.sqlobject.SqlUpdate;
import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;

import com.toptal.blog.mapper.PartsMapper;
import com.toptal.blog.model.Part;

@RegisterMapper(PartsMapper.class)
public interface PartsDao {

@SqlQuery("select * from parts;")
public List getParts();

@SqlQuery("select * from parts where id = :id")
public Part getPart(@Bind("id") final int id);

@SqlUpdate("insert into parts(name, code) values(:name, :code)")
void createPart(@BindBean final Part part);

@SqlUpdate("update parts set name = coalesce(:name, name), code = coalesce(:code, code) where id = :id")
void editPart(@BindBean final Part part);

@SqlUpdate("delete from parts where id = :id")
int deletePart(@Bind("id") final int id);

@SqlQuery("select last_insert_id();")
public int lastInsertId();
}
As you can see, it’s fairly simple. However, we need to map our SQL result sets to a model, which we do by registering a mapper class. Here is our mapper class:
import java.sql.ResultSet;
import java.sql.SQLException;

import org.skife.jdbi.v2.StatementContext;
import org.skife.jdbi.v2.tweak.ResultSetMapper;

import com.toptal.blog.model.Part;

public class PartsMapper implements ResultSetMapper {
private static final String ID = "id";
private static final String NAME = "name";
private static final String CODE = "code";

public Part map(int i, ResultSet resultSet, StatementContext statementContext)
throws SQLException {
return new Part(resultSet.getInt(ID), resultSet.getString(NAME), resultSet.getString(CODE));
}
}
And our model:
import org.hibernate.validator.constraints.NotEmpty;

public class Part {
private int id;
@NotEmpty
private String name;
@NotEmpty
private String code;

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getCode() {
return code;
}

public void setCode(String code) {
this.code = code;
}

public Part() {
super();
}

public Part(int id, String name, String code) {
super();
this.id = id;
this.name = name;
this.code = code;
}
}

Dropwizard Health Check

Dropwizard offers native support for health checking. In our case, we would probably like to check if the database is up and running before saying that our service is healthy. What we do is actually perform some simple DB action like getting parts from the DB and handling the potential outcomes (successful or exceptions).
Here is our health check implementation in Dropwizard:
import com.codahale.metrics.health.HealthCheck;
import com.toptal.blog.service.PartsService;

public class DropwizardBlogApplicationHealthCheck extends HealthCheck {
private static final String HEALTHY = "The Dropwizard blog Service is healthy for read and write";
private static final String UNHEALTHY = "The Dropwizard blog Service is not healthy. ";
private static final String MESSAGE_PLACEHOLDER = "{}";

private final PartsService partsService;

public DropwizardBlogApplicationHealthCheck(PartsService partsService) {
this.partsService = partsService;
}

@Override
public Result check() throws Exception {
String mySqlHealthStatus = partsService.performHealthCheck();

if (mySqlHealthStatus == null) {
return Result.healthy(HEALTHY);
} else {
return Result.unhealthy(UNHEALTHY + MESSAGE_PLACEHOLDER, mySqlHealthStatus);
}
}
}

Adding Authentication

Dropwizard supports basic authentication and OAuth. Here. I will show you how to protect your service with OAuth. However, due to complexity, I have omitted an underlying DB structure and just showed how it is wrapped. Implementing to full scale should not be an issue starting from here. Dropwizard has two important interfaces we need to implement.
The first one is Authenticator. Our class should implement the authenticate method, which should check if the given access token is a valid one. So I would call this as a first gate to the application. If succeeded, it should return a principal. This principal is our actual user with its role. The role is important for another Dropwizard interface we need to implement. This one is Authorizer, and it is responsible for checking whether the user has sufficient permissions to access a certain resource. So, if you go back and check our resource class, you will see that it requires the admin role for accessing its endpoints. These annotations can be per method also. Dropwizard authorization support is a separate Maven module, so we need to add it to dependencies:

io.dropwizard
dropwizard-auth
${dropwizard.version}

Here are the classes from our example that doesn’t actually do anything smart, but it’s a skeleton for a full-scale OAuth authorization:
import java.util.Optional;

import io.dropwizard.auth.AuthenticationException;
import io.dropwizard.auth.Authenticator;

public class DropwizardBlogAuthenticator implements Authenticator {
@Override
public Optional authenticate(String token) throws AuthenticationException {
if ("test_token".equals(token)) {
return Optional.of(new User());
}
return Optional.empty();
}
}
import java.util.Objects;

import io.dropwizard.auth.Authorizer;

public class DropwizardBlogAuthorizer implements Authorizer {
@Override
public boolean authorize(User principal, String role) {
// Allow any logged in user.
if (Objects.nonNull(principal)) {
return true;
}
return false;
}
}
import java.security.Principal;

public class User implements Principal {
private int id;
private String username;
private String password;

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

@Override
public String getName() {
return username;
}
}

Unit Tests in Dropwizard

Let’s add some unit tests to our application. I will stick to testing Dropwizard specific parts of the code, in our case Representation and Resource. We will need to add following dependencies to our Maven file:

io.dropwizard
dropwizard-testing
${dropwizard.version}


org.mockito
mockito-c


This post first appeared on Latest Technology News And Trends, please read the originial post: here

Share the post

A Dropwizard Tutorial : How to Hire Dropwizard Developers

×

Subscribe to Latest Technology News And Trends

Get updates delivered right to your inbox!

Thank you for your subscription

×