raml-org / raml-spec

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

Define set of query parameters based on the value of other query parameters #749

Open stock-dd opened 3 years ago

stock-dd commented 3 years ago

I have the following case:

traits:
  feedSortable:
    queryParameters:
      sortBy:
        description:  Sort the topic feed
        required:     false
        default:      'most_recent'
        type:         string
        enum:         [ 'most_recent', 'upvotes' ]

      since:
        description:  Get topics since utc creation date. Required in case of upvotes
        required:     false
        type:         datetime-only

      until:
        description:  Get topics until utc creation date
        required:     false
        type:         datetime-only

Since and until query parameters are only required when sortBy is defined as upvotes. How do I enforce this best in my RAML definition? More generally, I want to know how I define query parameter definitions dependent on other query parameters.

The problem is I got stuck in my API definition and therefore development because I'm unable to properly document this, and it would seem this case is very common. You don't want to change the api definition for the sake of the documentation tool. Any solution?

mikeacjones commented 3 years ago

Do you have a proposed format for how you would go about defining this? It seems straightforward to define a query parameter that is only required when another is present, but defining it based on the value of another query parameter doesn't seem like it has an elegant solution.

jenschude commented 3 years ago

Theoretically you could to this with queryString instead of queryParameters

https://github.com/raml-org/raml-spec/blob/master/versions/raml-10/raml-10.md#the-query-string-as-a-whole

and the type would be a union of different intersection types. But I'm pretty sure this would not look very nice in the end.

jstoiko commented 3 years ago

To expand on @jenschude's suggestion, here's how this can be achieved:

(...)
types:
  SortByMostRecent:
    properties:
      sortBy?:
        enum: [ most_recent ]
  SortByUpvotes:
    properties:
      sortBy?:
        enum: [ upvotes ]
      since?:
        type: datetime-only
      until?:
        type: datetime-only

traits:
  feedSortable:
    queryString:
      type: SortByMostRecent | SortByUpvotes
(...)

Making each individual query parameter required: false (or the equivalent <typeName>? syntax), will only restrict query parameters that are of those two exact sets of keys/values. Any other sets of keys/values would be considered valid. In order to make those two sets the only two possible combinations, the sortBy parameter could be made required and any additional (undefined) properties could be forbidden by setting the additionalProperties: false facet on both those types.

Hope this helps!