Microservice Using Dropwizard, Hibernate and H2 Database
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.
Other related software
Web Application– Jetty is embedded in the Dropwizard Framework and can be used as Web application for running this project.
Project Management Tool– Dropwizard 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.
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
- Open Run/Debug Configuration menu by selecting
Run -> Edit Configurations
from the menu. - Add a new configuration by pressing Alt+Insert or clicking the green plus sign in the top left corner.
- From the dropdown menu, select Application.
- Add a name to the configuration.
- Enter the fully qualified name of your main class.
- Enter
server configuration.yml
to the Program arguments field (if you do not have anyconfiguration.yml
, as yet, you can only enterserver
). - Press Shift+F10 or select
Run -> Run <<your run configuration name>>
from the menu to start your Dropwizard application.
Server start
Your Dropwizard application is now listening on ports 8080
for application requests and 8081
for administration requests.
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 |
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:
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.
- 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}
- 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
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 Method | POST |
Endpoint URL | http://localhost:8080/todo-app/tasks |
Request Header | Content-type: application/json |
Request Body | { |
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 |
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 |
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 Method | PUT |
Endpoint URL | http://localhost:8080/todo-app/tasks |
Request Header | Content-type: application/json |
Request Body | { |
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
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.