0
# HTTP Server
1
2
Micronaut's HTTP server provides high-performance request handling with both blocking and non-blocking APIs, comprehensive routing, content negotiation, and error handling.
3
4
## Capabilities
5
6
### Controllers
7
8
Define HTTP endpoints using controller classes with declarative routing annotations.
9
10
```java { .api }
11
/**
12
* Basic controller with GET endpoint
13
*/
14
@Controller("/api/users")
15
public class UserController {
16
17
@Get("/{id}")
18
public User getUser(Long id) {
19
return userService.findById(id);
20
}
21
22
@Get
23
public List<User> getUsers(@QueryValue Optional<String> filter) {
24
return userService.findAll(filter.orElse(null));
25
}
26
27
@Post
28
public HttpResponse<User> createUser(@Body @Valid User user) {
29
User created = userService.save(user);
30
return HttpResponse.created(created);
31
}
32
33
@Put("/{id}")
34
public User updateUser(Long id, @Body @Valid User user) {
35
return userService.update(id, user);
36
}
37
38
@Delete("/{id}")
39
@Status(HttpStatus.NO_CONTENT)
40
public void deleteUser(Long id) {
41
userService.delete(id);
42
}
43
}
44
```
45
46
### Parameter Binding
47
48
Bind HTTP request data to method parameters with type conversion and validation.
49
50
```java { .api }
51
/**
52
* Path parameters, query parameters, and headers
53
*/
54
@Controller("/api/products")
55
public class ProductController {
56
57
@Get("/{id}")
58
public Product getProduct(@PathVariable Long id,
59
@QueryValue Optional<Boolean> includeDetails,
60
@Header("Accept-Language") String language) {
61
return productService.findById(id, includeDetails.orElse(false), language);
62
}
63
64
@Get
65
public Page<Product> searchProducts(@QueryValue String q,
66
@QueryValue @Positive int page,
67
@QueryValue @Positive int size,
68
@QueryValue Optional<String> sort) {
69
return productService.search(q, page, size, sort.orElse("name"));
70
}
71
72
@Post("/bulk")
73
public List<Product> createProducts(@Body List<@Valid Product> products,
74
@Header("X-Batch-Id") String batchId) {
75
return productService.createBatch(products, batchId);
76
}
77
}
78
79
/**
80
* Form data and multipart handling
81
*/
82
@Controller("/upload")
83
public class FileUploadController {
84
85
@Post(value = "/", consumes = MediaType.MULTIPART_FORM_DATA)
86
public HttpResponse<String> upload(@Part CompletedFileUpload file,
87
@Part("description") String description) {
88
String filename = fileService.store(file, description);
89
return HttpResponse.ok("File uploaded: " + filename);
90
}
91
92
@Post(value = "/form", consumes = MediaType.APPLICATION_FORM_URLENCODED)
93
public HttpResponse<String> handleForm(@Body Map<String, String> formData) {
94
return HttpResponse.ok("Form processed");
95
}
96
}
97
```
98
99
### Content Negotiation
100
101
Handle different content types for request and response bodies.
102
103
```java { .api }
104
/**
105
* Content type handling
106
*/
107
@Controller("/api/data")
108
public class DataController {
109
110
@Get(value = "/export", produces = {
111
MediaType.APPLICATION_JSON,
112
MediaType.APPLICATION_XML,
113
"text/csv"
114
})
115
public Object exportData(@Header("Accept") String acceptHeader) {
116
if (acceptHeader.contains("xml")) {
117
return new XmlDataResponse();
118
} else if (acceptHeader.contains("csv")) {
119
return new CsvDataResponse();
120
}
121
return new JsonDataResponse();
122
}
123
124
@Post(value = "/import", consumes = {
125
MediaType.APPLICATION_JSON,
126
MediaType.APPLICATION_XML
127
})
128
public HttpResponse<ImportResult> importData(@Body Object data) {
129
ImportResult result = dataService.importData(data);
130
return HttpResponse.ok(result);
131
}
132
}
133
```
134
135
### Reactive Controllers
136
137
Handle requests reactively using reactive types for non-blocking I/O.
138
139
```java { .api }
140
/**
141
* Reactive endpoints with Single, Maybe, and Flowable
142
*/
143
@Controller("/api/async")
144
public class AsyncController {
145
146
@Get("/user/{id}")
147
public Single<User> getUserAsync(Long id) {
148
return userService.findByIdAsync(id);
149
}
150
151
@Get("/users")
152
public Flowable<User> streamUsers(@QueryValue Optional<String> filter) {
153
return userService.streamAll(filter.orElse(null));
154
}
155
156
@Post("/user")
157
public Single<HttpResponse<User>> createUserAsync(@Body @Valid User user) {
158
return userService.saveAsync(user)
159
.map(HttpResponse::created);
160
}
161
162
@Get(value = "/events", produces = MediaType.TEXT_EVENT_STREAM)
163
public Publisher<Event> streamEvents() {
164
return eventService.streamEvents();
165
}
166
}
167
168
/**
169
* CompletableFuture support
170
*/
171
@Controller("/api/future")
172
public class FutureController {
173
174
@Get("/data/{id}")
175
public CompletableFuture<Data> getDataAsync(Long id) {
176
return dataService.fetchAsync(id);
177
}
178
}
179
```
180
181
### Error Handling
182
183
Handle errors and exceptions with custom error responses.
184
185
```java { .api }
186
/**
187
* Exception handlers
188
*/
189
@Singleton
190
public class GlobalExceptionHandler implements ExceptionHandler<Exception, HttpResponse<?>> {
191
192
@Override
193
public HttpResponse<?> handle(HttpRequest request, Exception exception) {
194
return HttpResponse.serverError()
195
.body(Map.of("error", exception.getMessage()));
196
}
197
}
198
199
/**
200
* Specific exception handlers
201
*/
202
@Singleton
203
public class ValidationExceptionHandler
204
implements ExceptionHandler<ConstraintViolationException, HttpResponse<?>> {
205
206
@Override
207
public HttpResponse<?> handle(HttpRequest request,
208
ConstraintViolationException exception) {
209
List<String> errors = exception.getConstraintViolations()
210
.stream()
211
.map(ConstraintViolation::getMessage)
212
.collect(Collectors.toList());
213
214
return HttpResponse.badRequest()
215
.body(Map.of("errors", errors));
216
}
217
}
218
219
/**
220
* Controller-level error handling
221
*/
222
@Controller("/api/orders")
223
public class OrderController {
224
225
@Get("/{id}")
226
public Order getOrder(Long id) {
227
return orderService.findById(id);
228
}
229
230
@Error(exception = OrderNotFoundException.class)
231
public HttpResponse<Map<String, String>> handleOrderNotFound(OrderNotFoundException ex) {
232
return HttpResponse.notFound(Map.of("error", ex.getMessage()));
233
}
234
235
@Error(status = HttpStatus.BAD_REQUEST)
236
public HttpResponse<Map<String, String>> handleBadRequest() {
237
return HttpResponse.badRequest(Map.of("error", "Invalid request"));
238
}
239
}
240
```
241
242
### Filters
243
244
Implement request/response filtering for cross-cutting concerns.
245
246
```java { .api }
247
/**
248
* HTTP filters for cross-cutting concerns
249
*/
250
@Filter("/api/**")
251
public class AuthenticationFilter implements HttpServerFilter {
252
253
@Override
254
public Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request,
255
ServerFilterChain chain) {
256
String authHeader = request.getHeaders().get("Authorization");
257
if (authHeader == null || !isValidToken(authHeader)) {
258
MutableHttpResponse<?> response = HttpResponse.unauthorized();
259
return Publishers.just(response);
260
}
261
return chain.proceed(request);
262
}
263
264
private boolean isValidToken(String token) {
265
// Token validation logic
266
return true;
267
}
268
}
269
270
/**
271
* CORS filter
272
*/
273
@Filter("/**")
274
public class CorsFilter implements HttpServerFilter {
275
276
@Override
277
public Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request,
278
ServerFilterChain chain) {
279
if (request.getMethod() == HttpMethod.OPTIONS) {
280
MutableHttpResponse<?> response = HttpResponse.ok()
281
.header("Access-Control-Allow-Origin", "*")
282
.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
283
.header("Access-Control-Allow-Headers", "Content-Type, Authorization");
284
return Publishers.just(response);
285
}
286
287
return chain.proceed(request)
288
.map(response -> response.header("Access-Control-Allow-Origin", "*"));
289
}
290
}
291
```
292
293
### Server Configuration
294
295
Configure the HTTP server with custom settings and SSL support.
296
297
```java { .api }
298
/**
299
* Server configuration properties
300
*/
301
@ConfigurationProperties("micronaut.server")
302
public class ServerConfiguration {
303
private int port = 8080;
304
private String host = "localhost";
305
private Duration readTimeout = Duration.ofSeconds(30);
306
private Duration writeTimeout = Duration.ofSeconds(30);
307
private int maxRequestSize = 1024 * 1024 * 10; // 10MB
308
309
// getters and setters
310
}
311
312
/**
313
* SSL configuration
314
*/
315
@ConfigurationProperties("micronaut.server.ssl")
316
public class SslConfiguration {
317
private boolean enabled = false;
318
private String keyStore;
319
private String keyStorePassword;
320
private String keyStoreType = "JKS";
321
private String trustStore;
322
private String trustStorePassword;
323
324
// getters and setters
325
}
326
327
/**
328
* Custom server configuration
329
*/
330
@Factory
331
public class ServerFactory {
332
333
@Bean
334
@Replaces(NettyHttpServerConfiguration.class)
335
public NettyHttpServerConfiguration customServerConfig() {
336
return new NettyHttpServerConfiguration() {
337
@Override
338
public int getMaxHeaderSize() {
339
return 16384; // 16KB headers
340
}
341
};
342
}
343
}
344
```
345
346
## Types
347
348
```java { .api }
349
// Core HTTP types
350
public interface HttpRequest<B> extends HttpMessage<B> {
351
HttpMethod getMethod();
352
URI getUri();
353
String getPath();
354
HttpParameters getParameters();
355
Map<String, Object> getAttributes();
356
Optional<B> getBody();
357
<T> Optional<T> getBody(Class<T> type);
358
}
359
360
public interface HttpResponse<B> extends HttpMessage<B> {
361
HttpStatus getStatus();
362
int code();
363
String reason();
364
static <T> MutableHttpResponse<T> ok();
365
static <T> MutableHttpResponse<T> created(T body);
366
static <T> MutableHttpResponse<T> badRequest();
367
static <T> MutableHttpResponse<T> notFound();
368
}
369
370
public interface MutableHttpResponse<B> extends HttpResponse<B>, MutableHttpMessage<B> {
371
MutableHttpResponse<B> status(HttpStatus status);
372
MutableHttpResponse<B> header(CharSequence name, CharSequence value);
373
MutableHttpResponse<B> body(B body);
374
}
375
376
// Filter interfaces
377
public interface HttpServerFilter extends ServerFilter {
378
Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request,
379
ServerFilterChain chain);
380
}
381
382
public interface ServerFilterChain {
383
Publisher<MutableHttpResponse<?>> proceed(HttpRequest<?> request);
384
}
385
386
// Exception handling
387
public interface ExceptionHandler<T extends Throwable, R> {
388
R handle(HttpRequest request, T exception);
389
}
390
391
// Route matching
392
public interface Router {
393
<T, R> Stream<UriRouteMatch<T, R>> find(HttpMethod httpMethod,
394
CharSequence uri,
395
HttpRequest<?> context);
396
<T, R> Optional<UriRouteMatch<T, R>> route(HttpMethod httpMethod,
397
CharSequence uri);
398
}
399
400
public interface RouteMatch<R> {
401
R execute(Map<String, Object> argumentValues);
402
Collection<Argument> getRequiredArguments();
403
boolean isExecutable();
404
}
405
406
// File upload
407
public interface CompletedFileUpload extends FileUpload {
408
byte[] getBytes();
409
InputStream getInputStream();
410
void moveTo(File destinationFile);
411
Optional<MediaType> getContentType();
412
}
413
```