1 package com.guinetik.rr.http;
2
3 /**
4 * Base runtime exception for all HTTP-related errors in RocketRest.
5 *
6 * <p>This exception captures HTTP error details including the status code and response body,
7 * making it easier to handle and diagnose API errors. As a RuntimeException, it doesn't
8 * require explicit catching, but can be caught for specific error handling.
9 *
10 * <h2>Exception Hierarchy</h2>
11 * <pre>
12 * RuntimeException
13 * └── RocketRestException (base - catch this for all HTTP errors)
14 * ├── CircuitBreakerOpenException (circuit breaker is open)
15 * ├── TokenExpiredException (401 - token needs refresh)
16 * └── ApiException (richer error details from server)
17 * </pre>
18 *
19 * <h2>Exception Handling</h2>
20 * <pre class="language-java">{@code
21 * try {
22 * User user = client.get("/users/1", User.class);
23 * } catch (CircuitBreakerOpenException e) {
24 * // Service is down, fail fast
25 * System.out.println("Service unavailable, retry in " + e.getEstimatedMillisUntilReset() + "ms");
26 * } catch (TokenExpiredException e) {
27 * // Token expired, re-authenticate
28 * refreshToken();
29 * } catch (RocketRestException e) {
30 * // All other HTTP errors
31 * System.err.println("HTTP " + e.getStatusCode() + ": " + e.getMessage());
32 * }
33 * }</pre>
34 *
35 * <h2>Avoiding Exceptions with Fluent API</h2>
36 * <pre class="language-java">{@code
37 * // Use fluent API to avoid exception handling
38 * Result<User, ApiError> result = client.fluent().get("/users/1", User.class);
39 *
40 * result.match(
41 * user -> System.out.println("Found: " + user.getName()),
42 * error -> System.out.println("Error " + error.getStatusCode() + ": " + error.getMessage())
43 * );
44 * }</pre>
45 *
46 * @author guinetik <guinetik@gmail.com>
47 * @see CircuitBreakerOpenException
48 * @see com.guinetik.rr.auth.TokenExpiredException
49 * @see com.guinetik.rr.api.ApiException
50 * @see com.guinetik.rr.result.ApiError
51 * @since 1.0.0
52 */
53 public class RocketRestException extends RuntimeException {
54
55 private static final long serialVersionUID = 1L;
56 private int statusCode;
57 private String responseBody;
58
59 /**
60 * Constructs a new exception with the specified detail message.
61 *
62 * @param message The detail message
63 */
64 public RocketRestException(String message) {
65 super(message);
66 }
67
68 /**
69 * Constructs a new exception with the specified detail message and cause.
70 *
71 * @param message The detail message
72 * @param cause The cause
73 */
74 public RocketRestException(String message, Throwable cause) {
75 super(message, cause);
76 }
77
78 /**
79 * Constructs a new exception with the specified detail message, status code, and response body.
80 *
81 * @param message The detail message
82 * @param statusCode The HTTP status code
83 * @param responseBody The response body
84 */
85 public RocketRestException(String message, int statusCode, String responseBody) {
86 super(message);
87 this.statusCode = statusCode;
88 this.responseBody = responseBody;
89 }
90
91 /**
92 * Gets the HTTP status code.
93 *
94 * @return The HTTP status code
95 */
96 public int getStatusCode() {
97 return statusCode;
98 }
99
100 /**
101 * Gets the response body.
102 *
103 * @return The response body
104 */
105 public String getResponseBody() {
106 return responseBody;
107 }
108 }