|
| 1 | +package com.retailsvc.http.internal; |
| 2 | + |
| 3 | +import com.retailsvc.http.BadRequestException; |
| 4 | +import com.retailsvc.http.validate.ValidationError; |
| 5 | +import java.util.Map; |
| 6 | + |
| 7 | +/** |
| 8 | + * Carrier for an RFC 7807 problem+json document. Serialized by the registered JSON {@code |
| 9 | + * TypeMapper}; the wire shape and field-order are whatever the configured mapper produces — title |
| 10 | + * is advisory per RFC 7807 since {@code type} is always {@code about:blank}. |
| 11 | + */ |
| 12 | +public record ProblemDetail( |
| 13 | + String type, String title, int status, String detail, String pointer, String keyword) { |
| 14 | + |
| 15 | + private static final String DEFAULT_TYPE = "about:blank"; |
| 16 | + |
| 17 | + public static ProblemDetail forValidation(ValidationError e) { |
| 18 | + return new ProblemDetail( |
| 19 | + DEFAULT_TYPE, "Bad Request", 400, e.message(), e.pointer(), e.keyword()); |
| 20 | + } |
| 21 | + |
| 22 | + public static ProblemDetail forBadRequest(BadRequestException e) { |
| 23 | + return new ProblemDetail( |
| 24 | + DEFAULT_TYPE, |
| 25 | + titleFor(e.status()), |
| 26 | + e.status(), |
| 27 | + e.getMessage(), |
| 28 | + e.pointer().orElse(null), |
| 29 | + e.keyword().orElse(null)); |
| 30 | + } |
| 31 | + |
| 32 | + private static final Map<Integer, String> TITLES = |
| 33 | + Map.of( |
| 34 | + 400, "Bad Request", |
| 35 | + 401, "Unauthorized", |
| 36 | + 403, "Forbidden", |
| 37 | + 404, "Not Found", |
| 38 | + 405, "Method Not Allowed", |
| 39 | + 409, "Conflict", |
| 40 | + 410, "Gone", |
| 41 | + 412, "Precondition Failed", |
| 42 | + 415, "Unsupported Media Type", |
| 43 | + 422, "Unprocessable Content"); |
| 44 | + |
| 45 | + private static String titleFor(int status) { |
| 46 | + return TITLES.getOrDefault(status, "Bad Request"); |
| 47 | + } |
| 48 | +} |
0 commit comments