Getting Started with Dropwizard – CRUD Operations

Getting Started with Dropwizard – CRUD Operations

Dropwizard is a Java framework for building RESTful web services. In essence, it is a glue framework which bundles together popular and battle-tested Java libraries and frameworks to make it easier to start building new RESTful web services. This post explores how to implement create, read, update, delete operations (CRUD) on a resource.

Last time we set out on a journey to build a simple RESTful web service with Dropwizard. The goal was to build a back-end for a hypothetical events application that would allow you to search for events based on your search criteria. It should be able to provide a list of events, add new events and modify existing ones. Make sure you read the previous post because we will be continuing were we left off. If you wish to follow along, clone the GitHub repository and check out the register-resource tag.

Quick recap

In the previous article we created a new Dropwizard project, added custom configuration, created a representation and a very basic resource. Because we didn’t have a data store in place, clients were only able to make a GET request to /events and receive hard-coded data. In this follow-up tutorial we’re going to expand the feature set of the application to meet the requirements we initially set.

Introducing a data store

This tutorial is going to cover how to implement CRUD functionality for our application. To keep things simple and not bog you down in database specifics, I’m not going to set one up. Instead we’re going to implement a very basic in-memory database backed by java.util.List.

To achieve better code reuse, it’s better to depend on abstractions, which in Java terms means not depending on concrete types. We will hence declare the public API of our in-memory data store in an interface.

Create a new interface in the com.mycompany.core package called EventRepository.

public interface EventRepository {

}

We will expand this interface throughout the rest of the article, adding methods as we need them.

Implementing EventRepository

We have created an interface that defines the public API of EventRepository. Now we need to come up with an implementation.

Note that the following class is by no means a solution that you’d deploy to production. For starters, because we’re going to store events in a list, we’re going to run into concurrency issues. The list is a shared resource which means it has to be thread safe. Since concurrency is not the topic of this article, pretend that you are the only user. The idea is not to worry about the storage of data but rather how to create methods in EventResource so we could meet the requirements we initially set.

Create a new class called DummyEventRepository in com.mycompany.core package and make it implement the EventRepository interface.

public class DummyEventRepository implements EventRepository {

    private static final String DATA_SOURCE = "dummy_data.json";

    private List<Event> events;

    public DummyEventRepository() {
        try {
            initData();
        } catch (IOException e) {
            throw new RuntimeException(
                    DATA_SOURCE + " missing or is unreadable", e);
        }
    }

    private void initData() throws IOException {
        URL url = Resources.getResource(DATA_SOURCE);
        String json = Resources.toString(url, Charsets.UTF_8);
        ObjectMapper mapper = new ObjectMapper();
        CollectionType type = mapper
                .getTypeFactory()
                .constructCollectionType(List.class, Event.class);
        events = mapper.readValue(json, type);
    }

}

When DummyEventRepository is instantiated, initData is called. This method reads a JSON file containing dummy data which will be used to populate our in-memory data store. The JSON file is read with Guava’s Resource class and is parsed with Jackson’s ObjectMapper class. Create a new JSON document called dummy_data.json and place it in src/main/resources. The following is the data I will be using.

[
    {
        "id": 1,
        "name": "Czech National Symphony Orchestra - I. Concert",
        "description": "PERFORMERS: Libor Pešek - conductor, Natalie Clein - violoncello",
        "location": "náměstí Republiky 5, Praha 1 - Staré Město, 110 00",
        "date": "2016-10-25T19:30+0200"
    },
    {
        "id": 2,
        "name": "Salsa Festival",
        "description": "World class shows & performances by some of the best artists in the world.",
        "location": "Copenhagen",
        "date": "2017-05-05T17:00+0200"
    },
    {
        "id": 3,
        "name": "National Restaurant Day",
        "description": "As autumn arrives the National Restaurant Day kicks off, awaiting the lovers of gastronomy for the 11th time.",
        "location": "Budapest, Hungary",
        "date": "2016-10-16T12:00+0200"
    },
    {
        "id": 4,
        "name": "UEFA Europa League: Austria Vienna vs. Roma",
        "description": "Don't miss this spectacular game and get tickets to see Austria Vienna v Roma now, before they run out.",
        "location": "Ernst-Happel Stadion, Vienna, Austria",
        "date": "2016-11-03T19:00+0200"
    }
]

EventResource, EventRepository and DummyEventRepository

In the following diagram you can see the three types in action. EventResource is responsible for for handling HTTP requests. When it needs to access or modify data, it delegates this concern to an instance of EventRepository. DummyEventRepository is an implementation of EventRepository and it will act as an in-memory data store.

class_diagram

EventResource needs a reference to an implementation of EventRepository to do its job. I don’t want to instantiate DummyEventRepository in the EventResource class directly. This would be a violation of the dependency inversion principle. The less it knows about concrete implementations of other classes the better. Therefore I added a constructor parameter to the EventResource class which can be used to inject a concrete implementation of EventRepository.

private EventRepository repository;

public EventResource(EventRepository repository) {
    this.repository = repository;
}

Finally, we need to wire together our object graph. In our application’s run method, get a reference to an instance of DummyEventRepository and pass it to EventResource.

@Override
public void run(EventsConfiguration configuration,
        Environment environment) {
    //irrelevant code not shown
    EventRepository repository = new DummyEventRepository();
    EventResource eventResource = new EventResource(repository);
    environment.jersey().register(eventResource);
}

Retrieving all events

We can start using our newly created EventRepository by refactoring the allEvents method in EventResource class. At the moment it returns a list of events which are created on the fly. But it would make more sense if it returned all events from the in-memory data store. So let’s make the required modifications to make that happen.

Modify the EventRepository interface and declare a method for finding all events as well.

List<Event> findAll();

Create an implementation of the method declared in the interface in the DummyEventRepository class. Returning the list of events is all you need to do for now.

@Override
public List<Event> findAll() {
    return events;
}

Now modify EventResource to delegate the search of all events to an implementation of EventRepository.

@GET
public List<Event> allEvents() {
    return repository.findAll();
}

When running the application, instead of getting hard-coded data as we did in the previous post, you should see a list of events that are retrieved from EventRepository when visiting http://localhost:8080/api/events.

In reality, you don’t want to get all the data at once. There could be thousands of records and retrieving all of them would create unnecessary overhead. In the front-end, it is reasonable to show only a small selection of events. For example, when you do a Google search, you’ll get results that are distributed among multiple pages. This act is called pagination. Although an important feature, we’re going to cover it in a future article.

Retrieving a single event

Continue reading %Getting Started with Dropwizard – CRUD Operations%