6.9 The HttpRequest and HttpResponse
If you need more control over request processing you can write a method that receives the complete HttpRequest.
In fact, there are several higher-level interfaces that can be bound to controller method parameters. These include:
Interface | Description | Example |
---|---|---|
The full |
| |
All HTTP headers present in the request |
| |
All HTTP parameters (either from URI variables or request parameters) present in the request |
| |
All Cookies present in the request |
|
The HttpRequest should be declared parametrized with a concrete generic type if the request body is needed, e.g. HttpRequest<MyClass> request . The body may not be available from the request otherwise. |
In addition, for full control over the emitted HTTP response you can use the static factory methods of the HttpResponse class which return a MutableHttpResponse.
The following example implements the previous MessageController
example using the HttpRequest and HttpResponse objects:
Request and Response Example
import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.context.ServerRequestContext;
import reactor.core.publisher.Mono;
@Controller("/request")
public class MessageController {
@Get("/hello") (1)
public HttpResponse<String> hello(HttpRequest<?> request) {
String name = request.getParameters()
.getFirst("name")
.orElse("Nobody"); (2)
return HttpResponse.ok("Hello " + name + "!!")
.header("X-My-Header", "Foo"); (3)
}
}
Request and Response Example
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpResponse
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Get
import io.micronaut.http.context.ServerRequestContext
import reactor.core.publisher.Mono
@Controller("/request")
class MessageController {
@Get("/hello") (1)
HttpResponse<String> hello(HttpRequest<?> request) {
String name = request.parameters
.getFirst("name")
.orElse("Nobody") (2)
HttpResponse.ok("Hello " + name + "!!")
.header("X-My-Header", "Foo") (3)
}
}
Request and Response Example
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpResponse
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Get
import io.micronaut.http.context.ServerRequestContext
import reactor.core.publisher.Mono
import reactor.util.context.ContextView
@Controller("/request")
class MessageController {
@Get("/hello") (1)
fun hello(request: HttpRequest<*>): HttpResponse<String> {
val name = request.parameters
.getFirst("name")
.orElse("Nobody") (2)
return HttpResponse.ok("Hello $name!!")
.header("X-My-Header", "Foo") (3)
}
}
1 | The method is mapped to the URI /hello and accepts a HttpRequest |
2 | The HttpRequest is used to obtain the value of a query parameter named name . |
3 | The HttpResponse.ok(T) method returns a MutableHttpResponse with a text body. A header named X-My-Header is also added to the response. |
The HttpRequest is also available from a static context via ServerRequestContext.
Using the ServerRequestContext
import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.context.ServerRequestContext;
import reactor.core.publisher.Mono;
@Controller("/request")
public class MessageController {
@Get("/hello-static") (1)
public HttpResponse<String> helloStatic() {
HttpRequest<?> request = ServerRequestContext.currentRequest() (1)
.orElseThrow(() -> new RuntimeException("No request present"));
String name = request.getParameters()
.getFirst("name")
.orElse("Nobody");
return HttpResponse.ok("Hello " + name + "!!")
.header("X-My-Header", "Foo");
}
}
Using the ServerRequestContext
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpResponse
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Get
import io.micronaut.http.context.ServerRequestContext
import reactor.core.publisher.Mono
@Controller("/request")
class MessageController {
@Get("/hello-static") (1)
HttpResponse<String> helloStatic() {
HttpRequest<?> request = ServerRequestContext.currentRequest() (1)
.orElseThrow(() -> new RuntimeException("No request present"))
String name = request.parameters
.getFirst("name")
.orElse("Nobody")
HttpResponse.ok("Hello " + name + "!!")
.header("X-My-Header", "Foo")
}
}
Using the ServerRequestContext
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpResponse
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Get
import io.micronaut.http.context.ServerRequestContext
import reactor.core.publisher.Mono
import reactor.util.context.ContextView
@Controller("/request")
class MessageController {
@Get("/hello-static") (1)
fun helloStatic(): HttpResponse<String> {
val request: HttpRequest<*> = ServerRequestContext.currentRequest<Any>() (1)
.orElseThrow { RuntimeException("No request present") }
val name = request.parameters
.getFirst("name")
.orElse("Nobody")
return HttpResponse.ok("Hello $name!!")
.header("X-My-Header", "Foo")
}
}
1 | The ServerRequestContext is used to retrieve the request. |
Generally ServerRequestContext is available within reactive flow, but the recommended approach is consume the request as an argument as shown in the previous example. If the request is needed in downstream methods it should be passed as an argument to those methods. There are cases where the context is not propagated because other threads are used to emit the data. |
An alternative for users of Project Reactor to using the ServerRequestContext is to use the contextual features of Project Reactor to retrieve the request. Because the Micronaut Framework uses Project Reactor as it’s default reactive streams implementation, users of Project Reactor can benefit by being able to access the request in the context. For example:
Using the Project Reactor context
import io.micronaut.http.HttpRequest;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.context.ServerRequestContext;
import reactor.core.publisher.Mono;
@Controller("/request")
public class MessageController {
@Get("/hello-reactor")
public Mono<HttpResponse<String>> helloReactor() {
return Mono.deferContextual(ctx -> { (1)
HttpRequest<?> request = ctx.get(ServerRequestContext.KEY); (2)
String name = request.getParameters()
.getFirst("name")
.orElse("Nobody");
return Mono.just(HttpResponse.ok("Hello " + name + "!!")
.header("X-My-Header", "Foo"));
});
}
}
Using the Project Reactor context
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpResponse
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Get
import io.micronaut.http.context.ServerRequestContext
import reactor.core.publisher.Mono
@Controller("/request")
class MessageController {
@Get("/hello-reactor")
Mono<HttpResponse<String>> helloReactor() {
Mono.deferContextual(ctx -> { (1)
HttpRequest<?> request = ctx.get(ServerRequestContext.KEY) (2)
String name = request.parameters
.getFirst("name")
.orElse("Nobody")
Mono.just(HttpResponse.ok("Hello " + name + "!!")
.header("X-My-Header", "Foo"))
})
}
}
Using the Project Reactor context
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpResponse
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Get
import io.micronaut.http.context.ServerRequestContext
import reactor.core.publisher.Mono
import reactor.util.context.ContextView
@Controller("/request")
class MessageController {
@Get("/hello-reactor")
fun helloReactor(): Mono<HttpResponse<String>?>? {
return Mono.deferContextual { ctx: ContextView -> (1)
val request = ctx.get<HttpRequest<*>>(ServerRequestContext.KEY) (2)
val name = request.parameters
.getFirst("name")
.orElse("Nobody")
Mono.just(HttpResponse.ok("Hello $name!!")
.header("X-My-Header", "Foo"))
}
}
}
1 | The Mono is created with a reference to the context |
2 | The request is retrieved from the context |
Using the context to retrieve the request is the best approach for reactive flows because Project Reactor propagates the context and it does not rely on a thread local like ServerRequestContext.