RAML 1.0 data types, required properties and GET, PUT, POST


#1

In a Mule project we have a bunch of resources that support GET (Retreive), PUT (update) and POST (Create) operations. For the PUT and POST operations the resource properties have differing needs for required fields. Usually there are a bunch of fields that are required during a create that then become optional during an update. For a GET, you’re not so much showing the required nature as the data is coming from the server as you are showing the schema of the returned data.

How do you handle this requirement in RAML 1.0? Currently we are having to essentially create three data types for each resource - a base xxxxGet that has all fields, an xxxxCreate that has some required fields, and an xxxxUpdate that has pretty much all optional fields (but may only be a sub-set of the get if not everything can be updated).

Am I missing something in the RAML specification that would handle this more cleanly? Thanks in advance for any advice.


#2

hi @Boschy, I think you’re on the right path (pun intended).

In RAML 1.0, fields/properties are required by default. so if you wanted to keep it as DRY as possible, you could have one single type referenced in both your GET response and POST request definitions, and have another type for your PUT request with either required: false or <field_name>? set on the properties you’d want to be optional.

As you may have read in the Specs, a required property in the parent type cannot be changed to optional in the sub-type, but nothing prevents to do the opposite. So you could technically have a parent type with optional properties, use that type for PUT/PATCH, and have a sub-type inheriting from that parent type with required: true set on all properties that were set optional in the parent type, and use that sub-type for both GET (response) and POST (request).

I would not personally use nor recommend the latter approach because I find it a bit odd to start from the “update” case, and I personally prefer the whitelist vs blacklist approach in most things I do. But if the Specs allow it, then it’s not necessarily “wrong”.

The former approach is how I would personally go about it unless I absolutely wanted to make sure that my GET response contain ALL fields (all required), in which case I would write three different types.

I hope this was helpful.


#3

Thanks @jstoiko.

We do in places have a shared entity between PUT and POST. This only works though if all properties returned by the GET are available (required or not) on the POST. We also have a few where the GET is derived from the POST as it returns a couple of extra details, like identifiers, that aren’t needed for the POST.

I have also looked at the pattern of making properties optional in the parent and required in a child object but don’t see it as that useful. As there is no attribute that marks the child properties as overrides, changing something in the parent would not hint that the child also needs changing. You may as well just keep the two entities separate and not complicate them with inheritance (they don’t really meet the “is a type of” test anyway).

What I’d really like to see is some way of defining the object as we have now, but being able to put the required (and maybe even visible) attributes on the GET, PUT or POST command itself.

Thanks again for you information.


#4

HTTP methods can be declared as optional with the use of resourceTypes. I am not sure this is what you had in mind though.

I think one could argue that, in the context of a response definition, the required property of a field is synonym with “may or may not be visible”. So I don’t see why you could not have the type used in your POST request definition, with all its required and optional fields, be re-used in your GET response definition, even if your API always ends-up returning all or only some of those “optional” fields. Annotations might also be a good way to mark which of those “optional” fields are to be hidden from your GET response, and use those annotations as flags for whatever is consuming your RAML file.