This project contains boilerplate code to turn simple quarkus rest-api development. Uses the Strategy Design Pattern and Template Method Design Pattern to define different behaviors for each application domain.
Note
See How to install guide to add the project maven dependency from github packages.
A Rest controller that provides an end-point with CRUD Operations (http verbs GET, CREATE, UPDATE and DELETE) can be easily implemented just by inserting respectively the types of the Data Transfer Object (DTO)
, Entity
, Service
, and Assembly
classes as arguments in the diamond operator <>
.
@Path("/foos")
public class FooController extends AbstractPanacheController<FooDTO, FooEntity, FooService, FooAssembler> {
}
Note that @Path
has /foos
as argument, so the end-points will be:
Http Verb | Uri |
---|---|
GET | /foos |
CREATE | /foos |
UPDATE | /foos/{id} |
DELETE | /foos/{id} |
If is necessary implement some code before or after Service
bussiness logic, override the before or after methods.
In following exemple a property of object received from CREATE
request is changed before it is passed to service layer.
@Path("/foos")
public class FooController extends AbstractPanacheController<FooDTO, FooEntity, FooService, FooAssembler> {
@Override
public void beforeCreate(FooDto dto) {
dto.someProperty = "new value";
}
}
Note
See JavaDoc to abstract classes details.
The assembler must have overridden methods to perform the mapping between Entity
and DTO
classes, for UPDATE
it must map the object attached to the database to the object with the new data as shown in the example.
@ApplicationScoped
public class FooAssembler extends AbstractPanacheAssembly<FooDTO, FooEntity> {
@Override
public FooEntity assembly(FooDTO dto) {
return FooEntity.builder()
.name(dto.name)
.age(dto.age)
.build();
}
@Override
public FooDTO assembly(FooEntity entity) {
return FooDTO.builder()
.id(entity.id)
.name(entity.name)
.age(entity.age)
.build();
}
@Override
public void fillToAttachedEntity(FooEntity attached, FooEntity detached) {
attached.name = detached.name;
attached.age = detached.age;
}
}
Tip
Additionally, the MapStruct dependency can help to automatically assembly code generation.
Similarly to Controller Implementation, Service
class need extends AbstractPanacheService
type and passes the Entity
type as an argument to the diamond operator <>
.
However, due to the way quarkus works, to avoid the use of reflection, there are 3 methods that must be overridden with the call to static methods through the entities that inherit from PanacheEntity.
@ApplicationScoped
public class FooService extends AbstractPanacheService<FooEntity> {
@Override
protected List<FooEntity> findStaticMethod() {
return FooEntity.<FooEntity>findAll().stream().toList();
}
@Override
protected FooEntity findByIdStatidMethod(Long id) {
return FooEntity.findById(id);
}
@Override
protected void deleteByIdStaticMethod(Long id) {
FooEntity.deleteById(id);
}
}
The bussiness logic can be declared into before and after methods.
@ApplicationScoped
public class FooService extends AbstractPanacheService<FooEntity> {
@Override
public beforeUpdade(Long id, FooEntity enitity) {
// ...some bussiness logic
}
@Override
public afterUpdate(Long id, FooEntity entity) {
// ...some bussiness logic
}
// ...Overriden static call methods
}
Classes annotated with @Entity
must extend the PanacheEntity
class.
@Entity
@Table(name = "foo")
public class FooEntity extends PanacheEntity {
public String name;
public Integer age;
}