Skip to content
Back to skills

Quarkus Service Architecture

ASecurity

Use when building or extending a Java service with Quarkus - layered architecture, JAX-RS resources, CDI beans, Panache persistence, and native-friendly patterns

  • 109 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 19, 2026
ai-agentsgojavareacttestingapidatabase

Works with

  • api

Security analysis

A100/100

Scanned October 2, 2026

npx -y skills add makifbaysal/tasktrooper --skill quarkus-service-architecture --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Quarkus Service Architecture?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Quarkus Service Architecture
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/makifbaysal-quarkus-service-architecture/badge)](https://www.skillsdirectory.com/skills/makifbaysal-quarkus-service-architecture)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: quarkus-service-architecture
category: architecture
description: Use when building or extending a Java service with Quarkus - layered architecture, JAX-RS resources, CDI beans, Panache persistence, and native-friendly patterns
tech_stack: Java
---
# Quarkus Service Architecture

## Overview

Quarkus is the default Java stack: fast startup, low memory, native-image friendly — the closest Java gets to Go's operational profile. Build services in clean layers so the framework stays at the edges and the domain stays plain Java.

**Core principle:** Framework annotations live at the boundaries (resources, repositories). The domain and services are plain classes you can unit-test without booting Quarkus.

## Layers

| Layer | Responsibility | Quarkus surface |
|-------|----------------|-----------------|
| Resource | HTTP in/out, validation, status codes | `@Path`, JAX-RS (`@GET`/`@POST`), `@Valid` |
| Service | Use-case orchestration, business rules | `@ApplicationScoped` CDI bean, constructor-injected |
| Domain | Entities, value objects, invariants | plain Java, no annotations driving behavior |
| Repository | Persistence | Panache (`PanacheRepository`) or JPA |

Dependencies point inward: resource → service → domain; repository implements a port the service depends on. A resource never contains business logic; a service never touches `RoutingContext` or JAX-RS types.

## Patterns

- **Constructor injection**, not field injection: `public TaskService(TaskRepository repo)`. Constructor injection is testable without CDI and makes dependencies explicit.
- **DTOs at the edge**: resources accept/return DTOs (records), map to/from domain in the service. Never expose JPA entities directly over HTTP.
- **Bean Validation** on request DTOs (`@NotNull`, `@Size(max=200)`) + `@Valid` on the resource method — validate at the boundary, reject early.
- **Reactive vs imperative**: default to imperative (Quarkus REST — formerly branded "RESTEasy Reactive" — with blocking) unless the task is genuinely reactive; don't sprinkle `Uni`/`Multi` without cause. A blocking-I/O-heavy endpoint on Java 21+ may run on a virtual thread instead (`@RunOnVirtualThread`) rather than going reactive.
- **Config** via `@ConfigProperty` from `application.properties`/env — never hardcode. Group related settings with `@ConfigMapping` instead of a pile of individual `@ConfigProperty` fields.
- **Error mapping** centrally with `@ServerExceptionMapper`, returning `RestResponse<ProblemDto>` (or the repo's equivalent) — not a `try/catch` per resource method (api-design-conventions has the shape).
- **Dev Services** start a throwaway Postgres automatically in dev/test when no `quarkus.datasource.jdbc.url` is set — don't hand-wire a local Postgres for local iteration unless the repo has opted out.
- **Schema management** outside tests is `quarkus.hibernate-orm.schema-management.strategy=none` (or `validate`); this property was renamed from `quarkus.hibernate-orm.database.generation` in 3.23 — use the current name unless the repo is pinned to an older Quarkus.
- Target the current LTS (3.40, supported to 2027-09); never move a repo onto the Quarkus 4 beta in a feature task.

## Worked Example

`POST /tasks` creating a task:

```java
// resource (boundary)
@Path("/tasks")
public class TaskResource {
    private final TaskService service;
    public TaskResource(TaskService service) { this.service = service; }

    @POST
    public Response create(@Valid CreateTaskRequest req) {
        Task t = service.create(req.title());
        return Response.status(201).entity(TaskResponse.from(t)).build();
    }
}

// service (plain, unit-testable without Quarkus)
@ApplicationScoped
public class TaskService {
    private final TaskRepository repo;
    public TaskService(TaskRepository repo) { this.repo = repo; }

    @Transactional
    public Task create(String title) {
        Task t = Task.create(title);   // domain enforces the <=200 invariant
        repo.persist(t);
        return t;
    }
}
```

`CreateTaskRequest` is a record with `@Size(max=200) String title`. The `<=200` invariant is ALSO enforced in `Task.create` so the rule holds even when called from a non-HTTP path.

## Common Mistakes

- Business logic in the resource — it belongs in the service.
- Returning JPA entities over HTTP (leaks schema, causes lazy-loading serialization errors).
- Field injection (`@Inject` on a field) — breaks plain unit testing.
- `@Transactional` on the resource instead of the service.

## Red Flags

- A JAX-RS import inside a domain or service test.
- A service method that takes a JAX-RS or servlet type.
- Validation only on the DTO, with the domain invariant unprotected.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…