Quarkus Patterns
affaan-m/ECC
Quarkus 3.x LTS architecture patterns with Camel for messaging, RESTful API design, CDI services, data access with Panache, and async processing.
Reviews REST API design for correct HTTP verbs, versioning, DTO use, consistent responses and backward compatibility before an API change ships.
$ npx skills add decebals/claude-code-java --skill api-contract-review -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install decebals/claude-code-java api-contract-review --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/decebals/claude-code-java.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/api-contract-review .claude/skills/api-contract-review && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "api-contract-review" agent skill from https://github.com/decebals/claude-code-java/tree/main/skills/api-contract-review into .claude/skills/api-contract-review/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "api-contract-review", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/decebals/claude-code-java/tree/main/skills/api-contract-reviewType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add decebals/claude-code-java --skill api-contract-review -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install decebals/claude-code-java api-contract-review --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/decebals/claude-code-java.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/api-contract-review .agents/skills/api-contract-review && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "api-contract-review" agent skill from https://github.com/decebals/claude-code-java/tree/main/skills/api-contract-review into .agents/skills/api-contract-review/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "api-contract-review", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add decebals/claude-code-java --skill api-contract-review -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install decebals/claude-code-java api-contract-review --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/decebals/claude-code-java.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/api-contract-review .cursor/skills/api-contract-review && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "api-contract-review" agent skill from https://github.com/decebals/claude-code-java/tree/main/skills/api-contract-review into .cursor/skills/api-contract-review/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "api-contract-review", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/decebals/claude-code-java.git --path skills/api-contract-review--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add decebals/claude-code-java --skill api-contract-review -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install decebals/claude-code-java api-contract-review --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/decebals/claude-code-java.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/api-contract-review .gemini/skills/api-contract-review && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "api-contract-review" agent skill from https://github.com/decebals/claude-code-java/tree/main/skills/api-contract-review into .gemini/skills/api-contract-review/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "api-contract-review", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install decebals/claude-code-java api-contract-reviewInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add decebals/claude-code-java --skill api-contract-review -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/decebals/claude-code-java.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/api-contract-review .github/skills/api-contract-review && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "api-contract-review" agent skill from https://github.com/decebals/claude-code-java/tree/main/skills/api-contract-review into .github/skills/api-contract-review/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "api-contract-review", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add decebals/claude-code-java --skill api-contract-review -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install decebals/claude-code-java api-contract-review --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/decebals/claude-code-java.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/api-contract-review .opencode/skills/api-contract-review && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "api-contract-review" agent skill from https://github.com/decebals/claude-code-java/tree/main/skills/api-contract-review into .opencode/skills/api-contract-review/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "api-contract-review", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
api-contract-reviewReviews REST API design for correct HTTP verbs, versioning, DTO use, consistent responses and backward compatibility before an API change ships.
The skill audits REST endpoints, with examples in Java and Spring annotations. It opens with a table of common problems: the wrong HTTP verb such as POST for an idempotent operation, missing versioning like `/users` instead of `/v1/users`, JPA entities leaked in responses, a 200 status that carries an error body, and inconsistent naming such as `/getUsers` next to `/users`.
It then goes through each area. A verb guide lists which methods are idempotent, safe and allowed a request body; versioning strategies (URL path, header and query parameter) are compared, with URL path recommended along with a checklist covering public APIs and deprecation; and request and response design covers DTOs versus entities, consistent response shapes and pagination of collections. Good and bad code samples illustrate each point, and backward compatibility is part of the scope.
6 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 0d98fe9. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
No scripts in the folder and no shell commands in SKILL.md (its code samples are java and bash).
From the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
REST API Contract Review loads about 2.8k tokens when it runs. Until then it costs about 57 tokens; SKILL.md has 587 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from decebals/claude-code-java at commit 0d98fe9, republished under its MIT licence (© decebals). 587 words, ~2,759 tokens.
.claude/skills/api-contract-review/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.Audit REST API design for correctness, consistency, and compatibility.
| Issue | Symptom | Impact |
|---|---|---|
| Wrong HTTP verb | POST for idempotent operation | Confusion, caching issues |
| Missing versioning | /users instead of /v1/users | Breaking changes affect all clients |
| Entity leak | JPA entity in response | Exposes internals, N+1 risk |
| 200 with error | {"status": 200, "error": "..."} | Breaks error handling |
| Inconsistent naming | /getUsers vs /users | Hard to learn API |
| Verb | Use For | Idempotent | Safe | Request Body |
|---|---|---|---|---|
| GET | Retrieve resource | Yes | Yes | No |
| POST | Create new resource | No | No | Yes |
| PUT | Replace entire resource | Yes | No | Yes |
| PATCH | Partial update | No* | No | Yes |
| DELETE | Remove resource | Yes | No | Optional |
*PATCH can be idempotent depending on implementation
// ❌ POST for retrieval
@PostMapping("/users/search")
public List<User> searchUsers(@RequestBody SearchCriteria criteria) { }
// ✅ GET with query params (or POST only if criteria is very complex)
@GetMapping("/users")
public List<User> searchUsers(
@RequestParam String name,
@RequestParam(required = false) String email) { }
// ❌ GET for state change
@GetMapping("/users/{id}/activate")
public void activateUser(@PathVariable Long id) { }
// ✅ POST or PATCH for state change
@PostMapping("/users/{id}/activate")
public ResponseEntity<Void> activateUser(@PathVariable Long id) { }
// ❌ POST for idempotent update
@PostMapping("/users/{id}")
public User updateUser(@PathVariable Long id, @RequestBody UserDto dto) { }
// ✅ PUT for full replacement, PATCH for partial
@PutMapping("/users/{id}")
public User replaceUser(@PathVariable Long id, @RequestBody UserDto dto) { }
@PatchMapping("/users/{id}")
public User updateUser(@PathVariable Long id, @RequestBody UserPatchDto dto) { }| Strategy | Example | Pros | Cons |
|---|---|---|---|
| URL path | /v1/users | Clear, easy routing | URL changes |
| Header | Accept: application/vnd.api.v1+json | Clean URLs | Hidden, harder to test |
| Query param | /users?version=1 | Easy to add | Easy to forget |
// ✅ Versioned endpoints
@RestController
@RequestMapping("/api/v1/users")
public class UserControllerV1 { }
@RestController
@RequestMapping("/api/v2/users")
public class UserControllerV2 { }
// ❌ No versioning
@RestController
@RequestMapping("/api/users") // Breaking changes affect everyone
public class UserController { }// ❌ Entity in response (leaks internals)
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userRepository.findById(id).orElseThrow();
// Exposes: password hash, internal IDs, lazy collections
}
// ✅ DTO response
@GetMapping("/{id}")
public UserResponse getUser(@PathVariable Long id) {
User user = userService.findById(id);
return UserResponse.from(user); // Only public fields
}// ❌ Inconsistent responses
@GetMapping("/users")
public List<User> getUsers() { } // Returns array
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) { } // Returns object
@GetMapping("/users/count")
public int countUsers() { } // Returns primitive
// ✅ Consistent wrapper (optional but recommended for large APIs)
@GetMapping("/users")
public ApiResponse<List<UserResponse>> getUsers() {
return ApiResponse.success(userService.findAll());
}
// Or at minimum, consistent structure:
// - Collections: always wrapped or always raw (pick one)
// - Single items: always object
// - Counts/stats: always object { "count": 42 }// ❌ No pagination on collections
@GetMapping("/users")
public List<User> getAllUsers() {
return userRepository.findAll(); // Could be millions
}
// ✅ Paginated
@GetMapping("/users")
public Page<UserResponse> getUsers(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size) {
return userService.findAll(PageRequest.of(page, size));
}| Code | When to Use | Response Body |
|---|---|---|
| 200 OK | Successful GET, PUT, PATCH | Resource or result |
| 201 Created | Successful POST (created) | Created resource + Location header |
| 204 No Content | Successful DELETE, or PUT with no body | Empty |
| Code | When to Use | Common Mistake |
|---|---|---|
| 400 Bad Request | Invalid input, validation failed | Using for "not found" |
| 401 Unauthorized | Not authenticated | Confusing with 403 |
| 403 Forbidden | Authenticated but not allowed | Using 401 instead |
| 404 Not Found | Resource doesn't exist | Using 400 |
| 409 Conflict | Duplicate, concurrent modification | Using 400 |
| 422 Unprocessable | Semantic error (valid syntax, invalid meaning) | Using 400 |
| 500 Internal Error | Unexpected server error | Exposing stack traces |
// ❌ NEVER DO THIS
@GetMapping("/{id}")
public ResponseEntity<Map<String, Object>> getUser(@PathVariable Long id) {
try {
User user = userService.findById(id);
return ResponseEntity.ok(Map.of("status", "success", "data", user));
} catch (NotFoundException e) {
return ResponseEntity.ok(Map.of( // Still 200!
"status", "error",
"message", "User not found"
));
}
}
// ✅ Use proper status codes
@GetMapping("/{id}")
public ResponseEntity<UserResponse> getUser(@PathVariable Long id) {
return userService.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}// ✅ Standard error response
public class ErrorResponse {
private String code; // Machine-readable: "USER_NOT_FOUND"
private String message; // Human-readable: "User with ID 123 not found"
private Instant timestamp;
private String path;
private List<FieldError> errors; // For validation errors
}
// In GlobalExceptionHandler
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(
ResourceNotFoundException ex, HttpServletRequest request) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(ErrorResponse.builder()
.code("RESOURCE_NOT_FOUND")
.message(ex.getMessage())
.timestamp(Instant.now())
.path(request.getRequestURI())
.build());
}// ❌ Exposes stack trace
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleAll(Exception ex) {
return ResponseEntity.status(500)
.body(ex.getStackTrace().toString()); // Security risk!
}
// ✅ Generic message, log details server-side
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleAll(Exception ex) {
log.error("Unexpected error", ex); // Full details in logs
return ResponseEntity.status(500)
.body(ErrorResponse.of("INTERNAL_ERROR", "An unexpected error occurred"));
}| Change | Breaking? | Migration |
|---|---|---|
| Remove endpoint | Yes | Deprecate first, remove in next version |
| Remove field from response | Yes | Keep field, return null/default |
| Add required field to request | Yes | Make optional with default |
| Change field type | Yes | Add new field, deprecate old |
| Rename field | Yes | Support both temporarily |
| Change URL path | Yes | Redirect old to new |
@RestController
@RequestMapping("/api/v1/users")
public class UserControllerV1 {
@Deprecated
@GetMapping("/by-email") // Old endpoint
public UserResponse getByEmailOld(@RequestParam String email) {
return getByEmail(email); // Delegate to new
}
@GetMapping(params = "email") // New pattern
public UserResponse getByEmail(@RequestParam String email) {
return userService.findByEmail(email);
}
}/v1/, /v2/)/users, not /getUsers)/users, not /user)/users/{id}/orders)@ValidFor large APIs:
find . -name "*Controller.java"@ExceptionHandler configuration once# Find potential entity leaks
grep -r "public.*Entity.*@GetMapping" --include="*.java"
# Find 200 with error patterns
grep -r "ResponseEntity.ok.*error" --include="*.java"
# Find unversioned APIs
grep -r "@RequestMapping.*api" --include="*.java" | grep -v "/v[0-9]"© decebals, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 1 other file in skills/api-contract-review of decebals/claude-code-java.
Open the folder on GitHubat commit 0d98fe9
REST API Contract Review next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| REST API Contract Review this skilldecebals/claude-code-java | 751 | — | ~2.8k | Automated safety check: Pass | MIT | |
| Quarkus Patternsaffaan-m/ECC | 276k | 1 repos | ~5.4k | Automated safety check: Pass | MIT | |
| Quarkus Patternsaffaan-m/ECC | 276k | — | ~6.1k | Automated safety check: Pass | MIT | |
| API Design Safetydoccker/cc-use-exp | 1.1k | — | ~962 | Automated safety check: Pass | Custom licence | |
| Code Qualitypiomin/claude-ai-spring-boot | 1.3k | — | ~2.2k | Automated safety check: Pass | Apache-2.0 | |
| Azsdk Common Generate SDK LocallyAzure/azure-sdk-for-android | 121 | — | ~1.5k | Automated safety check: Pass | MIT |
affaan-m/ECC
Quarkus 3.x LTS architecture patterns with Camel for messaging, RESTful API design, CDI services, data access with Panache, and async processing.
affaan-m/ECC
Quarkus 3.x LTS architecture patterns with Camel for messaging, RESTful API design, CDI services, data access with Panache, and async processing.
doccker/cc-use-exp
当设计或修改 REST API 响应结构、处理 API 返回值时触发。防止 API 设计缺陷导致的字段错位、类型歧义等问题。
piomin/claude-ai-spring-boot
Comprehensive code review for Java - clean code principles, API contracts, null safety, exception handling, and performance.
Azure/azure-sdk-for-android
Generate, build, and test Azure SDKs locally from TypeSpec with automatic customization.
wshobson/agents
Create, validate and maintain OpenAPI 3.1 specs for REST APIs, whether designed first or generated from existing code, and use them for docs and client SDKs.
decebals/claude-code-java
A practical Java reference for Builder, Factory, Singleton, Strategy, Observer and other patterns, with a table matching problems to patterns.
decebals/claude-code-java
JPA/Hibernate patterns and common pitfalls (N+1, lazy loading, transactions, queries).
decebals/claude-code-java
Java logging best practices with SLF4J, structured logging (JSON), and MDC for request tracing.
decebals/claude-code-java
Reviews a Java project's architecture at the macro level: package structure, module boundaries, dependency direction and layering.
decebals/claude-code-java
Builds changelog entries from conventional commits in a Java project, after working out whether it uses SemVer, two-part versions or calendar versions.
decebals/claude-code-java
Covers Clean Code principles for Java: DRY, KISS and YAGNI with before-and-after examples, plus naming conventions for variables and booleans.
Works with
Categories
Reviews REST API design for correct HTTP verbs, versioning, DTO use, consistent responses and backward compatibility before an API change ships. The skill audits REST endpoints, with examples in Java and Spring annotations. It opens with a table of common problems: the wrong HTTP verb such as POST for an idempotent operation, missing versioning like `/users` instead of `/v1/users`, JPA entities leaked in responses, a 200 status that carries an error body, and inconsistent naming such as `/getUsers` next to `/users`.
REST API Contract Review fits situations like: reviewing REST controllers before releasing API changes; reviewing a pull request that touches controller code; checking an endpoint set for backward compatibility; deciding on a versioning scheme for a REST API.
Run `npx skills add decebals/claude-code-java --skill api-contract-review -a claude-code`. Or copy the skill folder (skills/api-contract-review in decebals/claude-code-java) into .claude/skills/api-contract-review in your project. Claude Code loads it when a task matches its description.
Run `npx skills add decebals/claude-code-java --skill api-contract-review -a codex`. Or copy the skill folder (skills/api-contract-review in decebals/claude-code-java) into .agents/skills/api-contract-review in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add decebals/claude-code-java --skill api-contract-review -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/api-contract-review, .gemini/skills/api-contract-review, .github/skills/api-contract-review and .opencode/skills/api-contract-review in your project.
SKILL.md names no scripts, command-line tools or credentials: REST API Contract Review is instructions for the agent only.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
REST API Contract Review is published under the MIT licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.
About 2.8k tokens (SKILL.md is roughly 11k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with REST API Contract Review: Quarkus Patterns (affaan-m/ECC, 276k stars), Quarkus Patterns (affaan-m/ECC, 276k stars), API Design Safety (doccker/cc-use-exp, 1.1k stars) and Code Quality (piomin/claude-ai-spring-boot, 1.3k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
decebals (a GitHub user) maintains it in decebals/claude-code-java, which has 751 GitHub stars. The repository holds 18 skills in this directory. The repository was last updated on September 6, 2026.
Source: decebals/claude-code-java on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.