ApiError.java

package com.dani.bff.error;

import io.swagger.v3.oas.annotations.media.Schema;
import java.time.Instant;
import org.springframework.http.HttpStatus;

/**
 * Structured error body returned by the BFF for predictable client-side handling.
 *
 * @param timestamp time the error response was produced
 * @param status numeric HTTP status
 * @param error HTTP status reason phrase
 * @param message stable, human-readable summary
 * @param path request path that failed
 */
@Schema(description = "Structured JSON error returned by the BFF for predictable client handling.")
public record ApiError(
        @Schema(description = "Time the error response was produced.", example = "2026-05-23T11:24:56.339Z")
        Instant timestamp,
        @Schema(description = "HTTP status code.", example = "401")
        int status,
        @Schema(description = "HTTP status reason phrase.", example = "Unauthorized")
        String error,
        @Schema(description = "Stable, human-readable summary.", example = "Authentication is required")
        String message,
        @Schema(description = "Request path that failed.", example = "/api/dashboard")
        String path) {

    /**
     * Creates an API error with the current timestamp.
     *
     * @param status HTTP status to represent
     * @param message stable message for clients and logs
     * @param path request path
     * @return structured API error
     */
    public static ApiError of(HttpStatus status, String message, String path) {
        return new ApiError(Instant.now(), status.value(), status.getReasonPhrase(), message, path);
    }
}