View Javadoc
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 &lt;guinetik@gmail.com&gt;
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 }