Problem : I have 2 functional endpoints
@Bean
public RouterFunction<ServerResponse> getById() {
return RouterFunctions.route(
GET("/threads/{threadId}"),
request -> ServerResponse.ok().bodyValue("/threads/{threadId}")
);
}
@Bean
public RouterFunction<ServerResponse> getSomeEntity() {
return RouterFunctions.route(
GET("/threads/some"),
request -> ServerResponse.ok().bodyValue("/threads/some"));
}
When i make request with GET /threads/some
Expected behavior : handler from getSomeEntity
router function bean will be invoked, response (/threads/some)
Actual behavior : handler from getById
router function bean will be invoked, response (/threads/{threadId})
so it is impossible to invoke handler function from getSomeEntity()
bean, because always invokes getById
.
also tried to unite this 2 functions into one RouterFunction
bean, problem also reproduces
NOTE
if try to model same situation with @RestController
and @GetMapping
pattern matching works as expected
spring boot version: 2.3.5 Release
from dependencies only
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
```
**Comment From: philwebb**
I don't think that `RouterFunction` beans work in the same way as `@RestController` mappings. I think the first matching route will win. You could try adding `@Order` to your bean definitions so that the `/threads/some` function is before the pattern.
I'll transfer this issue to the Spring Framework team that are responsible for this code.
**Comment From: tka4ukalex**
Thank you, as temporary workaround @Order helped
**Comment From: bclozel**
As Phil said, routes defined within a `RouterFunction` [will be evaluated in order](https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-fn-routes).
This means that if you define both `GET("/threads/{threadId}")` and `GET("/threads/some")` in the same `RouterFunction`, `GET("/threads/some")` should be defined first as it's the most specific. This is an important design principle with WebFlux.fn.
I'm not sure if the code snippet you've provided is a sample repro or is an actual part of your application. In most cases, you should try and declare related routes (or all your app routes, it's your call) within the same `RouterFunction`. Something like this:
@Bean
public RouterFunction
This, as well as nested routes, is explained in the reference docs.
You can define multiple RouterFunction
instances in your application. Maybe you want to have one per "feature slice" in your application and keep handlers and routes package private. In this case, related routes should still be defined in the same RouterFunction
. During startup, all RouterFunction
components are loaded and reduced, in order, as a single RouterFunction
.
To summarize, ordering between routes is guaranteed by:
- their declaration order within a
RouterFunction
- the
RouterFunction
ordering of components, using the standard Spring ordering mechanism with@Order
orimplements Ordered
.
In your case, declaring related routes within the same RouterFunction
seems like a good match. If there are other constraints not shown in your sample, then @Order
is not a workaround, but the expected way of achieving this.
I'm leaving this issue opened for now as this specific part might not be well documented in the reference docs. Paging @poutsma for an opinion here.
Comment From: tka4ukalex
@bclozel thank you for your detailed explanation, now everything is clear.