My Spring Reactive Web API should be able to filter based on query parameters but I'm struggling to get this right.
GET /v1/address?type=business
Should return all addresses of type 'business' in the system (just an example since I'm not posting the actual requirements). If the parameter is absent then just return all addresses.
[
{ "id" : 1, "type" : "business", "street" : "..."},
{ "id" : 2, "type" : "business", "street" : "..."},
...
}
I'm using Router functions to map the request:
public RouterFunction<ServerResponse> route(AddressHandler handler) {
return route(GET("/v1/address"), handler::getAddresses);
}
But I'm struggling to determine how to check for the parameter and, if it isn't present, to return all addresses.
class AddressHandler {
Mono<ServerResponse> getAddressesFilteredOrNot(ServerRequest request) {
Optional<String> addressType = request.getQueryParam("type");
...
}
}
Now the Optional.ifPresent() isn't going to work, I can't return from the method:
class AddressHandler {
Mono<ServerResponse> getAddressesFilteredOrNot(ServerRequest request) {
Optional<String> addressType = request.getQueryParam("type");
// invalid
addressType.ifPresent(addrType -> {
return ServerResponse.ok()
.body(this.service.getAddressByType(addrType),
Address.class);
});
}
Also I can't switchIfEmpty() on the parameter since it throws a NullPointerException:
class AddressHandler {
Mono<ServerResponse> getAddressesFilteredOrNot(ServerRequest request) {
Optional<String> addressType = request.getQueryParam("type");
// also invalid
return Mono.justOrEmpty(addressType.orElse(""))
.flatMap(addrType -> ServerResponse.ok().body(this.service.getAddressByType(addrType), Address.class)
.switchIfEmpty(ServerResponse.ok().body(this.service.getAllAddresses(), Address.class));
});
}
What's the flow to use query parameters if they are present and fall back on the getAllAddresses() method? Is it actually possible?
You can use the orElse()
or orElseGet()
functionality of Optional
to invoke an alternative method. For example:
request
.getQueryParam("type")
.map(type -> service.getAddressByType(type))
.orElseGet(() -> service.getAllAddresses());
In this case, orElseGet()
makes more sense, because it's lazily invoked. Be aware though that both methods should have the same return type, so probably Flux<Address>
.