0
# Request Context and Exchange
1
2
Comprehensive interface for accessing and manipulating HTTP request and response objects, providing both low-level Vert.x access and high-level convenience methods.
3
4
## Capabilities
5
6
### RoutingExchange Interface
7
8
Primary interface providing convenient access to HTTP request/response context with both low-level Vert.x access and high-level convenience methods.
9
10
```java { .api }
11
/**
12
* Convenient wrapper around Vert.x RoutingContext for route methods
13
* Provides access to request/response objects and convenience methods
14
*/
15
public interface RoutingExchange {
16
17
/**
18
* Access to underlying Vert.x RoutingContext
19
* @return The Vert.x routing context
20
*/
21
io.vertx.ext.web.RoutingContext context();
22
23
/**
24
* Access to HTTP request object
25
* @return Vert.x HTTP server request
26
*/
27
io.vertx.core.http.HttpServerRequest request();
28
29
/**
30
* Access to HTTP response object
31
* @return Vert.x HTTP server response
32
*/
33
io.vertx.core.http.HttpServerResponse response();
34
35
/**
36
* Get request parameter by name
37
* @param name Parameter name
38
* @return Optional parameter value
39
*/
40
Optional<String> getParam(String name);
41
42
/**
43
* Get HTTP header by name
44
* @param name Header name (accepts CharSequence for flexibility)
45
* @return Optional header value
46
*/
47
Optional<String> getHeader(CharSequence name);
48
49
/**
50
* Set response status to 200 and return response object for chaining
51
* Must call HttpServerResponse.end() to complete the response
52
* @return The HTTP response object for chaining
53
*/
54
io.vertx.core.http.HttpServerResponse ok();
55
56
/**
57
* Set response status to 200, write content, and end response
58
* @param chunk Response content to write
59
*/
60
void ok(String chunk);
61
62
/**
63
* Set response status to 500 and return response object for chaining
64
* Must call HttpServerResponse.end() to complete the response
65
* @return The HTTP response object for chaining
66
*/
67
io.vertx.core.http.HttpServerResponse serverError();
68
69
/**
70
* Set response status to 404 and return response object for chaining
71
* Must call HttpServerResponse.end() to complete the response
72
* @return The HTTP response object for chaining
73
*/
74
io.vertx.core.http.HttpServerResponse notFound();
75
}
76
```
77
78
**Usage Examples:**
79
80
```java
81
import io.quarkus.vertx.web.RoutingExchange;
82
import io.vertx.core.http.HttpHeaders;
83
84
@ApplicationScoped
85
public class ContextExamples {
86
87
// Basic context access
88
@Route(path = "/info", methods = HttpMethod.GET)
89
public String getRequestInfo(RoutingExchange exchange) {
90
String method = exchange.request().method().name();
91
String path = exchange.request().path();
92
String userAgent = exchange.getHeader("User-Agent").orElse("Unknown");
93
94
return String.format("Method: %s, Path: %s, UA: %s", method, path, userAgent);
95
}
96
97
// Response manipulation
98
@Route(path = "/custom-response", methods = HttpMethod.GET)
99
public void customResponse(RoutingExchange exchange) {
100
exchange.response()
101
.putHeader("X-Custom-Header", "MyValue")
102
.putHeader("Cache-Control", "no-cache");
103
104
exchange.ok("Custom response with headers");
105
}
106
107
// Conditional responses
108
@Route(path = "/conditional/:id", methods = HttpMethod.GET)
109
public void conditionalResponse(@Param("id") String id, RoutingExchange exchange) {
110
if (id == null || id.trim().isEmpty()) {
111
exchange.notFound().end("Item not found");
112
return;
113
}
114
115
try {
116
long itemId = Long.parseLong(id);
117
if (itemId <= 0) {
118
exchange.serverError().end("Invalid item ID");
119
return;
120
}
121
exchange.ok("Item: " + itemId);
122
} catch (NumberFormatException e) {
123
exchange.serverError().end("Invalid item ID format");
124
}
125
}
126
127
// Query parameter access
128
@Route(path = "/search", methods = HttpMethod.GET)
129
public void search(RoutingExchange exchange) {
130
String query = exchange.getParam("q").orElse("");
131
String limit = exchange.getParam("limit").orElse("10");
132
String offset = exchange.getParam("offset").orElse("0");
133
134
if (query.isEmpty()) {
135
exchange.ok("No search query provided");
136
return;
137
}
138
139
exchange.ok(String.format("Search: %s (limit: %s, offset: %s)",
140
query, limit, offset));
141
}
142
}
143
```
144
145
### Low-Level Vert.x Access
146
147
Direct access to Vert.x objects for advanced request/response manipulation.
148
149
```java { .api }
150
// Access patterns for low-level operations
151
io.vertx.ext.web.RoutingContext context = exchange.context();
152
io.vertx.core.http.HttpServerRequest request = exchange.request();
153
io.vertx.core.http.HttpServerResponse response = exchange.response();
154
```
155
156
**Advanced Usage Examples:**
157
158
```java
159
@ApplicationScoped
160
public class AdvancedContextExamples {
161
162
// File upload handling
163
@Route(path = "/upload", methods = HttpMethod.POST, type = Route.HandlerType.BLOCKING)
164
public String handleFileUpload(RoutingExchange exchange) {
165
io.vertx.ext.web.RoutingContext context = exchange.context();
166
167
// Enable body handler for file uploads (configure in application)
168
Set<io.vertx.ext.web.FileUpload> uploads = context.fileUploads();
169
170
if (uploads.isEmpty()) {
171
return exchange.ok("No files uploaded");
172
}
173
174
StringBuilder result = new StringBuilder("Uploaded files:\n");
175
for (io.vertx.ext.web.FileUpload upload : uploads) {
176
result.append("- ").append(upload.fileName())
177
.append(" (").append(upload.size()).append(" bytes)\n");
178
}
179
180
return exchange.ok(result.toString());
181
}
182
183
// Cookie handling
184
@Route(path = "/set-cookie", methods = HttpMethod.POST)
185
public String setCookie(@Body CookieData cookieData, RoutingExchange exchange) {
186
io.vertx.core.http.HttpServerResponse response = exchange.response();
187
188
response.addCookie(io.vertx.core.http.Cookie.cookie(
189
cookieData.getName(),
190
cookieData.getValue()
191
).setMaxAge(3600).setPath("/"));
192
193
return exchange.ok("Cookie set: " + cookieData.getName());
194
}
195
196
// Session handling
197
@Route(path = "/session", methods = HttpMethod.GET)
198
public String handleSession(RoutingExchange exchange) {
199
io.vertx.ext.web.RoutingContext context = exchange.context();
200
io.vertx.ext.web.Session session = context.session();
201
202
if (session == null) {
203
return exchange.ok("No session available");
204
}
205
206
String visitCount = session.get("visitCount");
207
int count = visitCount != null ? Integer.parseInt(visitCount) : 0;
208
count++;
209
session.put("visitCount", String.valueOf(count));
210
211
return exchange.ok("Visit count: " + count);
212
}
213
214
// Request body streaming
215
@Route(path = "/stream-body", methods = HttpMethod.POST, type = Route.HandlerType.NORMAL)
216
public Uni<String> streamRequestBody(RoutingExchange exchange) {
217
io.vertx.core.http.HttpServerRequest request = exchange.request();
218
219
return request.body()
220
.map(buffer -> {
221
int size = buffer.length();
222
String preview = buffer.getString(0, Math.min(100, size));
223
return exchange.ok("Received " + size + " bytes, preview: " + preview);
224
});
225
}
226
}
227
228
// Supporting classes
229
public class CookieData {
230
private String name;
231
private String value;
232
233
public String getName() { return name; }
234
public void setName(String name) { this.name = name; }
235
public String getValue() { return value; }
236
public void setValue(String value) { this.value = value; }
237
}
238
```
239
240
### Response Status and Headers
241
242
Comprehensive response manipulation including status codes, headers, and content types.
243
244
```java
245
@ApplicationScoped
246
public class ResponseExamples {
247
248
// Custom status codes
249
@Route(path = "/custom-status/:code", methods = HttpMethod.GET)
250
public String customStatus(@Param("code") String statusCode, RoutingExchange exchange) {
251
try {
252
int code = Integer.parseInt(statusCode);
253
exchange.response().setStatusCode(code);
254
return exchange.ok("Status set to: " + code);
255
} catch (NumberFormatException e) {
256
return exchange.serverError();
257
}
258
}
259
260
// CORS headers
261
@Route(path = "/cors-enabled", methods = HttpMethod.GET)
262
public String corsEnabled(RoutingExchange exchange) {
263
io.vertx.core.http.HttpServerResponse response = exchange.response();
264
265
response.putHeader("Access-Control-Allow-Origin", "*")
266
.putHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
267
.putHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
268
269
return exchange.ok("CORS headers set");
270
}
271
272
// Content-Type manipulation
273
@Route(path = "/xml-response", methods = HttpMethod.GET)
274
public String xmlResponse(RoutingExchange exchange) {
275
exchange.response().putHeader("Content-Type", "application/xml");
276
return exchange.ok("<?xml version=\"1.0\"?><root><message>Hello XML</message></root>");
277
}
278
279
// Cache control
280
@Route(path = "/cached-resource", methods = HttpMethod.GET)
281
public String cachedResource(RoutingExchange exchange) {
282
exchange.response()
283
.putHeader("Cache-Control", "public, max-age=3600")
284
.putHeader("ETag", "\"resource-v1\"");
285
286
return exchange.ok("This response is cacheable");
287
}
288
}
289
```
290
291
### Error Handling
292
293
Comprehensive error handling using the RoutingExchange interface.
294
295
```java
296
@ApplicationScoped
297
public class ErrorHandlingExamples {
298
299
// Validation with custom error responses
300
@Route(path = "/validate/:id", methods = HttpMethod.GET)
301
public String validateId(@Param("id") String id, RoutingExchange exchange) {
302
if (id == null || id.trim().isEmpty()) {
303
exchange.response().setStatusCode(400);
304
return exchange.ok("Bad Request: ID is required");
305
}
306
307
try {
308
long numericId = Long.parseLong(id);
309
if (numericId <= 0) {
310
exchange.response().setStatusCode(400);
311
return exchange.ok("Bad Request: ID must be positive");
312
}
313
return exchange.ok("Valid ID: " + numericId);
314
} catch (NumberFormatException e) {
315
exchange.response().setStatusCode(400);
316
return exchange.ok("Bad Request: ID must be numeric");
317
}
318
}
319
320
// Authentication check
321
@Route(path = "/protected-resource", methods = HttpMethod.GET)
322
public String protectedResource(RoutingExchange exchange) {
323
String authHeader = exchange.getHeader("Authorization").orElse("");
324
325
if (!authHeader.startsWith("Bearer ")) {
326
exchange.response().setStatusCode(401)
327
.putHeader("WWW-Authenticate", "Bearer");
328
return exchange.ok("Unauthorized: Bearer token required");
329
}
330
331
String token = authHeader.substring(7);
332
if (!isValidToken(token)) {
333
exchange.response().setStatusCode(403);
334
return exchange.ok("Forbidden: Invalid token");
335
}
336
337
return exchange.ok("Access granted to protected resource");
338
}
339
340
private boolean isValidToken(String token) {
341
// Token validation logic
342
return token.length() > 10;
343
}
344
}
345
```