View Javadoc
1   package com.guinetik.rr.http;
2   
3   import java.util.HashMap;
4   import java.util.Map;
5   
6   /**
7    * Fluent builder for HTTP request headers with convenience methods for common headers.
8    *
9    * <p>This class provides a type-safe way to build and manage HTTP headers for requests,
10   * with predefined constants for common header names and content types.
11   *
12   * <h2>Building Headers</h2>
13   * <pre class="language-java"><code>
14   * // Create headers with fluent API
15   * RocketHeaders headers = new RocketHeaders()
16   *     .contentType(RocketHeaders.ContentTypes.APPLICATION_JSON)
17   *     .accept(RocketHeaders.ContentTypes.APPLICATION_JSON)
18   *     .set("X-Custom-Header", "custom-value");
19   *
20   * // Use in request
21   * RequestSpec request = RequestBuilder.post("/users")
22   *     .headers(headers)
23   *     .body(user)
24   *     .responseType(User.class)
25   *     .build();
26   * </code></pre>
27   *
28   * <h2>Authentication Headers</h2>
29   * <pre class="language-java"><code>
30   * // Bearer token authentication
31   * RocketHeaders headers = new RocketHeaders()
32   *     .bearerAuth("my-jwt-token");
33   *
34   * // Basic authentication
35   * RocketHeaders basicAuth = new RocketHeaders()
36   *     .basicAuth("username", "password");
37   * </code></pre>
38   *
39   * <h2>Default JSON Headers</h2>
40   * <pre class="language-java"><code>
41   * // Get pre-configured JSON headers
42   * RocketHeaders jsonHeaders = RocketHeaders.defaultJson();
43   * // Equivalent to Content-Type: application/json + Accept: application/json
44   * </code></pre>
45   *
46   * <h2>Merging Headers</h2>
47   * <pre class="language-java"><code>
48   * RocketHeaders base = RocketHeaders.defaultJson();
49   * RocketHeaders auth = new RocketHeaders().bearerAuth("token");
50   *
51   * // Merge headers (auth values take precedence)
52   * RocketHeaders merged = base.merge(auth);
53   * </code></pre>
54   *
55   * @author guinetik &lt;guinetik@gmail.com&gt;
56   * @see com.guinetik.rr.request.RequestBuilder
57   * @since 1.0.0
58   */
59  public class RocketHeaders {
60      
61      private final Map<String, String> headers;
62      
63      /**
64       * Standard HTTP header names as constants.
65       */
66      public static final class Names {
67          public static final String CONTENT_TYPE = "Content-Type";
68          public static final String ACCEPT = "Accept";
69          public static final String AUTHORIZATION = "Authorization";
70          public static final String USER_AGENT = "User-Agent";
71          public static final String CONTENT_LENGTH = "Content-Length";
72      }
73      
74      /**
75       * Common content types as constants.
76       */
77      public static final class ContentTypes {
78          public static final String APPLICATION_JSON = "application/json";
79          public static final String APPLICATION_FORM = "application/x-www-form-urlencoded";
80          public static final String TEXT_PLAIN = "text/plain";
81          public static final String MULTIPART_FORM = "multipart/form-data";
82      }
83      
84      /**
85       * Creates a new empty header container.
86       */
87      public RocketHeaders() {
88          this.headers = new HashMap<>();
89      }
90      
91      /**
92       * Creates a new header container with the specified headers.
93       *
94       * @param headers The initial headers
95       */
96      public RocketHeaders(Map<String, String> headers) {
97          this.headers = new HashMap<>(headers);
98      }
99      
100     /**
101      * Sets a header value.
102      *
103      * @param name The header name
104      * @param value The header value
105      * @return This HttpHeader instance for chaining
106      */
107     public RocketHeaders set(String name, String value) {
108         headers.put(name, value);
109         return this;
110     }
111     
112     /**
113      * Gets a header value.
114      *
115      * @param name The header name
116      * @return The header value or null if not present
117      */
118     public String get(String name) {
119         return headers.get(name);
120     }
121     
122     /**
123      * Removes a header.
124      *
125      * @param name The header name
126      * @return This HttpHeader instance for chaining
127      */
128     public RocketHeaders remove(String name) {
129         headers.remove(name);
130         return this;
131     }
132     
133     /**
134      * Checks if a header is present.
135      *
136      * @param name The header name
137      * @return true if the header is present
138      */
139     public boolean contains(String name) {
140         return headers.containsKey(name);
141     }
142     
143     /**
144      * Sets the Content-Type header.
145      *
146      * @param contentType The content type
147      * @return This HttpHeader instance for chaining
148      */
149     public RocketHeaders contentType(String contentType) {
150         return set(Names.CONTENT_TYPE, contentType);
151     }
152     
153     /**
154      * Sets the Accept header.
155      *
156      * @param accept The accept value
157      * @return This HttpHeader instance for chaining
158      */
159     public RocketHeaders accept(String accept) {
160         return set(Names.ACCEPT, accept);
161     }
162     
163     /**
164      * Sets the Authorization header with a Bearer token.
165      *
166      * @param token The token
167      * @return This HttpHeader instance for chaining
168      */
169     public RocketHeaders bearerAuth(String token) {
170         return set(Names.AUTHORIZATION, "Bearer " + token);
171     }
172     
173     /**
174      * Sets the Authorization header with Basic authentication.
175      *
176      * @param username The username
177      * @param password The password
178      * @return This HttpHeader instance for chaining
179      */
180     public RocketHeaders basicAuth(String username, String password) {
181         String auth = java.util.Base64.getEncoder().encodeToString((username + ":" + password).getBytes());
182         return set(Names.AUTHORIZATION, "Basic " + auth);
183     }
184     
185     /**
186      * Gets all headers as a Map.
187      *
188      * @return An unmodifiable view of the header map
189      */
190     public Map<String, String> asMap() {
191         return java.util.Collections.unmodifiableMap(headers);
192     }
193     
194     /**
195      * Merges this header with another, with values from the other taking precedence.
196      *
197      * @param other The other HttpHeader instance
198      * @return A new HttpHeader instance with merged values
199      */
200     public RocketHeaders merge(RocketHeaders other) {
201         RocketHeaders result = new RocketHeaders(this.headers);
202         result.headers.putAll(other.headers);
203         return result;
204     }
205     
206     /**
207      * Creates a set of default headers with JSON content type.
208      *
209      * @return A new HttpHeader with JSON content type and accept headers
210      */
211     public static RocketHeaders defaultJson() {
212         return new RocketHeaders()
213             .contentType(ContentTypes.APPLICATION_JSON)
214             .accept(ContentTypes.APPLICATION_JSON);
215     }
216 }