Financial REST API Skill
Purpose
Standardize RESTful API design, response envelopes, ISO 8601 timestamps, error payloads, and pagination models across financial endpoints.
1. Response Envelope Format (ApiResponse<T>)
RECOMMENDED
API responses SHOULD use the standard envelope unless there is a documented requirement to use another representation (e.g., binary downloads, file exports, health checks, server-sent events):
package com.npci.platform.common.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.time.Instant;
import java.util.Map;
@JsonInclude(JsonInclude.Include.NON_NULL)
public record ApiResponse<T>(
boolean success,
T data,
ApiError error,
String timestamp
) {
public static <T> ApiResponse<T> success(T data) {
return new ApiResponse<>(true, data, null, Instant.now().toString());
}
public static <T> ApiResponse<T> error(String code, String message) {
return new ApiResponse<>(false, null, new ApiError(code, message, null), Instant.now().toString());
}
public static <T> ApiResponse<T> error(String code, String message, Map<String, String> details) {
return new ApiResponse<>(false, null, new ApiError(code, message, details), Instant.now().toString());
}
public record ApiError(String code, String message, Map<String, String> details) {}
}
2. Self-Contained Pagination DTO Pattern (PageResponse<T>)
MANDATORY
Spring Data services & repositories MUST internally use Spring Data Pageable (org.springframework.data.domain.Pageable) and Page<T>.
REST Controllers MUST NOT expose raw Spring Page<T> or PageImpl to UI/clients. They MUST map Page<T> into a clean, self-contained PageResponse<T> record using PageResponse.from(page):
package com.npci.platform.common.dto;
import org.springframework.data.domain.Page;
import java.util.List;
public record PageResponse<T>(
List<T> content,
int pageNumber,
int pageSize,
long totalElements,
int totalPages,
boolean first,
boolean last
) {
public static <T> PageResponse<T> from(Page<T> springPage) {
return new PageResponse<>(
springPage.getContent(),
springPage.getNumber(),
springPage.getSize(),
springPage.getTotalElements(),
springPage.getTotalPages(),
springPage.isFirst(),
springPage.isLast()
);
}
}