1 package com.guinetik.rr.request;
2
3 import com.guinetik.rr.http.RocketHeaders;
4
5 import java.util.HashMap;
6 import java.util.Map;
7
8 /**
9 * Fluent builder for constructing {@link RequestSpec} instances.
10 *
11 * <p>This builder provides a clean, type-safe API for creating HTTP request specifications
12 * with all necessary parameters like endpoint, method, headers, body, and response type.
13 *
14 * <h2>Static Factory Methods</h2>
15 * <pre class="language-java"><code>
16 * // GET request
17 * RequestSpec<Void, User> getUser = RequestBuilder.<Void, User>get("/users/1")
18 * .responseType(User.class)
19 * .build();
20 *
21 * // POST request with body
22 * RequestSpec<CreateUser, User> createUser = RequestBuilder.<CreateUser, User>post("/users")
23 * .body(new CreateUser("John", "john@example.com"))
24 * .responseType(User.class)
25 * .build();
26 *
27 * // PUT request
28 * RequestSpec<UpdateUser, User> updateUser = RequestBuilder.<UpdateUser, User>put("/users/1")
29 * .body(new UpdateUser("John Doe"))
30 * .responseType(User.class)
31 * .build();
32 *
33 * // DELETE request
34 * RequestSpec<Void, Void> deleteUser = RequestBuilder.<Void, Void>delete("/users/1")
35 * .responseType(Void.class)
36 * .build();
37 * </code></pre>
38 *
39 * <h2>With Headers and Query Params</h2>
40 * <pre class="language-java"><code>
41 * Map<String, String> params = new HashMap<>();
42 * params.put("page", "1");
43 * params.put("limit", "10");
44 *
45 * RequestSpec<Void, UserList> request = RequestBuilder.<Void, UserList>get("/users")
46 * .queryParams(params)
47 * .headers(RocketHeaders.defaultJson().set("X-Custom", "value"))
48 * .responseType(UserList.class)
49 * .build();
50 * </code></pre>
51 *
52 * @param <Req> the type of the request body
53 * @param <Res> the type of the response
54 * @author guinetik <guinetik@gmail.com>
55 * @see RequestSpec
56 * @since 1.0.0
57 */
58 public class RequestBuilder<Req, Res> {
59 private String endpoint;
60 private String method = "GET";
61 private Map<String, String> queryParams = new HashMap<>();
62 private RocketHeaders headers = RocketHeaders.defaultJson();
63 private Req body;
64 private Class<Res> responseType;
65
66 /**
67 * Creates a GET request builder for the specified endpoint.
68 *
69 * @param endpoint the API endpoint.
70 * @param <Req> The type of the request body.
71 * @param <Res> The type of the response.
72 * @return a new builder instance.
73 */
74 public static <Req, Res> RequestBuilder<Req, Res> get(String endpoint) {
75 return new RequestBuilder<Req, Res>().endpoint(endpoint).method("GET");
76 }
77
78 /**
79 * Creates a POST request builder for the specified endpoint.
80 *
81 * @param endpoint the API endpoint.
82 * @param <Req> The type of the request body.
83 * @param <Res> The type of the response.
84 * @return a new builder instance.
85 */
86 public static <Req, Res> RequestBuilder<Req, Res> post(String endpoint) {
87 return new RequestBuilder<Req, Res>().endpoint(endpoint).method("POST");
88 }
89
90 /**
91 * Creates a PUT request builder for the specified endpoint.
92 *
93 * @param endpoint the API endpoint.
94 * @param <Req> The type of the request body.
95 * @param <Res> The type of the response.
96 * @return a new builder instance.
97 */
98 public static <Req, Res> RequestBuilder<Req, Res> put(String endpoint) {
99 return new RequestBuilder<Req, Res>().endpoint(endpoint).method("PUT");
100 }
101
102 /**
103 * Creates a DELETE request builder for the specified endpoint.
104 *
105 * @param endpoint the API endpoint.
106 * @param <Req> The type of the request body.
107 * @param <Res> The type of the response.
108 * @return a new builder instance.
109 */
110 public static <Req, Res> RequestBuilder<Req, Res> delete(String endpoint) {
111 return new RequestBuilder<Req, Res>().endpoint(endpoint).method("DELETE");
112 }
113
114 /**
115 * Sets the API endpoint for the request.
116 *
117 * @param endpoint the API endpoint.
118 * @return the builder instance.
119 */
120 public RequestBuilder<Req, Res> endpoint(String endpoint) {
121 this.endpoint = endpoint;
122 return this;
123 }
124
125 /**
126 * Sets the HTTP method for the request.
127 *
128 * @param method the HTTP method (e.g., GET, POST, PUT, DELETE).
129 * @return the builder instance.
130 */
131 public RequestBuilder<Req, Res> method(String method) {
132 this.method = method;
133 return this;
134 }
135
136 /**
137 * Sets the query parameters for the request.
138 *
139 * @param queryParams a map of query parameters.
140 * @return the builder instance.
141 */
142 public RequestBuilder<Req, Res> queryParams(Map<String, String> queryParams) {
143 this.queryParams = queryParams;
144 return this;
145 }
146
147 /**
148 * Adds a single query parameter to the request.
149 *
150 * @param name the parameter name.
151 * @param value the parameter value.
152 * @return the builder instance.
153 */
154 public RequestBuilder<Req, Res> queryParam(String name, String value) {
155 this.queryParams.put(name, value);
156 return this;
157 }
158
159 /**
160 * Sets the headers for the request.
161 *
162 * @param headers a map of headers.
163 * @return the builder instance.
164 */
165 public RequestBuilder<Req, Res> headers(RocketHeaders headers) {
166 this.headers = headers;
167 return this;
168 }
169
170 /**
171 * Sets the body of the request.
172 *
173 * @param body the request body.
174 * @return the builder instance.
175 */
176 public RequestBuilder<Req, Res> body(Req body) {
177 this.body = body;
178 return this;
179 }
180
181 /**
182 * Sets the expected response type of the request.
183 *
184 * @param responseType the response type.
185 * @return the builder instance.
186 */
187 public RequestBuilder<Req, Res> responseType(Class<Res> responseType) {
188 this.responseType = responseType;
189 return this;
190 }
191
192 /**
193 * Builds and returns a {@link RequestSpec} instance.
194 *
195 * @return the constructed {@link RequestSpec}.
196 */
197 public RequestSpec<Req, Res> build() {
198 return new RequestSpec<>(endpoint, method, queryParams, headers, body, responseType);
199 }
200 }