home / skills / bitsoex / bitso-java / api-guidelines-rfc-39
This skill helps design and review RFC-39 compliant Java REST APIs with standardized patterns for requests, responses, errors, pagination, versioning, and
npx playbooks add skill bitsoex/bitso-java --skill api-guidelines-rfc-39Review the files below or copy the command above to add this skill to your agents.
---
name: api-guidelines-rfc-39
description: >
RFC-39 compliant API best practices for Java services. Covers request/response patterns,
error handling, pagination, versioning, and authentication standards.
Use when designing or reviewing REST APIs in Java services.
compatibility: Java projects using Spring Boot for REST APIs
metadata:
version: "1.0.0"
technology: java
category: api
tags:
- java
- api
- rfc-39
- rest
- spring-boot
---
# API Guidelines (RFC-39)
RFC-39 compliant API best practices for Java services.
## When to use this skill
- Designing new REST API endpoints
- Reviewing API implementations for compliance
- Implementing error handling patterns
- Setting up pagination and filtering
- Configuring API versioning
- Implementing authentication and authorization
## Skill Contents
### Sections
- [When to use this skill](#when-to-use-this-skill) (L24-L32)
- [Quick Start](#quick-start) (L55-L93)
- [Request/Response Patterns](#requestresponse-patterns) (L94-L143)
- [Error Handling](#error-handling) (L144-L207)
- [Pagination](#pagination) (L208-L252)
- [Versioning](#versioning) (L253-L280)
- [Authentication](#authentication) (L281-L311)
- [References](#references) (L312-L317)
- [Related Rules](#related-rules) (L318-L321)
- [Related Skills](#related-skills) (L322-L327)
### Available Resources
**📚 references/** - Detailed documentation
- [response patterns](references/response-patterns.md)
---
## Quick Start
### 1. Controller Setup
```java
@RestController
@RequestMapping("/api/v1/orders")
@RequiredArgsConstructor
public class OrderController {
private final OrderService orderService;
private final ResponseFactory responseFactory;
@GetMapping("/{orderId}")
public ResponseEntity<ApiResponse<OrderDto>> getOrder(
@PathVariable String orderId) {
OrderDto order = orderService.findById(orderId);
return responseFactory.ok(order);
}
}
```
### 2. Response Factory
```java
@Component
public class ResponseFactory {
public <T> ResponseEntity<ApiResponse<T>> ok(T data) {
return ResponseEntity.ok(ApiResponse.success(data));
}
public <T> ResponseEntity<ApiResponse<T>> created(T data) {
return ResponseEntity.status(HttpStatus.CREATED)
.body(ApiResponse.success(data));
}
}
```
## Request/Response Patterns
### Standard Response Envelope
```json
{
"success": true,
"data": { ... },
"meta": {
"requestId": "abc-123",
"timestamp": "2026-01-27T12:00:00Z"
}
}
```
### Java Implementation
```java
@Data
@Builder
public class ApiResponse<T> {
private boolean success;
private T data;
private ApiError error;
private ApiMeta meta;
public static <T> ApiResponse<T> success(T data) {
return ApiResponse.<T>builder()
.success(true)
.data(data)
.meta(ApiMeta.now())
.build();
}
}
@Data
@Builder
public class ApiMeta {
private String requestId;
private Instant timestamp;
public static ApiMeta now() {
return ApiMeta.builder()
.requestId(MDC.get("requestId"))
.timestamp(Instant.now())
.build();
}
}
```
## Error Handling
### Error Response Format
```json
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request parameters",
"details": [
{
"field": "email",
"message": "must be a valid email address"
}
]
},
"meta": {
"requestId": "abc-123",
"timestamp": "2026-01-27T12:00:00Z"
}
}
```
### Exception Handler
```java
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ApiResponse<Void>> handleNotFound(
ResourceNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(ApiResponse.error("NOT_FOUND", ex.getMessage()));
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiResponse<Void>> handleValidation(
MethodArgumentNotValidException ex) {
List<FieldError> details = ex.getBindingResult()
.getFieldErrors()
.stream()
.map(e -> new FieldError(e.getField(), e.getDefaultMessage()))
.toList();
return ResponseEntity.badRequest()
.body(ApiResponse.validationError(details));
}
}
```
### Standard Error Codes
| Code | HTTP Status | Description |
|------|-------------|-------------|
| `VALIDATION_ERROR` | 400 | Invalid request parameters |
| `UNAUTHORIZED` | 401 | Missing or invalid authentication |
| `FORBIDDEN` | 403 | Insufficient permissions |
| `NOT_FOUND` | 404 | Resource not found |
| `CONFLICT` | 409 | Resource conflict |
| `RATE_LIMITED` | 429 | Too many requests |
| `INTERNAL_ERROR` | 500 | Unexpected server error |
## Pagination
### Request Parameters
| Parameter | Default | Description |
|-----------|---------|-------------|
| `page` | 0 | Page number (0-indexed) |
| `size` | 20 | Page size (max 100) |
| `sort` | - | Sort field and direction |
### Response Format
```json
{
"success": true,
"data": [...],
"meta": {
"pagination": {
"page": 0,
"size": 20,
"totalElements": 150,
"totalPages": 8,
"hasNext": true,
"hasPrevious": false
}
}
}
```
### Controller Example
```java
@GetMapping
public ResponseEntity<ApiResponse<List<OrderDto>>> listOrders(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size,
@RequestParam(required = false) String sort) {
Pageable pageable = PageRequest.of(page, Math.min(size, 100));
Page<OrderDto> orders = orderService.findAll(pageable);
return responseFactory.paginated(orders);
}
```
## Versioning
### URL Path Versioning (Preferred)
```java
@RestController
@RequestMapping("/api/v1/orders")
public class OrderV1Controller { }
@RestController
@RequestMapping("/api/v2/orders")
public class OrderV2Controller { }
```
### Deprecation Headers
```java
@GetMapping("/legacy-endpoint")
@Deprecated
public ResponseEntity<ApiResponse<Void>> legacyEndpoint() {
return ResponseEntity.ok()
.header("Deprecation", "true")
.header("Sunset", "Sat, 01 Mar 2026 00:00:00 GMT")
.header("Link", "</api/v2/new-endpoint>; rel=\"successor-version\"")
.body(ApiResponse.success(null));
}
```
## Authentication
### WebAPI Annotation
```java
@RestController
@RequestMapping("/api/v1/orders")
public class OrderController {
@GetMapping
@WebAPI(AuthType.PRIVATE) // Requires user authentication
public ResponseEntity<...> listOrders() { }
@GetMapping("/public-info")
@WebAPI(AuthType.PUBLIC) // No authentication required
public ResponseEntity<...> getPublicInfo() { }
@GetMapping("/internal")
@WebAPI(AuthType.INTERNAL) // Service-to-service only
public ResponseEntity<...> internalEndpoint() { }
}
```
### Authentication Types
| Type | Usage |
|------|-------|
| `PRIVATE` | User-authenticated endpoints |
| `PUBLIC` | Unauthenticated, public endpoints |
| `INTERNAL` | Service-to-service communication |
## References
| Reference | Description |
|-----------|-------------|
| [references/response-patterns.md](references/response-patterns.md) | Detailed response patterns |
## Related Rules
- [java-rest-api-guidelines](.cursor/rules/java-rest-api-guidelines/java-rest-api-guidelines.mdc) - REST API standards (RFC-30/RFC-39)
## Related Skills
| Skill | Purpose |
|-------|---------|
| [rest-api](.claude/skills/rest-api/SKILL.md) | REST API implementation |
| [grpc-services-rfc-33](.claude/skills/grpc-services-rfc-33/SKILL.md) | gRPC service standards |
<!-- AUTO-GENERATED FILE - DO NOT EDIT DIRECTLY -->
<!-- Source: bitsoex/ai-code-instructions → java/skills/api-guidelines-rfc-39/SKILL.md -->
<!-- To modify, edit the source file and run the distribution workflow -->
This skill provides RFC-39 compliant API best practices tailored for Java services. It codifies request/response patterns, error handling, pagination, versioning, and authentication to use when designing or reviewing REST APIs. The guidance focuses on consistent envelopes, standard error codes, and practical controller patterns for maintainable services.
The skill defines a standard ApiResponse envelope with success, data, error, and meta sections (including requestId and timestamp). It provides Java examples for controllers, a ResponseFactory, global exception handling, pagination helpers, and versioning/deprecation approaches. Authentication types (PUBLIC, PRIVATE, INTERNAL) and annotations show when to require user auth or service-to-service access.
What should be included in the meta section?
Include requestId (from MDC) and a timestamp; pagination info goes under meta.pagination for list endpoints.
How do I handle validation errors?
Use a global exception handler to catch MethodArgumentNotValidException, map field errors to a details array, and return VALIDATION_ERROR with HTTP 400.