Views

Microservice Using Dropwizard, Hibernate and H2 Database

Microservice Using Dropwizard, Hibernate and H2 Database
Page content

In this article, I will develop a Microservice Application using Dropwizard Framework and H2 Database and expose all CRUD (Create, Read, Update, Delete) Operations as the REST APIs.

Dropwizard Framework will serve as back-end server and I will be using Relational Database known as H2 Database, it is also known as an Embedded Java Database, for persisting(storing) the data.

By the end of this article, you would learn about how to:

  • Configure Hibernate to work with Relational Database and persist the data.
  • Create and Expose REST APIs for CRUD Operations using Dropwizard Framework.
  • How to handle HTTP and CORS Requests through REST Controller.

Overview

We will build a Rest CRUD API using Dropwizard Framework for a Todo Task Application in that:

  • Each Todo Task has id, title, description, creation date, due date, status and comments.
  • APIs help to Create, Read, Update, Delete Todo Tasks.

Below mentioned are the REST APIs for CRUD Operations using Dropwizard Framework.

Description CRUD Operation HTTP Method REST API Endpoint
Create New Todo Task CREATE POST /tasks
Fetch All Todo Tasks READ GET /tasks
Fetch One Todo Task READ GET /tasks/{id}
Update One Specific Todo Task UPDATE PUT /tasks
Delete One Specific Todo Task DELETE DELETE /tasks/{id}

If you have no time to read this article, but want to try the code for yourself, GitHub location is provided here. Go ahead and clone the code repository.


Definitions

Dropwizard is an open source Java Framework for the rapid development of REST APIs. Dropwizard is kind of ecosystem which contains all the dependencies (such as Jersey, Jackson or Jetty) from the Java ecosystem into a simple, light-weight package that lets you focus on getting things done.

Microservices is an architecture that allows the developers to develop and deploy services independently. Each service running has its own process and this achieves the lightweight model to support business applications. One of the most popular types of APIs for building Microservices applications is known as “RESTful API” or “REST API”.

REpresentational State Transfer (REST) is an architectural style that defines a set of constraints to be used for creating web services. REST API is a way of accessing web services in a simple and flexible way without having any processing. All communication done via REST API uses only HTTP request.

Application Programming Interface (API) is a software intermediary that allows two applications to talk to each other. To simplify, an API delivers a user requests to a system and sends the system’s response back to a user.


Prerequisites

There are some prerequisites that are required for creating the Microservice Application using Dropwizard.

Familiarity with Technology and Frameworks

It is assumed that you have prior knowledge or familiarity with Java Technology, Jetty, Jersey, Jackson, Hibernate Frameworks, working with RDBMS databases and basic SQL commands, because I will not be covering the basics of these in this article.

If you are not familiar, then it is advised to get the basic knowledge of these before continuing.

JDK 1.8+

Download the latest version of the Java JDK (1.17 is the latest LTS version, at the time of writing this article) from here. Click on the downloaded .exe and complete the installation.

Since it is an Oracle Proprietary product you will need to sign-in/create Oracle Account, before downloading.

Integrated Development Environment (IDE) for Code Development

You can use any IDE of your choice. I will be using the IntelliJ IDEA Community Edition.

If you wish to use the IntelliJ IDEA Community Edition, download the latest version from here.

Click on the downloaded .exe and complete the installation.

Web ApplicationJetty is embedded in the Dropwizard Framework and can be used as Web application for running this project.

Project Management ToolDropwizard Framework officially supports Maven, so we are going to use it in this project.


Create Base Dropwizard Project

Let me first create the Base Dropwizard Project, the basic project without any of the customization. Later I will enhance it with different methods, to include CRUD Operations and Expose REST APIs, as discussed above.

Create Dropwizard Project using Maven

There are two options for creating the project using Maven.

Using Command Prompt

Move to the folder where you want to create the project and open the command prompt.

mvn archetype:generate  -DgroupId=com.myzonesoft.todo 
                        -DartifactId=microservice-dropwizard-h2 
                        -DarchetypeArtifactId=maven-archetype-quickstart 
                        -DinteractiveMode=false

Using Integrated Development Environment (IDE)

Open your favorite IDE(I will be using IntelliJ IDEA Community Edition, as mentioned here) and select File -> New -> Project.

  • A popup window with option to create new project appears.
  • Fill in Name, Location, Language, Build System, JDK, GroupId, ArtifactId and click Create.
  • New project will be created.
    new-project-creation-using-ide.jpeg
    New Dropwizard Project creation using IDE

Generated project will have pom.xml file as well. Add Dropwizard dependencies there.

 1<properties>
 2    <dropwizard.version>2.1.0</dropwizard.version>
 3</properties>
 4
 5<dependencyManagement>
 6    <dependencies>
 7        <dependency>
 8            <groupId>io.dropwizard</groupId>
 9            <artifactId>dropwizard-dependencies</artifactId>
10            <version>${dropwizard.version}</version>
11            <type>pom</type>
12            <scope>import</scope>
13        </dependency>
14    </dependencies>
15</dependencyManagement>
16
17<dependencies>
18    <dependency>
19        <groupId>io.dropwizard</groupId>
20        <artifactId>dropwizard-core</artifactId>
21    </dependency>
22</dependencies>

That’s it. This will download all the required dependencies to your project. The current Dropwizard version is 2.1.0.

Libraries included inside dropwizard

Once you include dropwizard into your project, you get following libraries added to your classpath.

  • Jersey – For building RESTful web applications. It allows you to write clean, testable classes which gracefully map HTTP requests to simple Java objects.
  • Jetty – Dropwizard uses the Jetty HTTP library to embed an HTTP server directly into your project.
  • Jackson – For object to/from JSON conversion. It allows to export your domain models directly with JAXB annotations.
  • Guava – highly optimized immutable data structures to speedup development.
  • Logback and SLF4j – for performant and flexible logging.
  • Hibernate Validator – an easy declarative framework for validating user input and generating helpful and i18n-friendly error messages.
  • Apache HTTPClient – For both low- and high-level interaction with other web services.
  • JDBI – the most straightforward way to use a relational database with Java.
  • Liquibase – to keep your database schema in check throughout your development and release cycle.
  • FreeMarker and Mustache – are simple templating systems for more user-facing applications.
  • Joda Time – very complete and sane library for handling dates and times.

Building Fat JARs

To add build and package support to our project, we will use the maven-shade plugin, which will allow us to package our project completely, along with its dependencies, into a single standalone JAR file (Fat/Uber JAR) that can be distributed and executed as is.

pom.xml after adding the build section.

 1<properties>
 2  <maven.compiler.source>1.17</maven.compiler.source>
 3  <maven.compiler.target>1.17</maven.compiler.target>
 4</properties>
 5
 6<build>
 7  <plugins>
 8    <plugin>
 9      <groupId>org.apache.maven.plugins</groupId>
10      <artifactId>maven-shade-plugin</artifactId>
11      <version>3.3.0</version>
12      <executions>
13        <execution>
14          <phase>package</phase>
15          <goals>
16            <goal>shade</goal>
17          </goals>
18          <configuration>
19            <transformers>
20              <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
21                <mainClass>com.myzonesoft.todo.microservice.MicroserviceDropwizardH2Application</mainClass>
22              </transformer>
23              <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer">
24              </transformer>
25            </transformers>
26          </configuration>
27        </execution>
28      </executions>
29    </plugin>
30  </plugins>
31</build>

Creating An Application Class

An Application Class is entry point for any Dropwizard Project. It needs to extend the io.dropwizard.Application class and implement its the run(Configuration, Environment) method. They prepare the runtime environment of the application.

To invoke the run method, you will need to have public static void main(String[] args) {} method, which will be invoked by java -jar command when you run the application as jar file.

 1public class MicroserviceDropwizardH2Application extends Application<Configuration> {
 2    public static void main(String[] args) throws Exception {
 3        new MicroserviceDropwizardH2Application().run(args);
 4    }
 5
 6    @Override
 7    public void run(Configuration configuration, Environment environment) throws Exception {
 8        // nothing to do yet
 9    }
10}

In the run method, we need to register all the Resource/Controller Classes later.


Create Representation/Model Class

Representation is what holds the data and serialized into JSON. It’s Model for RESTful application. When using Jersey with Jackson, all you need to build a resource representation is – a simple POJO following Java Bean standards. Jackson constructs the JSON string recursively according to the getter methods of each class and their return type.

  • Create new Representation/Model Class - model.Tasks
 1public class Tasks {
 2  private String systemTasksId;
 3  private String title;
 4  private String description;
 5  @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy")
 6  private LocalDate creationDate;
 7  @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy")
 8  private LocalDate dueDate;
 9  private String status;
10  private Set<TodoTaskComments> todoTaskCommentsSet;
11}
  • Create new Representation/Model Class - model.TodoTaskComments
1public class TodoTaskComments {
2  private Long todoTaskCommentsId;
3  private String taskComments;
4  @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
5  private LocalDate creationDate;
6  private Tasks todoTask;
7}

Add Project Lombok to Representation/Model Class

Representation/Model Class would require lots of bolier plate codes like No Args Constructor methods, All Args Constructor methods, Getters/Setters methods, To String methods and Class Builder methods. Instead of writing these for all model classes, in order to reduce the code, we can use Project Lombok.

  • In our pom.xml, add the following dependency
 1<properties>
 2    <lombok.version>1.18.24</lombok.version>
 3</properties>
 4
 5<dependencies>
 6    <dependency>
 7        <groupId>org.projectlombok</groupId>
 8        <artifactId>lombok</artifactId>
 9        <version>${lombok.version}</version>
10        <scope>provided</scope>
11    </dependency>
12</dependencies>
  • Update the Representation/Model Class to include the Lombok Annotations - model.Tasks
1@Builder
2@Getter
3@Setter
4@NoArgsConstructor
5@AllArgsConstructor
6@ToString
7public class Tasks { }

Create DAO/Repository Class

DAO/Repository Class will be responsible for updating the Model Class data in the Database. Let us create- repository.TasksDAO

Hardcode the Data

For now, I will hardcode the data to represent the database entity. In the later section of this article, I will connect to database.

 1public class TasksDAO {
 2  public static HashMap<Integer, Tasks> tasksHashMap = new HashMap<>();
 3  static{
 4      Set<TodoTaskComments> todoTaskCommentsSet = new HashSet<>();
 5      todoTaskCommentsSet.add(TodoTaskComments.builder()
 6        .todoTaskCommentsId(2L).taskComments("Hardcode Comment").creationDate(LocalDate.now()).build());
 7      tasksHashMap.put(1, Tasks.builder()
 8        .systemTasksId(1L).title("Test from Dropwizard").description("Hardcoded in Dropwizard")
 9        .creationDate(LocalDate.now()).dueDate(LocalDate.now()).status("NOT_STARTED")
10        .todoTaskCommentsSet(todoTaskCommentsSet)
11        .build());
12  }
13
14  public List<Tasks> getAllTodoTasks() {
15      return new ArrayList<>(tasksHashMap.values());
16  }
17}

Creating A Resource/Controller Class

We will now add REST resources containing REST APIs. Each Resource/Controller Class is associated with a URI template. This class will be responsible for handling HTTP requests and generating JSON responses. Jersey is used for building these REST APIs.

  • Create Resource/Controller Class - controller.TodoController
 1@Path("/todo-app/tasks")
 2@Produces(MediaType.APPLICATION_JSON)
 3public class TodoController {
 4  private final TasksDAO tasksDAO = new TasksDAO();
 5
 6  public TodoController() { }
 7
 8  @GET
 9  public Response getAllTodoTasks() {
10      return Response.ok(tasksDAO.getAllTodoTasks()).build();
11  }
12}

Registering A Resource

We need to register this Resource/Controller Class in the run() method of our Application Class.

 1public class MicroserviceDropwizardH2Application extends Application<Configuration> {
 2    public static void main(String[] args) throws Exception {
 3        new MicroserviceDropwizardH2Application().run(args);
 4    }
 5
 6    @Override
 7    public void run(Configuration configuration, Environment environment) throws Exception {
 8        environment.jersey().register(new TodoController());
 9    }
10}

Running the Application

Once we have everything configured, its time to run the application.

We have 2 ways of running the application.

Using the Uber Fat Jar File (Standalone application)

Build Application Uber Fat Jar File

Go into your project directory and run this:

mvn clean package (or run the `clean package` goal from your IDE)

Start Application Jetty server

In your project directory, run this:

java -jar .\target\microservice-dropwizard-h2-1.0-SNAPSHOT.jar server

And if you have configuration.yml file, then run the below command:

java -jar .\target\microservice-dropwizard-h2-1.0-SNAPSHOT.jar server configuration.yml

Through the Intellij Idea IDE

  1. Open Run/Debug Configuration menu by selecting Run -> Edit Configurations from the menu.
  2. Add a new configuration by pressing Alt+Insert or clicking the green plus sign in the top left corner.
  3. From the dropdown menu, select Application.
  4. Add a name to the configuration.
  5. Enter the fully qualified name of your main class.
  6. Enter server configuration.yml to the Program arguments field (if you do not have any configuration.yml, as yet, you can only enter server).
  7. Press Shift+F10 or select Run -> Run <<your run configuration name>> from the menu to start your Dropwizard application.
    running-through-intellij-idea-ide.jpeg
    Running through the Intellij Idea IDE

Server start

Your Dropwizard application is now listening on ports 8080 for application requests and 8081 for administration requests.

jetty-server-started.jpeg
Jetty Server Started and Listening on Ports 8080 and 8081


Access the URI

Once you have started the server (using any of method mentioned above), open any REST client(like Postman) and provide values, as per the below table and see the response from the server.

HTTP Method Endpoint URL
GET http://localhost:8080/todo-app/tasks

get-all-response-from-server.jpeg
Server Response for GET All API call

We have successfully got our first Dropwizard Project up and running by hardcoding the values.


Enhance the Existing Application to Expose REST APIs

It is now time to enhance our project to include REST API endpoints, so that they can be exposed for consumption by other applications.

Final Project Structure

The final project structure will look something like this:

final-project-structure.jpeg
Final Project Structure


Connecting with Database

We will first setup the database for persisting the data. I will be using the Relational Database known as H2 Database. It is called the Java SQL database. You can extend this to use any other Relational Database and only Database configurations needs to be changed.

To know more about the H2 Database, read here.

Add dependencies to pom.xml

Add dependencies of Hibernate and H2 Database to pom.xml

 1<properties>
 2    <h2db.version>2.1.214</h2db.version>
 3</properties>
 4
 5<dependencies>
 6    <!-- For Database connectivity -->
 7    <dependency>
 8        <groupId>io.dropwizard</groupId>
 9        <artifactId>dropwizard-hibernate</artifactId>
10    </dependency>
11    <dependency>
12        <groupId>com.h2database</groupId>
13        <artifactId>h2</artifactId>
14        <version>${h2db.version}</version>
15    </dependency>
16</dependencies>

Update Representation/Model Classes

Add some Hibernate Annotations to the Representation/Model Classes.

  1. Update Representation/Model Class- model.Tasks
 1@Entity
 2@NamedQueries({
 3        @NamedQuery(name = "com.myzonesoft.todo.microservice.model.Tasks.findAll",
 4                query = "select e from Tasks e")
 5})
 6public class Tasks {
 7  @Id
 8  @GeneratedValue(strategy = GenerationType.AUTO)
 9  private Long systemTasksId;
10  private String title;
11  private String description;
12  @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
13  private LocalDate creationDate;
14  @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
15  private LocalDate dueDate;
16  private String status;
17  @OneToMany(mappedBy = "todoTask", fetch = FetchType.EAGER)
18  private Set<TodoTaskComments> todoTaskCommentsSet;
19}
  1. Update Representation/Model Class - model.TodoTaskComments
 1@Entity
 2@NamedQueries({
 3        @NamedQuery(name = "com.myzonesoft.todo.microservice.model.TodoTaskComments.findAll",
 4                query = "select e from TodoTaskComments e")
 5})
 6public class TodoTaskComments {
 7    @Id
 8    @GeneratedValue(strategy = GenerationType.AUTO)
 9    private Long todoTaskCommentsId;
10    private String taskComments;
11    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
12    private LocalDate creationDate;
13    @JsonIgnore
14    @ManyToOne(fetch = FetchType.EAGER)
15    @JoinColumn(name="systemTasksId", nullable=false)
16    private Tasks todoTask;
17}

Some of the Hibernate Annotations used in the above code are explained below:

  • @Entity– Letting the Hibernate know that this POJO Model Class is to be converted to Table in the database and its private variables into Columns of that Table.
  • @NamedQueries and @NamedQuery - They enable us to declare a query in your persistence layer and reference it in your business code. It can easily be reused.
  • @Id– To identify the primary key of the table.
  • @GeneratedValue(strategy = GenerationType.AUTO)– To Auto Generate the sequence for the Primary Key. There are different strategies available, based on the database that is used.
  • @JsonIgnore- is used at field level to mark a property or list of properties to be ignored.
  • @OneToMany- Each Todo task can have many comments.
    • So there is a One-To-Many relationship between Todo POJO Model Class and TodoTaskComments POJO Model Class.
    • We are using mappedBy attribute, where we inform the Hibernate which variable is responsible for updating this relationship.
  • @ManyToOne- Reverse mapping for the OneToMany explained above.
  • @JoinColumn- Refers to the Primary Key of the Main Model Class.

Update/Create DAO/Repository Classes

  • Update repository.TasksDAO
1public class TasksDAO extends AbstractDAO<Tasks> {
2  public TasksDAO(SessionFactory sessionFactory) {
3    super(sessionFactory);
4  }
5}
  • Create repository.TodoTaskCommentsDAO
1public class TodoTaskCommentsDAO extends AbstractDAO<Tasks> {
2  public TodoTaskCommentsDAO(SessionFactory sessionFactory) {
3    super(sessionFactory);
4  }
5}

DAO Class should extend the io.dropwizard.hibernate.AbstractDAO and implemet its constructor.


Add the Configuration file to the root folder - <root>/configuration.yml

 1database:
 2  # the name of your JDBC driver
 3  driverClass: org.h2.Driver
 4
 5  # the username
 6  user: root
 7
 8  # the password
 9  password: root
10
11  # the JDBC URL
12  url: jdbc:h2:~/todo-app
13
14  # any properties specific to your JDBC driver:
15  properties:
16    charSet: UTF-8
17    hibernate.dialect: org.hibernate.dialect.H2Dialect
18    hibernate.hbm2ddl.auto: create-drop
19    hibernate.show_sql: true
20
21  # the maximum amount of time to wait on an empty pool before throwing an exception
22  maxWaitForConnection: 3s
23
24  # the SQL query to run when validating a connection's liveness
25  validationQuery: "/* MyApplication Health Check */ SELECT 1"
26
27  # the minimum number of connections to keep open
28  minSize: 8
29
30  # the maximum number of connections to keep open
31  maxSize: 30

Create Configuration Class - configuration.TodoConfiguration

1@Getter
2@Setter
3public class TodoConfiguration extends Configuration {
4  @Valid
5  @NotNull
6  @JsonProperty("database")
7  private DataSourceFactory dataSourceFactory = new DataSourceFactory();
8}

Configuration Class would be reading from the configuration.yml file.


Update the Application Class to register the Hibernate Bundle

 1public class MicroserviceDropwizardH2Application extends Application<TodoConfiguration> {
 2    public static void main(String[] args) throws Exception {
 3        new MicroserviceDropwizardH2Application().run(args);
 4    }
 5
 6    @Override
 7    public void run(TodoConfiguration todoConfiguration, Environment environment) throws Exception {
 8        final TasksDAO tasksDAO = new TasksDAO(hibernateBundle.getSessionFactory());
 9        environment.jersey().register(new TodoController(tasksDAO));
10        environment.jersey().register(new JsonProcessingExceptionMapper(true));
11    }
12
13    private final HibernateBundle<TodoConfiguration> hibernateBundle = 
14      new HibernateBundle<TodoConfiguration>(Tasks.class, TodoTaskComments.class) {
15        @Override
16        public DataSourceFactory getDataSourceFactory(TodoConfiguration configuration) {
17            return configuration.getDataSourceFactory();
18        }
19    };
20
21    @Override
22    public void initialize(Bootstrap<TodoConfiguration> bootstrap) {
23        bootstrap.addBundle(hibernateBundle);
24    }
25}

Now, if we start the server, as explained here, we see the Hibernate tables created during the server startup, as shown below

database-connection-successful.jpeg
Database Table Creation

Now, with this basic understanding of how Models, Entities and Tables mapping works in Hibernate, let us move on and add some REST API Endpoints.


Add REST API Endpoint for CREATE Operation

Description CRUD Operation HTTP Method REST API Endpoint
Create New Todo Task CREATE POST /tasks
  • Update DAO/Repository Class repository.TasksDAO
 1public Tasks createOrUpdateTask(Tasks task) {
 2  //Get the list of TodoTaskComments from the Request Body
 3  Set<TodoTaskComments> todoTaskCommentsSet = task.getTodoTaskCommentsSet();
 4
 5  if(todoTaskCommentsSet != null) {
 6    for(TodoTaskComments todoTaskComment: todoTaskCommentsSet){
 7      if (todoTaskComment != null && !todoTaskComment.getTaskComments().isEmpty()) {
 8        todoTaskComment.setTodoTask(task);
 9        todoTaskCommentsDAO.createTodoTaskComments(todoTaskComment);
10      }
11    }
12  }
13
14  //Set the Creation Date only during initial creation of the task
15  if(task.getCreationDate() == null)
16      task.setCreationDate(LocalDate.now());
17
18  return persist(task);
19}
  • Update DAO/Repository Class repository.TodoTasksCommentsDAO
1public void createTodoTaskComments(TodoTaskComments todoTaskComment) {
2  todoTaskComment.setCreationDate(LocalDate.now());
3  persist(todoTaskComment);
4}
  • Create Util Interface, for storing all the constants, enums and other values= util.TodoApplicationConstants
1public interface TodoApplicationConstants {
2  //Enums
3  enum TASK_STATUS {NOT_STARTED, IN_PROGRESS, ON_HOLD, COMPLETED, DEFERRED}
4}
  • Update Resource/Controller Class, for exposing the REST APIs = controller.TodoController
 1@POST
 2@UnitOfWork
 3@Consumes(MediaType.APPLICATION_JSON)
 4public Response createTasks(Tasks task) {
 5  return Response.accepted(tasksDAO.createOrUpdateTask(task)).build() ;
 6}
 7
 8@GET
 9@Path("/status")
10@UnitOfWork
11public List<String> getTodoStatusAsList() {
12  List<String> taskStatusList = Stream.of(TASK_STATUS.values()).map(TASK_STATUS::name).collect(Collectors.toList());
13  return taskStatusList;
14}

Now, Open any REST client and provide values, as per the below table and see the response from the server.

HTTP MethodPOST
Endpoint URLhttp://localhost:8080/todo-app/tasks
Request HeaderContent-type: application/json
Request Body{
  "title": "Testing the Application",
  "description": "Testing the Application",
  "dueDate": "2022-06-30",
  "status": "NOT_STARTED",
  "todoTaskCommentsSet": []
}

create-api-response.jpeg
Server Response for POST API call


Add REST API Endpoint for GET All Operation

Description CRUD Operation HTTP Method REST API Endpoint
Fetch All Todo Tasks READ GET /tasks

For creating this endpoint, we would need to update following classes:

  • Update DAO/Repository Class repository.TasksDAO
1public List<Tasks> getAllTodoTasks() {
2  return list(namedTypedQuery("com.myzonesoft.todo.microservice.model.Tasks.findAll"));
3}
  • Update Resource/Controller Class, for exposing the REST APIs = controller.TodoController
1@GET
2@UnitOfWork
3public Response getAllTodoTasks() {
4  return Response.ok(tasksDAO.getAllTodoTasks()).build();
5}

Now, Open any REST client and provide values, as per the below table and see the response from the server.

HTTP Method Endpoint URL
GET http://localhost:8080/todo-app/tasks

find-all-api-response.jpeg
Server Response for GET All API call


Add REST API Endpoint for GET Operation

Description CRUD Operation HTTP Method REST API Endpoint
Fetch One Todo Task READ GET /tasks/{id}

For creating this endpoint, we would need to update following classes:

  • Update DAO/Repository Class repository.TasksDAO
1public Optional<Tasks> getById(Long systemTasksId) {
2  return Optional.ofNullable(get(systemTasksId));
3}
  • Update Resource/Controller Class, for exposing the REST APIs = controller.TodoController
1@GET
2@Path("/{id}")
3@UnitOfWork
4public Optional<Tasks> getById(@PathParam("id") Long id) {
5  return tasksDAO.getById(id);
6}

Now, Open any REST client and provide values, as per the below table and see the response from the server.

HTTP Method Endpoint URL
GET http://localhost:8080/todo-app/tasks/1

find-one-api-response.jpeg
Server Response for GET API call


Add REST API Endpoint for UPDATE Operation

Description CRUD Operation HTTP Method REST API Endpoint
Update One Specific Todo Task UPDATE PUT /tasks

For creating this endpoint, we would need to update following classes:

  • Update Resource/Controller Class, for exposing the REST APIs = controller.TodoController
1@PUT
2@UnitOfWork
3@Consumes(MediaType.APPLICATION_JSON)
4public Response updateTasks(Tasks tasks) {
5  return Response.accepted(tasksDAO.createOrUpdateTask(tasks)).build();
6}

Now, Open any REST client and provide values, as per the below table and see the response from the server.

HTTP MethodPUT
Endpoint URLhttp://localhost:8080/todo-app/tasks
Request HeaderContent-type: application/json
Request Body{
  "systemTasksId": 1,
  "title": "Testing the Application",
  "description": "Testing the Application",
  "creationDate": "2022-06-27",
  "dueDate": "2022-06-30",
  "status": "IN_PROGRESS",
  "todoTaskCommentsSet": [{
    "taskComments": "Testing comments 1"
  }]
}

update-api-response.jpeg
Server Response for PUT API call


Add REST API Endpoint for DELETE Operation

Description CRUD Operation HTTP Method REST API Endpoint
Delete One Specific Todo Task DELETE DELETE /tasks/{id}

For creating this endpoint, we would need to update following classes:

  • Update DAO/Repository Class repository.TasksDAO
 1public boolean deleteTask(Long id){
 2  boolean isDeleted = false;
 3  try{
 4      //Delete the TaskComments before deleting the tasks.
 5      Optional<Tasks> deletionTask = getById(id);
 6      if(deletionTask.isPresent()){
 7          Set<TodoTaskComments> todoTaskCommentsSet = deletionTask.get().getTodoTaskCommentsSet();
 8          if (todoTaskCommentsSet != null) {
 9              for (TodoTaskComments todoTaskComment : todoTaskCommentsSet) {
10                  todoTaskCommentsDAO.deleteTodoTaskComments(todoTaskComment);
11              }
12          }
13          currentSession().delete(deletionTask.get());
14          isDeleted = true;
15      }
16  } catch (Exception ex) {
17      ex.getMessage();
18  }
19  return isDeleted;
20}
  • Update DAO/Repository Class repository.TodoTasksCommentsDAO
1public void deleteTodoTaskComments(TodoTaskComments todoTaskComments) {
2  currentSession().delete(todoTaskComments);
3}
  • Update Resource/Controller Class, for exposing the REST APIs = controller.TodoController
 1@DELETE
 2@Path("/{id}")
 3@UnitOfWork
 4public Response deleteTask(@PathParam("id") Long id) {
 5  try{
 6      if(tasksDAO.deleteTask(id))
 7          return Response.noContent().build();
 8  } catch (IllegalArgumentException exception) {
 9      return Response.serverError().build();
10  }
11  return Response.status(Response.Status.NOT_FOUND).build();
12}

Now, Open any REST client and provide values, as per the below table

HTTP Method Endpoint URL
DELETE http://localhost:8080/todo-app/tasks/1

Response from the Server

delete-api-response.jpeg
Server Response for /deleteById/{id} DELETE API call


Configure Dropwizard to Handle CORS Request

By default, the Dropwizard Server which is running on http://localhost:8080/, will not allow requests from frontend applications through domains like http://localhost:3000/.

This is called CORS (Cross-Origin Resource Sharing) policy, where in by default, servers block request coming from other servers or domains.

Let’s configure Dropwizard Application to allow access from specific server(s), in order to allow our frontend applications(will be developed later) to make REST APIs calls to this application.

  • Update the run method of the Application Class to include the CORS update = MicroserviceDropwizardH2Application
1final FilterRegistration.Dynamic cors = environment.servlets().addFilter("CORS", CrossOriginFilter.class);
2
3cors.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "http://localhost:3000");
4cors.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "X-Requested-With,Content-Type,Accept,Origin,Authorization");
5cors.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "OPTIONS,GET,PUT,POST,DELETE,HEAD");
6cors.setInitParameter(CrossOriginFilter.ALLOW_CREDENTIALS_PARAM, "true");
7
8// Add URL mapping
9cors.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");

Conclusion

With these endpoints’ setup, we have come to an end of this article and we have enabled CRUD (Create, Read, Update, Delete) Operations using below REST API Endpoints and they are ready to be consumed by any frontend or other microservice applications.

Description CRUD Operation HTTP Method REST API Endpoint
Create New Todo Task CREATE POST /tasks
Fetch All Todo Tasks READ GET /tasks
Fetch One Todo Task READ GET /tasks/{id}
Update One Specific Todo Task UPDATE PUT /tasks
Delete One Specific Todo Task DELETE DELETE /tasks/{id}

Through this article, you have learned about how to:

  • Configure Hibernate to work with Relational Database and persist the data.
  • Create and Expose REST APIs for CRUD Operations using Dropwizard Framework.
  • How to handle HTTP and CORS Requests through REST Controller.

Complete code for this project can be found at GitHub here.

Instructions on how to clone the code repository and run the project are provided on the GitHub project page.