
Quarkus Patterns
- 2k installs
- 234k repo stars
- Updated July 27, 2026
- affaan-m/everything-claude-code
quarkus-patterns teaches Quarkus 3.x REST, CDI, Panache, and Camel integration architecture patterns.
About
The quarkus-patterns ECC skill documents cloud-native Quarkus architecture with JAX-RS or RESTEasy Reactive resources, service layers using ApplicationScoped CDI, Hibernate Panache repositories, Apache Camel RabbitMQ publishers, validation, exception mapping, pagination, and profile-specific YAML config. Examples show OrderProcessingService with RequiredArgsConstructor injection, transactional boundaries, async fulfillment publishers, and custom LogContext MDC patterns. Activation covers event-driven flows, CompletableFuture async work, GraalVM native compilation, and environment profiles for dev staging prod. Catalog SKILL content is Spanish-language with upstream ECC origin. Use when building Quarkus APIs, structuring resource-service-repository layers, or integrating Camel messaging in JVM microservices.
- Documents resource, service, repository layering with CDI injection.
- Covers Panache persistence, Camel async publishers, and transactions.
- Includes custom LogContext and structured logging patterns.
- Supports RESTEasy Reactive APIs and GraalVM native targets.
- Profiles YAML configuration across dev, staging, and production.
Quarkus Patterns by the numbers
- 1,982 all-time installs (skills.sh)
- +284 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #7 of 89 Java & JVM skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
quarkus-patterns capabilities & compatibility
- Capabilities
- cdi service design · panache persistence · camel messaging
- Use cases
- api development · devops
npx skills add https://github.com/affaan-m/everything-claude-code --skill quarkus-patternsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2k |
|---|---|
| repo stars | ★ 234k |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 27, 2026 |
| Repository | affaan-m/everything-claude-code ↗ |
How should I structure a Quarkus microservice with messaging and Panache?
Apply Quarkus 3.x LTS patterns for REST APIs, CDI services, Panache data access, Camel messaging, and GraalVM native builds.
Who is it for?
Quarkus 3 cloud-native APIs with Camel and Hibernate Panache.
Skip if: Non-JVM frameworks or Spring-only projects without Quarkus.
When should I use this skill?
User builds Quarkus APIs, Camel RabbitMQ, or Panache data layers.
What you get
Layered Quarkus service code following ECC transactional and async messaging conventions.
- REST resource classes
- Camel route configurations
- Panache repository entities
By the numbers
- Targets Quarkus 3.x LTS architecture patterns
Files
Patrones de Desarrollo Quarkus
Patrones de arquitectura y API de Quarkus 3.x para servicios cloud-native y orientados a eventos con Apache Camel.
Cuándo Activar
- Construir APIs REST con JAX-RS o RESTEasy Reactive
- Estructurar capas resource → service → repository
- Implementar patrones orientados a eventos con Apache Camel y RabbitMQ
- Configurar Hibernate Panache, caché o streams reactivos
- Agregar validación, mapeo de excepciones o paginación
- Configurar perfiles para entornos dev/staging/producción (configuración YAML)
- Logging personalizado con LogContext y Logback/Logstash encoder
- Trabajar con CompletableFuture para operaciones asíncronas
- Implementar procesamiento condicional de flujos
- Trabajar con compilación nativa GraalVM
Capa de Servicio con Múltiples Dependencias
@Slf4j
@ApplicationScoped
@RequiredArgsConstructor
public class OrderProcessingService {
private final OrderValidator orderValidator;
private final EventService eventService;
private final OrderRepository orderRepository;
private final FulfillmentPublisher fulfillmentPublisher;
private final AuditPublisher auditPublisher;
@Transactional
public OrderReceipt process(CreateOrderCommand command) {
ValidationResult validation = orderValidator.validate(command);
if (!validation.valid()) {
eventService.createErrorEvent(command, "ORDER_REJECTED", validation.message());
throw new WebApplicationException(validation.message(), Response.Status.BAD_REQUEST);
}
Order order = Order.from(command);
orderRepository.persist(order);
OrderReceipt receipt = OrderReceipt.from(order);
fulfillmentPublisher.publishAsync(receipt);
auditPublisher.publish("ORDER_ACCEPTED", receipt);
eventService.createSuccessEvent(receipt, "ORDER_ACCEPTED");
log.info("Orden procesada {}", order.id);
return receipt;
}
}Patrones Clave:
@RequiredArgsConstructorpara inyección por constructor mediante Lombok@Slf4jpara logging con Logback@Transactionalen métodos de servicio que escriben a través de Panache o repositorios- Validar entrada antes de persistencia o publicación de mensajes
- Seguimiento de eventos para escenarios de éxito/error
- Publicación asíncrona de mensajes Camel
Patrón de Contexto de Logging Personalizado (Logback)
@ApplicationScoped
public class ProcessingService {
public void processDocument(Document doc) {
LogContext logContext = CustomLog.getCurrentContext();
try (SafeAutoCloseable ignored = CustomLog.startScope(logContext)) {
logContext.put("documentId", doc.getId().toString());
logContext.put("documentType", doc.getType());
logContext.put("userId", SecurityContext.getUserId());
log.info("Iniciando procesamiento de documento");
processInternal(doc);
log.info("Procesamiento de documento completado");
} catch (Exception e) {
log.error("Error en el procesamiento de documento", e);
throw e;
}
}
}Configuración de Logback (logback.xml):
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<includeContext>true</includeContext>
<includeMdc>true</includeMdc>
</encoder>
</appender>
<logger name="com.example" level="INFO"/>
<root level="WARN">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>Patrón de Servicio de Eventos
@Slf4j
@ApplicationScoped
@RequiredArgsConstructor
public class EventService {
private final EventRepository eventRepository;
private final ObjectMapper objectMapper;
public void createSuccessEvent(Object payload, String eventType) {
Objects.requireNonNull(payload, "El payload no puede ser null");
Event event = new Event();
event.setType(eventType);
event.setStatus(EventStatus.SUCCESS);
event.setPayload(serializePayload(payload));
event.setTimestamp(Instant.now());
eventRepository.persist(event);
log.info("Evento de éxito creado: {}", eventType);
}
public void createErrorEvent(Object payload, String eventType, String errorMessage) {
Objects.requireNonNull(payload, "El payload no puede ser null");
if (errorMessage == null || errorMessage.isBlank()) {
throw new IllegalArgumentException("El mensaje de error no puede estar en blanco");
}
Event event = new Event();
event.setType(eventType);
event.setStatus(EventStatus.ERROR);
event.setErrorMessage(errorMessage);
event.setPayload(serializePayload(payload));
event.setTimestamp(Instant.now());
eventRepository.persist(event);
log.error("Evento de error creado: {} - {}", eventType, errorMessage);
}
private String serializePayload(Object payload) {
try {
return objectMapper.writeValueAsString(payload);
} catch (JsonProcessingException e) {
throw new IllegalStateException("Error al serializar el payload del evento", e);
}
}
}Publicación de Mensajes Camel (RabbitMQ)
@Slf4j
@ApplicationScoped
@RequiredArgsConstructor
public class BusinessRulesPublisher {
private final ProducerTemplate producerTemplate;
public void publishSync(BusinessRulesPayload payload) {
producerTemplate.sendBody(
"direct:business-rules-publisher",
payload
);
}
}Configuración de Ruta Camel:
@ApplicationScoped
public class BusinessRulesRoute extends RouteBuilder {
@ConfigProperty(name = "camel.rabbitmq.queue.business-rules")
String businessRulesQueue;
@ConfigProperty(name = "rabbitmq.host")
String rabbitHost;
@ConfigProperty(name = "rabbitmq.port")
Integer rabbitPort;
@Override
public void configure() {
from("direct:business-rules-publisher")
.routeId("business-rules-publisher")
.log("Publicando mensaje en RabbitMQ: ${body}")
.marshal().json(JsonLibrary.Jackson)
.toF("spring-rabbitmq:%s?hostname=%s&portNumber=%d",
businessRulesQueue, rabbitHost, rabbitPort);
}
}Rutas Camel Direct (En Memoria)
@ApplicationScoped
public class DocumentProcessingRoute extends RouteBuilder {
@Override
public void configure() {
onException(ValidationException.class)
.handled(true)
.to("direct:validation-error-handler")
.log("Error de validación: ${exception.message}");
from("direct:process-document")
.routeId("document-processing")
.log("Procesando documento: ${header.documentId}")
.bean(DocumentValidator.class, "validate")
.bean(DocumentTransformer.class, "transform")
.choice()
.when(header("documentType").isEqualTo("INVOICE"))
.to("direct:process-invoice")
.when(header("documentType").isEqualTo("CREDIT_NOTE"))
.to("direct:process-credit-note")
.otherwise()
.to("direct:process-generic")
.end();
}
}Procesamiento de Archivos Camel
@ApplicationScoped
public class FileMonitoringRoute extends RouteBuilder {
@ConfigProperty(name = "file.input.directory")
String inputDirectory;
@ConfigProperty(name = "file.processed.directory")
String processedDirectory;
@ConfigProperty(name = "file.error.directory")
String errorDirectory;
@Override
public void configure() {
from("file:" + inputDirectory + "?move=" + processedDirectory +
"&moveFailed=" + errorDirectory + "&delay=5000")
.routeId("file-monitor")
.log("Procesando archivo: ${header.CamelFileName}")
.to("direct:process-file");
}
}Estructura de API REST
@Path("/api/documents")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@RequiredArgsConstructor
public class DocumentResource {
private final DocumentService documentService;
@GET
public Response list(
@QueryParam("page") @DefaultValue("0") int page,
@QueryParam("size") @DefaultValue("20") int size) {
List<Document> documents = documentService.list(page, size);
return Response.ok(documents).build();
}
@POST
public Response create(@Valid CreateDocumentRequest request, @Context UriInfo uriInfo) {
Document document = documentService.create(request);
URI location = uriInfo.getAbsolutePathBuilder()
.path(String.valueOf(document.id))
.build();
return Response.created(location).entity(DocumentResponse.from(document)).build();
}
@GET
@Path("/{id}")
public Response getById(@PathParam("id") Long id) {
return documentService.findById(id)
.map(DocumentResponse::from)
.map(Response::ok)
.orElse(Response.status(Response.Status.NOT_FOUND))
.build();
}
}Patrón de Repositorio (Panache Repository)
@ApplicationScoped
public class DocumentRepository implements PanacheRepository<Document> {
public List<Document> findByStatus(DocumentStatus status, int page, int size) {
return find("status = ?1 order by createdAt desc", status)
.page(page, size)
.list();
}
public Optional<Document> findByReferenceNumber(String referenceNumber) {
return find("referenceNumber", referenceNumber).firstResultOptional();
}
}Capa de Servicio con Transacciones
@ApplicationScoped
@RequiredArgsConstructor
public class DocumentService {
private final DocumentRepository repo;
private final EventService eventService;
@Transactional
public Document create(CreateDocumentRequest request) {
Document document = new Document();
document.setReferenceNumber(request.referenceNumber());
document.setDescription(request.description());
document.setStatus(DocumentStatus.PENDING);
document.setCreatedAt(Instant.now());
repo.persist(document);
eventService.createSuccessEvent(document, "DOCUMENT_CREATED");
return document;
}
}DTOs y Validación
public record CreateDocumentRequest(
@NotBlank @Size(max = 200) String referenceNumber,
@NotBlank @Size(max = 2000) String description,
@NotNull @FutureOrPresent Instant validUntil,
@NotEmpty List<@NotBlank String> categories) {}
public record DocumentResponse(Long id, String referenceNumber, DocumentStatus status) {
public static DocumentResponse from(Document document) {
return new DocumentResponse(document.getId(), document.getReferenceNumber(),
document.getStatus());
}
}Mapeo de Excepciones
@Provider
public class ValidationExceptionMapper implements ExceptionMapper<ConstraintViolationException> {
@Override
public Response toResponse(ConstraintViolationException exception) {
String message = exception.getConstraintViolations().stream()
.map(cv -> cv.getPropertyPath() + ": " + cv.getMessage())
.collect(Collectors.joining(", "));
return Response.status(Response.Status.BAD_REQUEST)
.entity(Map.of("error", "validation_error", "message", message))
.build();
}
}Operaciones Asíncronas con CompletableFuture
@Slf4j
@ApplicationScoped
@RequiredArgsConstructor
public class FileStorageService {
private final S3Client s3Client;
private final ExecutorService executorService;
public CompletableFuture<StoredDocumentInfo> uploadOriginalFile(
InputStream inputStream,
long size,
LogContext logContext,
InvoiceFormat format) {
return CompletableFuture.supplyAsync(() -> {
try (SafeAutoCloseable ignored = CustomLog.startScope(logContext)) {
String path = generateStoragePath(format);
PutObjectRequest request = PutObjectRequest.builder()
.bucket(bucketName)
.key(path)
.contentLength(size)
.build();
s3Client.putObject(request, RequestBody.fromInputStream(inputStream, size));
return new StoredDocumentInfo(path, size, Instant.now());
} catch (Exception e) {
log.error("Error al subir archivo a S3", e);
throw new StorageException("Subida fallida", e);
}
}, executorService);
}
}Caché
@ApplicationScoped
@RequiredArgsConstructor
public class DocumentCacheService {
private final DocumentRepository repo;
@CacheResult(cacheName = "document-cache")
public Optional<Document> getById(@CacheKey Long id) {
return repo.findByIdOptional(id);
}
@CacheInvalidate(cacheName = "document-cache")
public void evict(@CacheKey Long id) {}
}Configuración como YAML
# application.yml
"%dev":
quarkus:
datasource:
jdbc:
url: jdbc:postgresql://localhost:5432/dev_db
username: dev_user
password: ${DB_PASSWORD}
"%test":
quarkus:
datasource:
jdbc:
url: jdbc:h2:mem:test
hibernate-orm:
database:
generation: drop-and-create
"%prod":
quarkus:
datasource:
jdbc:
url: ${DATABASE_URL}
username: ${DB_USER}
password: ${DB_PASSWORD}Health Checks
@Readiness
@ApplicationScoped
@RequiredArgsConstructor
public class DatabaseHealthCheck implements HealthCheck {
private final AgroalDataSource dataSource;
@Override
public HealthCheckResponse call() {
try (Connection conn = dataSource.getConnection()) {
boolean valid = conn.isValid(2);
return HealthCheckResponse.named("Database connection")
.status(valid)
.build();
} catch (SQLException e) {
return HealthCheckResponse.down("Database connection");
}
}
}Dependencias (Maven)
<properties>
<quarkus.platform.version>3.27.0</quarkus.platform.version>
<lombok.version>1.18.42</lombok.version>
<assertj-core.version>3.24.2</assertj-core.version>
<jacoco-maven-plugin.version>0.8.13</jacoco-maven-plugin.version>
<maven.compiler.release>17</maven.compiler.release>
</properties>Buenas Prácticas
Arquitectura
- Usar
@RequiredArgsConstructorcon Lombok para inyección por constructor - Mantener la capa de servicio delgada; delegar lógica compleja a clases especializadas
- Usar rutas Camel para enrutamiento de mensajes y patrones de integración
- Preferir el patrón Panache Repository para acceso a datos
Orientado a Eventos
- Siempre rastrear operaciones con EventService (eventos de éxito/error)
- Usar endpoints
direct:de Camel para enrutamiento en memoria - Usar el componente
spring-rabbitmqpara integración con RabbitMQ
Logging
- Usar Logback con Logstash encoder para logging estructurado
- Propagar LogContext a través de llamadas de servicio con
SafeAutoCloseable - Usar
@Slf4jen lugar de instanciación manual del logger
Configuración
- Usar configuración YAML (
quarkus-config-yaml) - Configuración consciente de perfil para entornos dev/test/prod
- Externalizar configuración sensible a variables de entorno
Related skills
Forks & variants (1)
Quarkus Patterns has 1 known copy in the catalog totaling 1.3k installs. They canonicalize to this original listing.
- affaan-m - 1.3k installs
How it compares
Use Quarkus Patterns when agents must emit Quarkus-native Camel and Panache structure instead of generic Spring-style Java snippets.
FAQ
What layering does quarkus-patterns use?
Resource to service to repository with ApplicationScoped CDI and transactions on writes.
Does it cover messaging?
Yes, including Apache Camel async publishers and event tracking patterns.
Is native compilation included?
Yes, GraalVM native build considerations are in scope.
Is Quarkus Patterns safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.