-
Notifications
You must be signed in to change notification settings - Fork 34
Inter parameter dependencies
One of the prominent features of RESTest is its ability to support dependencies between parameters, allowing the definition of logical relationships among them and ensuring that requests meet the server's requirements.
Proper management of parameter dependencies is crucial to ensure the coherence and security of an API. At times, certain parameters should only be valid or necessary if specific other parameters are provided. In other words, the value or existence of one parameter may depend on another. If these dependencies are not handled correctly, communication errors between the client and server may arise, leading to unexpected results or even API failures.
RESTest addresses this challenge by enabling developers to define rules and restrictions for parameters based on their interrelationships. This means that logical conditions can be established for the values or existence of certain parameters, ensuring that requests sent to the API are consistent and comply with the server's specified requirements.
- What are inter-parameter dependencies?
- IDL: describing inter-parameter dependencies
- IDL4OAS: including dependencies in an OAS document
Inter-parameter dependencies are constraints that restrict the way in which two or more input parameters can be combined to form valid calls to some API operation. For example, the documentation of the search operation of the YouTube API states that, when using the videoDefinition
parameter, the type
parameter must be set to video
, otherwise a 400 status code ("bad request") is returned:
Automatically generating test cases without considering inter-parameter dependencies can be challenging in practice. To address this issue, you can formally specify the inter-parameter dependencies present in the API using the Inter-parameter Dependency Language (IDL), a Domain-Specific Language (DSL) designed to support [various types of inter-parameter dependencies commonly encountered in real-world scenarios]((https://www.researchgate.net/publication/336816181_A_Catalogue_of_Inter-parameter_Dependencies_in_RESTful_Web_APIs). By doing so, these dependencies will be taken into account during the test case generation process.
The following are some examples of dependencies described in IDL.
The presence of a parameter p1 in an API call requires the presence of another parameter p2, denoted as p1 → p2.
As an example, in the Paypal Invoicing API, when creating a draft invoice, if the parameter custom.label is present, then custom.custom amount becomes required, i.e. custom.label → custom.custom amount. Similarly, in the YouTube Data API, when searching for videos with a certain definition (parameter videoDefinition), the type parameter must be set to ‘video’, i.e. videoDefinition → type=video.
Given a set of parameters p1, p2, . . . , pn, one or more of them must be included in the API call, denoted as Or(p1, p2, . . . , pn).
As an example, when setting the information of a photo in the Flickr API, at least one of the parameters title or description must be provided, i.e. Or(title, description). Similarly, in the DocuSign eSignature API, at least one of the parameters from date, envelope ids or transaction ids must be submitted in the API call when retrieving the status of several envelopes, i.e. Or(from date, envelope ids, transaction ids).
Given a set of parameters p1, p2, . . . , pn, one, and only one of them must be included in the API call, denoted as OnlyOne(p1, p2, . . . , pn).
For example, in the Twilio SMS API, when retrieving the messages of a particular account, either the parameter MessagingServiceSid or the parameter From must be included, but not both at the same time, i.e. OnlyOne(MessagingServiceSid, From). Similarly, when deleting a picture in the PicPlz API, only one of the parameters id, longurl id or shorturl id must be submitted in the API call, i.e. OnlyOne(id, longurl id, shorturl id).
Given a set of parameters p1, p2, . . . , pn, either all of them are provided or none of them, denoted as AllOrNone(p1, p2, . . . , pn).
In the GitHub API, for example, the operation to obtain information about a user accepts two optional parameters, subject type and subject id, and they must be used together, i.e. AllOrNone(subject type, subject id). In the payments API Stripe, when creating a Stock Keeping Unit (a specific version of a product, used to manage the inventory of a store), if inventory.type is set to ‘finite’, then inventory.quantity must be present, and vice versa, i.e. AllOrNone(inventory.type=finite, inventory.quantity).
Given a set of parameters p1, p2, . . . , pn, zero or one can be present in the API call, denoted as ZeroOrOne(p1, p2, . . . , pn).
Interestingly, about one third of the occurrences of this dependency type were found in YouTube, where filtering by a video ID in the search operation restricts the allowed parameters it can be combined with to only 8, as shown in Figure 5. Since the operation accepts other 22 optional parameters, they are related to the video ID parameter by means of ZeroOrOne dependencies, e.g. ZeroOrOne(relatedToVideoId, topicId). Other examples of this dependency type include those where the use of a parameter restricts the allowed values of another parameter, like in the Google Maps API: when searching for places nearby, if radius is present, then rankby cannot be set to ‘distance’, i.e. ZeroOrOne(radius, rankby=distance).*
Given a set of parameters p1, p2, . . . , pn, they are related by means of arithmetic and/or relational constraints, e.g. p1 + p2 > p3.
As an example, in the GeoNames API, when retrieving information about cities, the north parameter must be greater than the south parameter for the API to return meaningful results, i.e. north > south (north, east, south and west are the coordinates of a bounding box conforming the search area). In the payments API Forte, when creating a merchant application, this can be owned by several businesses, in which case the sum of the percentages cannot be greater than 100, i.e. owner.percentage + owner2.percentage + owner3.percentage + owner4.percentage <= 100.
These dependencies involve two or more of the types of constraints previously presented. Based on our results, they are typically formed by a combination of Requires and OnlyOne dependencies.
For example, in the Tumblr API, when creating a new post, if the type parameter is set to ‘video’, then either embed or data must be specified, but not both, i.e. type=video → OnlyOne(embed, data). Figure 6 shows an extract of the documentation of the search operation in the Foursquare API. As illustrated, if intent is set to ‘browse’, then either ll and radius are present or sw and ne are present, i.e. intent=browse → OnlyOne((ll ∧ radius),(sw ∧ ne)).
In conclusion, we can categorize the dependencies between parameters of commercial APIs into each of the types we have previously explained.
IF videoDefinition THEN type=='video'; // Requires
Or(query, type); // Or
ZeroOrOne(radius, rankby=='distance'); // ZeroOrOne
AllOrNone(location, radius); // AllOrNone
OnlyOne(amount_off, percent_off); // OnlyOne
publishedAfter >= publishedBefore; // Relational
limit + offset <= 1000; // Arithmetic
IF intent=='browse' THEN OnlyOne(ll AND radius, sw AND ne); // Complex
To know more, visit the IDL repository and the sample IDL specifications.
IDL4OAS stands for "Interface Description Language for OpenAPI Specification," and it refers to a method of including dependencies in an OpenAPI Specification (OAS) document.
In traditional OpenAPI documents, dependencies between parameters were not directly supported. However, with the introduction of IDL4OAS, developers now have a way to express dependencies explicitly in the OAS document.
Below, we can see an example in which dependencies between query parameters are included.
/example/path:
get:
parameters:
- name: "p1"
in: "query"
required: false
type: "boolean"
- name: "p2"
in: "query"
required: false
type: "string"
x-dependencies:
- IF p2=='example string' THEN p1;
- Or(p1, p2)
responses:
default:
description: "Default"