Install Rest API Conventions
Pick your agent. Every command is ready to paste.
npx skills add rrezartprebreza/spring-boot-skills --skill rest-api-conventionsThe open skills CLI detects your agents (Claude Code, Cursor, Codex and 70+ more) and installs to the right folder. Add -g to install globally.
01
Install it
Run the command above, or upload the folder in Claude.
02
Ask naturally
Describe the task. Your agent loads rest-api-conventions when the request matches its description.
03
Name it if needed
If it does not trigger, say “use the rest-api-conventions skill”. In Codex, type $rest-api-conventions.
REST API Conventions
Project Contract
Inspect existing controllers, tests and OpenAPI before choosing a response contract. Preserve the project's IDs, response shape and versioning strategy. Do not migrate unrelated endpoints while adding one route. The envelope below is an optional convention for a project that uses it; plain success DTOs are equally valid. A 204 response has no body.
Success and error formats are independent: an existing success envelope can coexist with RFC 9457 errors. Use one consistent error policy; choose the legacy error examples below only when the project already requires that format.
Example success envelope:
{
"success": true,
"data": { },
"error": null,
"timestamp": "2026-04-13T10:00:00Z"
}
Error response:
{
"success": false,
"data": null,
"error": {
"code": "ORDER_NOT_FOUND",
"message": "Order with id 123 not found",
"details": []
},
"timestamp": "2026-04-13T10:00:00Z"
}
ApiResponse Wrapper
@JsonInclude(JsonInclude.Include.NON_NULL)
public record ApiResponse<T>(
boolean success,
T data,
ApiError error,
Instant timestamp
) {
public static <T> ApiResponse<T> ok(T data) {
return new ApiResponse<>(true, data, null, Instant.now());
}
public static <T> ApiResponse<T> error(String code, String message) {
return new ApiResponse<>(false, null, new ApiError(code, message, List.of()), Instant.now());
}
}
public record ApiError(String code, String message, List<String> details) {}
HTTP Status Mapping
| Scenario | Status |
|---|---|
| GET — found | 200 |
| POST — created resource | 201 |
| PUT/PATCH — updated | 200 |
| DELETE — deleted | 204 (no body) |
| Validation failure | 400 |
| Unauthenticated | 401 |
| Forbidden | 403 |
| Not found | 404 |
| Conflict (duplicate) | 409 |
| Unhandled server error | 500 |
URL Conventions
- Plural nouns for resources:
/orders,/users,/products - Kebab-case for multi-word:
/order-items, not/orderItems - Versioning in path:
/api/v1/orders - Nested resources max 2 levels:
/orders/{id}/itemsis fine,/orders/{id}/items/{itemId}/notesis too deep — flatten to/order-item-notes/{id} - IDs: preserve the existing ID type. UUIDs are an option, not an authorization mechanism.
GET /api/v1/orders → list (paginated)
POST /api/v1/orders → create
GET /api/v1/orders/{id} → get one
PUT /api/v1/orders/{id} → full update
PATCH /api/v1/orders/{id} → partial update
DELETE /api/v1/orders/{id} → delete
GET /api/v1/orders/{id}/items → nested resource
Pagination
{
"success": true,
"data": {
"content": [...],
"page": 0,
"size": 20,
"totalElements": 150,
"totalPages": 8,
"last": false
}
}
Query params: ?page=0&size=20&sort=createdAt,desc
Use Spring Data Pageable in controllers:
@GetMapping
public ApiResponse<PageResponse<OrderResponse>> list(Pageable pageable) {
return ApiResponse.ok(PageResponse.from(orderService.findAll(pageable).map(OrderResponse::from)));
}
Cap the page size. A bare Pageable accepts ?size=100000 from any client — one request can
drag your whole table into memory. Spring's default cap is 2000, still too high for most APIs:
spring:
data:
web:
pageable:
default-page-size: 20
max-page-size: 100 # requests above this are silently clamped
The compiled PageResponse fixes the JSON pagination contract.
Mapping entities to DTOs alone does not stabilize Spring Data PageImpl serialization.
Spring Data's org.springframework.data.web.PagedModel is another option when its shape fits
the API. Validate sort fields against an allowlist and add an ID tie-breaker to non-unique sorts.
Legacy Envelope Exception Handler
// Extends ResponseEntityExceptionHandler: without it the Exception.class catch-all turns
// malformed JSON, 405, bad path variables and unknown URLs into 500. Full version, verified
// against Boot 3 and 4: templates/GlobalExceptionHandler.java
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<ApiResponse<Void>> handleNotFound(EntityNotFoundException ex) {
return ResponseEntity.status(404).body(ApiResponse.error("NOT_FOUND", ex.getMessage()));
}
@ExceptionHandler(AccessDeniedException.class) // @PreAuthorize denials surface here, not in the filter
public ResponseEntity<ApiResponse<Void>> handleAccessDenied(AccessDeniedException ex) {
return ResponseEntity.status(403).body(ApiResponse.error("FORBIDDEN", "Access denied"));
}
@Override // an @ExceptionHandler for this type would clash with the superclass at startup
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
List<String> details = ex.getBindingResult().getFieldErrors().stream()
.map(e -> e.getField() + ": " + e.getDefaultMessage()).toList();
return ResponseEntity.status(400).body(ApiResponse.validationError(details));
}
@Override // keep the framework's status + headers, return the envelope
protected ResponseEntity<Object> handleExceptionInternal(
Exception ex, Object body, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
return ResponseEntity.status(status).headers(headers)
.body(ApiResponse.error("HTTP_" + status.value(), "Request could not be processed"));
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ApiResponse<Void>> handleGeneric(Exception ex) {
return ResponseEntity.status(500).body(ApiResponse.error("INTERNAL_ERROR", "An unexpected error occurred"));
}
}
Gotchas
- Agent writes an
Exception.classcatch-all in an advice that doesn't extendResponseEntityExceptionHandler— malformed JSON, 405, type-mismatched path variables and unknown URLs all become 500 - Agent imposes a new envelope - preserve the existing success contract.
- Agent invents competing error handlers - use the project's established error contract.
- Agent puts exception handlers in controllers — always use
@RestControllerAdvice - Agent changes ID types while adding an endpoint - retain the existing ID scheme.
- Agent accepts unbounded
Pageable— setspring.data.web.pageable.max-page-sizeor one request can pull the whole table - Agent serializes PageImpl directly - map entities to DTOs, then wrap in PageResponse.
Tips for Rest API Conventions
- • Start a fresh session after installing so your agent picks up the new skill.
- • It bundles reference files. The agent reads them only when needed, so they cost no context until then.
- • It is part of a pack with 30 skills. Install only the ones you need with --skill to keep triggers precise.
- • If two skills overlap, mention the one you want by name.
Questions about Rest API Conventions
What does the Rest API Conventions skill do?
Use when generating REST controllers, DTOs, success response contracts, pagination, HTTP status mapping, or API versioning. For RFC 9457 exception and error response formatting, use problem-details-rfc9457 unless the project explicitly requires a legacy error envelope.
How do I install Rest API Conventions?
Run "npx skills add rrezartprebreza/spring-boot-skills --skill rest-api-conventions" in your project. The skills CLI installs it for Claude Code, Cursor, Codex and 70+ other agents. In Claude on the web, upload the skill folder as a ZIP under Customize > Skills.
Does Rest API Conventions work in Cursor and Codex?
Yes. Rest API Conventions uses the open SKILL.md format, so it works in Claude Code, Claude, Cursor, OpenAI Codex, Gemini CLI, GitHub Copilot and other agents that support agent skills.
Is Rest API Conventions free?
Rest API Conventions is open source on GitHub under the MIT license. It is free to install; check the license before commercial use.
Who made Rest API Conventions?
Rest API Conventions is published by rrezartprebreza in the rrezartprebreza/spring-boot-skills repository, together with 29 other skills.


