-
Notifications
You must be signed in to change notification settings - Fork 35
Inter parameter dependencies
- What is an inter parameter dependency?
- IDL: a language to specify inter parameter dependencies
- An OpenAPI extension: x-dependencies
There are many APIs that restrict the use of two or more parameters combined in a request. That's what we call inter parameter dependencies. We will take the YouTube Data API as an example. The GET operation of the /search
path describes a considerable amount of inter parameter dependencies. For example, you can only specify one of the following parameters: forContentOwner
, forDeveloper
, forMine
or relatedToVideoId
, or if the location
parameter is set, you must specify the locationRadius
one. If the request does not comply with the restrictions, the API will return a bad request status.
Currently, the OpenAPI specification does not support parameter dependencies and mutually exclusive parameters, as stated in the OpenAPI specification documentation. This is the option OpenAPI offers:
What you can do is document the restrictions in the parameter description and define the logic in the 400 Bad Request response.
It is infeasible to infer the inter parameter dependencies from a formal description in many cases, so it is necessary to design a language which describes those dependencies with a machine-readable definition.
RESTest uses IDL, a language that allows the inter parameter dependencies to be defined in a machine-readable way, so it can be interpreted by an algorithm.
We will use the GET operation of the /search
path for this example again. YouTube indicates that you can only use zero or one of the following parameters: forContentOwner
, forDeveloper
, forMine
or relatedToVideoId
. You can declare this inter parameter dependency with IDL using the ZeroOrOne
function:
ZeroOrOne(forContentOwner, forDeveloper, forMine, relatedToVideoId);
Another dependency is the following one:
The API returns an error if your request specifies a value for the
location
parameter but does not also specify a value for thelocationRadius
parameter.
You can use the function AllOrNone
to declare this dependency:
AllOrNone(location, locationRadius);
You can also use the logical operators AND
, OR
and NOT
, the comparison operators >
, <
, >=
, <=
and ==
, and the conditional operator IF (...) THEN (...)
. For example, the following restriction:
If
forContentOwner
is set to true, the request must also meet these requirements:
- The
onBehalfOfContentOwner
parameter is required.
[...]- The type parameter value must be set to
video
.- None of the following other parameters can be set:
videoDefinition
,videoDimension
,videoDuration
,videoLicense
,videoEmbeddable
,videoSyndicated
,videoType
.
can be declared as:
IF forContentOwner==true THEN onBehalfOfContentOwner AND type=='video' AND NOT (videoDefinition OR videoDimension OR videoDuration OR videoLicense OR videoEmbeddable OR videoSyndicated OR videoType);
You can see more examples in the IDL repository.
As you can see, IDL is very helpful, as it gives us a tool to model the inter parameter dependencies without using formal language. But where can we declare those dependencies if the OpenAPI specification does not support them?
OpenAPI does not support inter parameter dependencies, but it supports extensions, which are custom properties for describing extra functionalities that are not covered by the OpenAPI specification. RESTest makes use of an extension for the operations called x-dependencies
, which is an array where you can specify the inter parameter dependencies using IDL. Here you can see how you can declare the inter parameter dependencies of the YouTube Data API GET operation of the /search
path in the OpenAPI specification file:
# (...)
/search:
get:
description: 'Returns a collection of search results that match the query parameters specified in the API request. By default, a search result set identifies matching video, channel, and playlist resources, but you can also configure queries to only retrieve a specific type of resource.'
operationId: youtube.search.list
parameters:
# (...)
x-dependencies:
- ZeroOrOne(forContentOwner, forDeveloper, forMine, relatedToVideoId);
- IF forContentOwner==true THEN onBehalfOfContentOwner AND type=='video' AND NOT (videoDefinition OR videoDimension OR videoDuration OR videoLicense OR videoEmbeddable OR videoSyndicated OR videoType);
- IF forMine==true THEN type=='video' AND NOT (videoDefinition OR videoDimension OR videoDuration OR videoLicense OR videoEmbeddable OR videoSyndicated OR videoType);
- IF relatedToVideoId THEN type=='video' AND NOT (channelId OR channelType OR eventType OR location OR locationRadius OR onBehalfOfContentOwner OR order OR publishedAfter OR publishedBefore OR q OR topicId OR videoCaption OR videoCategoryId OR videoDefinition OR videoDimension OR videoDuration OR videoEmbeddable OR videoLicense OR videoSyndicated OR videoType);
- IF eventType THEN type=='video';
- AllOrNone(location, locationRadius);
# - publishedAfter>=publishedBefore; # Date comparison is not supported yet
- IF videoCaption THEN type=='video';
- IF videoCategoryId THEN type=='video';
- IF videoDefinition THEN type=='video';
- IF videoDimension THEN type=='video';
- IF videoDuration THEN type=='video';
- IF videoEmbeddable THEN type=='video';
- IF videoLicense THEN type=='video';
- IF videoSyndicated THEN type=='video';
- IF videoType THEN type=='video';
responses:
# (...)