# Request / Response Design

### Request Payload Structure

* Use a structured format like **JSON** or **XML** for request payloads.
* Use camelCase for field names to align with JavaScript conventions.
* Define required fields and optional fields explicitly in API documentation.
* Use `PATCH` for partial updates with only the fields that need to be changed.
* Validate the input request properly
* Use proper validation messages and handle exceptions .

{% hint style="info" %}
See [Bean Validation](https://wisdom.gitbook.io/gyan/core/bean-validation) for more info.
{% endhint %}

### Response Design

### **Flat Response:**&#x20;

Use for simple resources with minimal metadata.

```json
{
  "id": 1,
  "title": "Product A",
  "price": 100.0
}
```

### **Envelope Response:**&#x20;

Use for more complex responses with metadata, pagination, or additional information.

```java
@Getter
@Builder
public class ApiResponse<T> {
    private String status;           // SUCCESS, ERROR, PARTIAL_SUCCESS
    private String message;          // Human readable message
    private T data;                  // Actual response data
    private List<String> errors;     // List of error messages
    private LocalDateTime timestamp; // Response timestamp
    private String traceId;         // For request tracing
    
    public static <T> ApiResponse<T> success(T data) {
        return ApiResponse.<T>builder()
            .status("SUCCESS")
            .data(data)
            .timestamp(LocalDateTime.now())
            .build();
    }
    
    public static <T> ApiResponse<T> error(String message, List<String> errors) {
        return ApiResponse.<T>builder()
            .status("ERROR")
            .message(message)
            .errors(errors)
            .timestamp(LocalDateTime.now())
            .build();
    }
}
```

### Specific Response Objects

```java
@Getter
@Builder
public class OrderResponse {
    private String orderId;
    private String status;
    private BigDecimal totalAmount;
    private List<OrderItemResponse> items;
    private ShippingDetails shipping;
    private PaymentDetails payment;
    
    @JsonInclude(Include.NON_NULL)
    private List<String> warnings;  // Optional warnings
}

```

### Paginated Response&#x20;

#### **Offset-Based Pagination:**

Use `offset` (starting point) and `limit` (number of items to return).

**Example:**\
`/products?offset=10&limit=20`

```json
{
  "status": "success",
  "data": [
    { "id": 11, "name": "Product 11" },
    { "id": 12, "name": "Product 12" }
  ],
  "meta": {
    "total": 100,
    "offset": 10,
    "limit": 20
  }
}

```

#### **Page-Based Pagination:**

Use `page` and `size`.

**Example Request:**\
`/products?page=2&size=20`

```json
{
  "status": "success",
  "data": [
    { "id": 21, "name": "Product 21" },
    { "id": 22, "name": "Product 22" }
  ],
  "meta": {
    "totalPages": 5,
    "currentPage": 2,
    "pageSize": 20
  }
}
```

#### **Cursor-Based Pagination:**

Use a cursor (e.g., unique ID or timestamp) for fetching the next set of records.

**Example Request:**\
`/products?cursor=abc123&limit=20`

```json
{
  "status": "success",
  "data": [
    { "id": 31, "name": "Product 31" },
    { "id": 32, "name": "Product 32" }
  ],
  "meta": {
    "nextCursor": "xyz456",
    "limit": 20
  }
}
```

#### **Metadata**

Include metadata to provide additional context:

* **total:** Total number of items in the collection.
* **currentPage:** Current page number.
* **totalPages:** Total number of pages.
* **nextCursor:** For cursor-based pagination, the token for the next set of records.

```java
// Sample paginated response
@Getter
@Builder
public class PagedResponse<T> {
    private List<T> data;
    private int pageNumber;
    private int pageSize;
    private long totalElements;
    private int totalPages;
    private boolean hasNext;
    
    private Map<String, Object> metadata;  // For additional info like facets
}
```

### **Error Response Standardization**

Standardizing error responses makes troubleshooting easier for API clients.

* **Code:** Unique error identifier (e.g., HTTP status code or custom code).
* **Message:** Human-readable description of the error.
* **Details:** Additional information, such as invalid fields or suggested fixes (optional).
* **Timestamp:** The time the error occurred (optional).

{% hint style="info" %}
We can use **Problem Detail Standardization** introduced in spring 6
{% endhint %}

```java
@Getter
@Builder
public class ErrorResponse {
    private String code;           // Error code
    private String message;        // User-friendly message
    private String details;        // Technical details (optional)
    private List<FieldError> fieldErrors;  // Validation errors
    private LocalDateTime timestamp;
    
    @Getter
    @Builder
    public static class FieldError {
        private String field;
        private String message;
        private String code;
    }
}

@RestControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(BusinessValidationException.class)
    public ResponseEntity<ErrorResponse> handleValidationException(
            BusinessValidationException ex) {
        
        ErrorResponse error = ErrorResponse.builder()
            .code("VALIDATION_ERROR")
            .message("Validation failed")
            .fieldErrors(ex.getErrors())
            .timestamp(LocalDateTime.now())
            .build();
            
        return ResponseEntity
            .badRequest()
            .body(error);
    }
}

```

Using Problem Detail&#x20;

```java
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ProblemDetail handleResourceNotFoundException(ResourceNotFoundException ex) {
        ProblemDetail problemDetail = ProblemDetail.forStatus(HttpStatus.NOT_FOUND);
        problemDetail.setTitle("Resource Not Found");
        problemDetail.setDetail(ex.getMessage());
        problemDetail.setProperty("errorCode", "RESOURCE_NOT_FOUND");
        return problemDetail;
    }
}

// response
{
  "type": "about:blank",
  "title": "Resource Not Found",
  "status": 404,
  "detail": "The requested resource was not found.",
  "instance": "/api/users/123",
  "errorCode": "RESOURCE_NOT_FOUND"
}
```

### Async Operation Response

```java
@Getter
@Builder
public class AsyncOperationResponse {
    private String operationId;    // ID to track the operation
    private String status;         // ACCEPTED, IN_PROGRESS, COMPLETED, FAILED
    private String resourceUrl;    // URL to check the status
    private LocalDateTime acceptedAt;
    private LocalDateTime estimatedCompletionTime;
}

@RestController
@RequestMapping("/api/v1/batch-operations")
public class BatchOperationController {
    
    @PostMapping("/orders/import")
    public ResponseEntity<AsyncOperationResponse> importOrders(
            @RequestBody MultipartFile file) {
            
        String operationId = batchService.startImport(file);
        
        AsyncOperationResponse response = AsyncOperationResponse.builder()
            .operationId(operationId)
            .status("ACCEPTED")
            .resourceUrl("/api/v1/batch-operations/" + operationId)
            .acceptedAt(LocalDateTime.now())
            .estimatedCompletionTime(LocalDateTime.now().plusMinutes(5))
            .build();
            
        return ResponseEntity
            .accepted()
            .body(response);
    }
}
```

### Streaming Response

```java
@GetMapping(value = "/orders/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<OrderResponse> streamOrders() {
    return orderService.streamOrders()
        .map(order -> OrderResponse.builder()
            .orderId(order.getId())
            .status(order.getStatus())
            .build());
}
```

### Best Practices Summary:

1. **Request Design**:
   * Use DTOs for request/response objects
   * Implement validation at multiple levels
   * Include tracking information
   * Support idempotency for non-idempotent operations
2. **Response Design**:
   * Use consistent response envelope
   * Include metadata when necessary
   * Support pagination for collections
   * Include relevant links (HATEOAS)
3. **Error Handling**:
   * Consistent error format
   * Appropriate error codes
   * Meaningful error messages
   * Validation error details
4. **Performance**:
   * Use sparse fieldsets
   * Support pagination
   * Consider streaming for large datasets
   * Implement caching headers
