Can RAML support multiple request bindings to one URL/verb?


#1

I’m relatively new to RAML so I may have missed something obvious in what follows…

In Spring MVC you can have multiple Controller methods that are bound to the same combination of URL and HTTP action; Spring MVC allows this as long as there is sufficient information regarding request parameters and headers to enable two requests to be distinguished.

For example:

@RequestMapping(value="/thing", method=RequestMethod.GET, params={“date”})
@ResponseBody
public List findActiveOnDate(@RequestParam(“date”) final Date date);

and

@RequestMapping(value="/thing", method=RequestMethod.GET, params={“name”})
@ResponseBody
public List findByName(@RequestParam(“name”) final String name);

are allowed by Spring MVC because it can route GET requests to /thing based on which of the two request parameters “name” or “date” is present.

As far as I can see there is no way in RAML to express the idea that “name” and “date” are “alternative” request parameters in RAML. You only get one shot at defining the request characteristics of a GET at a given URL. So when mapping the above to RAML you have to include both request parameters and make them optional e.g.

/thing:
  get:
    queryParameters:
      name:
        type: string
        required: false
      date:
        type: date
        required: false

In the above RAML snippet, you can’t express formally the idea that either “name” or “date” is required, but not both.

The situation becomes more complex if the “variants” of the GET to /thing support multiple parameters, different response types etc. etc.

What seems to be missing is the ability to have multiple bindings for the same HTTP operation at a given URL - something like:

/thing:
     get:
        queryParameters:
          name:
            type: string
            required: true
     get:
        queryParameters:
          date:
            type: date
            required: true

All the RAML parsers I’m familiar with reject the above because “get:” can’t be declared multiple times for a given URL.


#2

I’d be very grateful for any input on this, even if it’s just to say I’ve misunderstood the RAML spec in some way. It seems perfectly valid to have different bindings to a GET for the same base URL which each have a different set of supported parameters and each return different resource representations, but it appears to me that RAML 0.8 doesn’t support that level of detail.

Have I misunderstood, or are there any plans to address this kind of thing in the next version?

Many thanks.


#3

I am a little unsure of how you are stuck at this point. The first snippet of RAML you defined makes sense, you have two query parameters (optional it appears). Are you using a tool to take the RAML and generate Spring MVC code?

You can use the raml-generator project to build your own Handlebars.js template that could very well create two separate methods, one for each query parameter, but that is really a matter of your wanting it done that way. For example, why could you not have a single method that accepts ALL query parameters? In fact, I’d argue against the two method way you present because what happens when they use both query parameters? Now you have to have a 3rd method to support the combo of both. Instead, I’d rather see something like:

@RequestMapping(value="/thing", method=RequestMethod.GET, params={“date”, ‘name’, ‘other’})
@ResponseBody
public List findActiveOnDate(@RequestParam(“date”) final Date date, @RequestParam(“name”) final String name, @RequestParam(“other”) final String other);

This way, you have one method that can handle any combo of the 3. You could even, in the template, determine if the query param is required or not, and if so, insert some code that adds a null/empty string/0 length check, and throw an exception if the required rule is not met for the given query parameter.

It took me a couple weeks and some help from the RAML guys to finally get my head around raml-generator, but now that I am using it, it is quite nice and easy to add any sort of generator, from server side, client side SDK or html doc output if wanted all in the same manner.


#4

Thanks for your reply Justin - on reflection it would have helped if I had explained a little more clearly; I’m generating RAML descriptions of existing Spring MVC controllers, so the opportunity to go back and “fix the Controller” is not possible here.

Besides, I think there’s something a little more going here, even if I could adjust the method in the way you describe.

The contract that the Controller methods are expressing is that a GET against /thing requires either the date param or the name param, but not both. That is what I think RAML’s model is currently not capable of expressing; you can indicate whether a parameter is required or not, but you can’t express the notion of “parameter groups” within which there are different constraints.

If you add into the mix the possibility that these two controller methods return different representations (e.g. one might return a single instance of thing, the other might return a collection) then you run into a similar problem with response bodies in RAML.

This is all about capturing constraints as accurately as possible; you can of course indicate in RAML that the two parameters are optional, and that the response (in e.g. JSON schema terms) is “oneOf” a single instance or a collection, but you lose the extra information that could drive a client to operate correctly.

Hope that makes sense.


#5

Ok…I understand. Yah, I am not sure if what you are looking to do is possible at this time in RAML. I think it would need the addition of some sort of AND/OR construct in the RAML definition itself, but because RAML is a spec, the only thing that may make use of this extra info is generators that turn RAML into something, such as documentation. If you are taking existing Spring and putting it in to RAML… what will you then do with the RAML… generate documentation and other things from it?

As a side note, assuming you could capture the entirety of Spring MVC into a RAML document, and there were a RAML to JAX-RS output… how cool would it be that we could use the RAML-GENERATOR project like a input/output converter. Input Spring-MVC to RAML, output RAML to JAX-RS… now you got a Spring MVC to JAX-RX project conversion path. If what you are working on does indeed capture SpringMVC to RAML, it would be great to offer this option to the community, and possibly the Mulesoft/Raml.org guys could look at taking the raml-generator project a step further for not just generating RAML to something, but allowing conversions to occur.


Method 'patch' already exists
#6

Hi Justin

My current intended usage for the RAML generated from Spring MVC controllers is two-fold; the first is documentation, and the second is for consumption by Mule Anypoint Studio when building HttpConnectors (i.e. defining RAML-based REST clients in Mule flows).

On the latter I don’t think Anypoint currently exploits all that it could RAML-wise (e.g. it doesn’t surface the fact that some URL parameters are optional), but in the spirit of improvement it would be great if in future releases it understood the concept of “alternative” request parameter groups (and corresponding response types) should that ever make it into RAML.

Alas I’m not in a position to make the work done so far in Spring MVC -> RAML generally available for a number of reasons, but the generic transformation work is fairly straightforward with a little knowledge of Spring MVC annotations and the standard RequestMappingHandlerMapping class from Spring MVC.


#7

bump

Experiencing the same issue years later. Seems to still have not been fixed.


#8

To be clear, I don’t think there is anything to fix here. RAML requires that a method be declared only once per resource. I have never seen a case where this was limiting an implementation in any way. In fact, most if not all implementations that I have seen (in several languages and frameworks) enforce the same rule at the routing level.

I think this can be achieved by using a combination of types, unions and type inheritance using queryString as the first example of this section showcases really well.


#9

Thanks for the pointer to those examples from the spec; the use of union types certainly helps address some of the original issues that motivated this question. But unless I’ve missed something, it doesn’t admit of expressing how the returned resource representation might depend upon which choice of input parameters is made.


#10

That’s right, it doesn’t. On one hand, I think that a mechanism that provides a way to describe conditional responses is something that could be useful. On the other hand, I think that this logic belongs to the API implementation rather than the API definition itself, and there is already a mechanism to describe such things, i.e. annotations.