I am implementing a Routing Datasource, where the datasource is picked based on the @Destination dbRoutingKey. For multiple rest endpoints we can inject it into the publisher context in a WebFilter and later use it to determine the lookup key. With Spring RSocket @MessageMapping how to write this dbRoutingKey to the request publish context for multiple endpoints?
/*
This works for Rest endpoints.
*/
@Component
@Order(-2)
public class TenancyContextFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
String tenant = extractTenantFromRequestPath(exchange.getRequest());
if (tenant != null) {
return chain.filter(exchange).subscriberContext(context -> context.put(DB_ROUTING_KEY, tenant));
}
return Mono.error(new TenantExtractionException());
}
private String extractTenantFromRequestPath(ServerHttpRequest request) {
String applicationPath = request.getPath().pathWithinApplication().value();
AntPathMatcher matcher = new AntPathMatcher();
matcher.setCaseSensitive(false);
if (matcher.match("/{tenant}/api/**", applicationPath)) {
Map<String, String> templateVariables = matcher.extractUriTemplateVariables("/{tenant}/api/**", applicationPath);
return templateVariables.get("tenant");
}
return null;
}
}
/*
Sample code
With Rocket we can inject the key in every @MessageMapping method
*/
@MessageMapping("test.request.{dbRoutingKey}")
public Mono<String> getData(@Destination String dbRoutingKey) {
return dbDataService.getData().contextWrite(ctx -> ctx.put(DB_ROUTING_KEY, dbRoutingKey));
}