raml-org / raml-spec

RAML Specification
http://raml.org
3.87k stars 859 forks source link

Parameterized types #684

Open LuisTCosta opened 6 years ago

LuisTCosta commented 6 years ago

I've been looking for any easy way to 'tweak' one DataType so that it can be reused for several methods in one resource.

For example, imagine a item DataType as an object with the following properties:

id:
  type: integer
  required: true
name:
  type: string
  required: true
description:
  type: string
  required: true

Now, I want to be able to use this one DataType across different methods of the /items resource. For a GET, all properties will be passed through on the response, so all of them are required. But, for a POST, since the idproperty will be generated in the DB, the API consumer shouldn't specify an id property. Furthermore, if I want to have a PATCH on /items/{id}, the name and description properties must not be required.

Unfortunately, I haven't seen any practical way that would solve this. The only solution is to specify different types for each method (like item_GET, item_POST, item_PATCH) but this is somewhat cumbersome. If, in the future, a property is added to the entity represented by the item type, then I would need to change all types.

I've even looked into ResourceTypes, but they (as far as I know) would also require to rewrite the entire type for each method.

My proposed solution, is to make types parameterized. In the definition of the DataType, a new section parameters would be added, in which each parameter would be defined as any other DataType (perhaps limiting it to scalar types). Then, when defining the properties of the type itself, those parameters could simply be referenced (in the ResourceTypes syntax, if needed).

For the previous item example, the definition could be something like:

parameters:
  id_required:
    type: boolean
  name_required:
    type: boolean
  description_required:
    type: boolean
properties:
  id:
    type: integer
    required: <<id_required>>
  name:
    type: string
    required: <<name_required>>
  description:
    type: string
    required: <<description_required>>

Then, when defining the /items resource's methods, the parameters would be passed along. Something like:

/items:
  post:
    body:
      type:
        item:
          id_required: false
          name: true
          description: true
  /{id}:
    patch:
      body:
        type:
          item:
            id_required: false
            name: false
            description: false

I believe this would be a great addition to RAML. Do you think it can be included in the spec?

jsamr commented 6 years ago

@LuisTCosta I love the idea of parametrized types since it would greatly enhance DRY principle and modularity. For the PATCH issue, where all fields are optional, check my suggestion: partial inheritance #687

jstoiko commented 6 years ago

I like that idea a lot.

We could also generalize the concept to other types of fragments. It would make a lot of sense and add a lot of DRYness across the board. E.g. re-use a single example multiple times by passing different parameters each time.