Jacques Chester opened SPR-15169 and commented

Commonly, routing is based on a combination of HTTP method (POST, GET) and URI components (path, query params).

We have a product in which there are "generate" and "regenerate" operations, which can be applied to various "types" (vagueness for effect).

In a URI-based scheme, we might have done something like:

@PostMapping(path = "/a_type")
  public ResponseEntity generateAType( ... )  {
  generateAType();
 }

@PostMapping(path = "/a_type", params={"regenerate=true"})
  public ResponseEntity generateAType( ... )  {
  regenerateAType();
 }

Then POST /a_type would create a new record, and POST /a_type?regenerate=true would regenerate a record. (We're handwaving away some other details).

However, for customer reasons, we cannot encode either of type or operation into the URI. Instead we have to embed these into a JSON payload. Currently in Spring it seems we could route based on matrix variables, query params or request attributes.

What we'd like is something similar for JSON payloads. For example, something like:

@PostMapping(path = "/a_type", payloadParams={"regenerate=true"})
  public ResponseEntity generateAType( ... )  {
  regenerateAType();
 }

Affects: 4.3.5

Comment From: spring-projects-issues

Brian Clozel commented

Hi Jacques Chester,

So you'd like to route a request to a particular Controller method if the JSON payload looks like this?

{
  "type": "project",
  "name": "spring",
  "regenerate": true,
  "foo": bar
}

This would mean that:

  1. we'd need to read the request body using Jackson and somehow deserialize it to a map or a @RequestBody method parameter
  2. since we can't read the request input stream multiple times, we'd need to wrap it and cache the whole body
  3. match that map/object against the argument provided, including for complex values such as dates, null, etc
  4. only dispatch to that method if the condition is met

That goes against many architecture principles behind Spring MVC and this would cause a lot of issues.

You could also use HTTP headers to route to different Controller methods.

But in this case, it seems the logic of selecting the right operation could be done in a service called by the controller. With a single Controller method, you could deserialize that "command" object and process the request accordingly.

The issue description is still a bit vague, so my last comment could apply or could be a very poor architecture choice in your application.

Comment From: spring-projects-issues

Jacques Chester commented

Hi Brian;

I don't necessarily disagree with your argument that this is suboptimal. The architectural deformation comes from the API's shape, where we have product considerations pushing in that direction (this may preclude a header, we'll talk about it more here).

Otherwise we'd stick to existing mechanisms and be done with it.

Your description -- cracking open the body and inspecting it -- is something we're considering ourselves through one of the extension points in Spring. But as much as possible, we always look for a way to delegate hairy operations to Spring, where they can be fit into the existing universe.

There's an imperfect analogy to form parameters here. These are supported by Spring, but presumably with ease due to their status as part of the HTTP standard. But they still represent a data object built from a POST body, rather than from a header or URI.

Our suspicion is that others will encounter this problem or similar; more as time goes on and APIs embed more and more into JSON payloads. Spring Integration treats content-based routing as quite ordinary, so there's precedent for it in a vague hand-wavy kind of way.

Comment From: bclozel

We didn't get much demand for this, so I'm closing this issue for now. Given the dramatic change in the web framework infrastructure, this requires a lot of changes and redesign. Currently this is not worth the effort it seems.

If we get more votes and compelling use cases for this, we might reconsider.