Exercise with Javalin and CRUD
Part 1 setup project
- Setup a new maven project in IntelliJ
- Add the following dependencies to the pom.xml file:
- Add necessary dependencies to pom.xml:
- Javalin
- JUnit
- Gson or Jackson
- hibernate
- postgresql
- Create a new javalin application with 2 ressources:
Hotel
andRoom
- Create a new database in postgresql called
hotel
- Create a IDAO generic interface with the following methods: *)
- getAll()
- getById()
- create()
- update()
- delete()
- Create an abstract DAO class that implements the IDAO interface *)
- Create a HotelDAO and a RoomDAO that extends the abstract DAO class
- Add a method to the HotelDAO that returns all rooms for a specific hotel
*) NB! If you have trouble with inheritance and generics, you can skip the generic interface and abstract class and just create the DAO classes with the methods you need. You should also see the hint at the end of this document for more details.
Part 2 DTOs
- Create a HotelDTO and a RoomDTO with the following fields: HotelDTO:
- id
- name
- address
- rooms
RoomDTO:
- id
- hotelId
- number
- price
- Implement functionality to convert between DTOs and Entities. Both ways.
Part 3 create API Ressources
- Create a HotelController and a RoomController that handles the above functionality using the DTOs
- Create a new Routes.java file that contains all routes for the application and implement the following routes with json:
- GET /hotel
- response json:
[{id: 1, name: "Hotel 1", address: "Address 1"}, {id: 2, name: "Hotel 2", address: "Address 2"}]
- response json:
- GET /hotel/{id}
- response json:
{id: 1, name: "Hotel 1", address: "Address 1"}
- response json:
- GET /hotel/{id}/rooms
- response json:
[{id: 1, hotelId: 1, number: 1, price: 100}, {id: 2, hotelId: 1, number: 2, price: 200}]
- response json:
- POST /hotel
- request json:
{name: "Hotel 3", address: "Address 3"}
- response json:
{id: 3, name: "Hotel 3", address: "Address 3"}
- request json:
- PUT /hotel/{id}
- request json:
{name: "Hotel renamedHotel", address: "Address 1"}
- response json:
{id: 1, name: "Hotel renamedHotel", address: "Address 1"}
- request json:
- DELETE /hotel/{id}
- response json:
{id: 1, name: "Hotel 1", address: "Address 1"}
- response json:
- GET /room
- Response json:
[{id: 1, hotelId: 1, number: 1, price: 100}, {id: 2, hotelId: 1, number: 2, price: 200}]
- Response json:
- GET /room/{id}
- Response json
{id: 1, hotelId: 1, number: 1, price: 100}
- Response json
- POST /room
- Request json
{hotelId: 1, number: 1, price: 100}
- Response json
{id: 1, hotelId: 1, number: 1, price: 100}
- Request json
- PUT /room/{id}
- Request json:
{hotelId: 1, number: 1234, price: 333}
- Response json
{id: 1, hotelId: 1, number: 1234, price: 333}
- Request json:
- DELETE /room/{id}
- Response json:
{id: 1, hotelId: 1, number: 1, price: 100}
- Response json:
- GET /hotel
In above api, if no request json is specified, then the request body should be empty.
NB! Use an http file to test the endpoints.
Part 4 Error handling
- Implement app.error() to handle:
- 404 Not Found (used for both missing resources and missing routes)
- Implement app.exception() to handle:
- IllegalStateException: When posting or updating a hotel or room with incorrect json representation.
Part 5: (Optional) logging
Use our small tutorial from yesterday and use LogBack to log requests, responses, and exceptions.
- Implement logging for all requests and responses
- Include the following information in the log:
- Timestamp
- Request method
- Request path
- Request body
- Response status code
- Response body
Part 6 (Optional) Documentation
- Configure javalin to use
RouteOverviewPlugin
to create an interactive documentation of your API.
Monday review
- Prepare a short presentation of your API for Monday’s review session. You will have 5 minutes to present your API and show how it works. You can use an http file to demonstrate the API.
Hint on generics and inheritance
When implementing your DAOs, consider creating a generic IDAO
interface and an AbstractDAO
class to handle common CRUD operations for any entity type. This approach helps reduce code duplication and makes your code more maintainable. Here’s a quick guide:
-
Define the
IDAO
Interface: This interface should specify basic CRUD methods (getAll()
,getById()
,create()
,update()
,delete()
) using generics (<T>
) to handle different types of entities. -
Create an
AbstractDAO
Class: Implement theIDAO
interface in an abstract class calledAbstractDAO
. This class will provide common implementations of CRUD methods, utilizing anEntityManager
for database interactions. Use generics to make it flexible for any entity type. -
Extend
AbstractDAO
in Specific DAOs: Create concrete DAO classes likeHotelDAO
andRoomDAO
that extendAbstractDAO
. These classes can inherit the common CRUD functionality and add any specific methods needed for their respective entities, such as fetching all rooms for a particular hotel inHotelDAO
. -
Example Method Signatures:
- In
IDAO
:List<T> getAll();
- In
AbstractDAO
:public List<T> getAll() { // common implementation }
- In
HotelDAO
:public List<Room> getRoomsForHotel(int hotelId) { // specific implementation }
- In
If you find generics and inheritance challenging, you can skip this approach and directly implement the required CRUD methods in your DAO classes (HotelDAO
and RoomDAO
). However, using the interface and abstract class will make your code cleaner and more reusable.