- Option 1: Pagination
- Options 2 and 3: Wish List, Wish Template
- Options 4 and 5: Conditional Request, Request Bundle
- Decision Drivers and Tradeoffs
Options 2 and 3: Wish List, Wish Template
API providers often serve diverse clients. It can be hard to design API operations that provide precisely the data required by all these clients. Some of them might use only a subset of the data offered by the operations; other clients might expect more data. The information need might not be predictable before runtime. A possible way to solve this problem is to let the client inform the provider at runtime about its data fetching preferences. A simple option to do this is to let the client send a list of its desires.
Pattern: WISH LIST | |
Problem | How can an API client inform the API provider at runtime about the data it is interested in? |
Solution | As an API client, provide a WISH LIST in the request that enumerates all desired data elements of the requested resource. As an API provider, deliver only those data elements in the response message that are enumerated in the Wish List. |
In an example case, a request for customer data might return all of the available attributes:
curl -X GET http://localhost:8080/customers/gktlipwhjr
For customer ID gktlipwhjr, this would return the following:
{
"customerId": "gktlipwhjr",
"firstname": "Max",
"lastname": "Mustermann",
"birthday": "1989-12-31T23:00:00.000+0000",
"streetAddress": "Oberseestrasse 10",
"postalCode": "8640",
"city": "Rapperswil",
"email": "admin@example.com",
"phoneNumber": "055 222 4111",
"moveHistory": [ ],
"customerInteractionLog": {
"contactHistory": [ ],
"classification": {
"priority": "gold"
}
}
}
To improve this design, a WISH LIST in the query string can restrict the result to the fields included in the wish. In the example, an API client might be interested in only the customerId, birthday, and postalCode:
curl -X GET http://localhost:8080/customers/gktlipwhjr?fields=customerId,birthday,postalCode
The returned response now contains only the requested fields:
{
"customerId": "gktlipwhjr",
"birthday": "1989-12-31T23:00:00.000+0000",
"postalCode": "8640"
}
This response is much smaller; only the information required by the client is transmitted.
A simple list of client wishes is not always easy to specify, for example, if a client requests only specific fractions of deeply nested or repetitive parameter structures. An alternative solution that works better for complex parameters is to let the client send a template expressing the wishes as examples in its request:
Pattern: WISH TEMPLATE | |
Problem | How can an API client inform the API provider about nested data that it is interested in? How can such preferences be expressed flexibly and dynamically? |
Solution | Add one or more additional parameters to the request message that mirror the parameters in the corresponding response message. Make these parameters optional, or use Boolean as their types so that their values indicate whether a parameter should be included. |
The following service contract introduces a WISH TEMPLATE, indicated by a <
:
data type PersonalData P // placeholder
data type Address P // placeholder
data type CustomerEntity <> {PersonalData?, Address?}
endpoint type CustomerInformationHolderService
exposes
operation getCustomerAttributes
expecting payload {
"customerId":ID, // the customer ID
<>"mirrorObject":CustomerEntity
// has same structure as desired result set
}
delivering payload CustomerEntity
In this example of an API, the client can send a CustomerEntity template that may include PersonalData and Address attributes (this is defined in the data type definition CustomerEntity). The provider can then check which attributes were sent and respond with a filled-out CustomerEntity instance.
The API contract in the example is specified in Microservice Domain-Specific Language (MDSL). This DSL allows API designers to specify (micro-)service contracts, their data representations and API endpoints. In support of API sketching, MDSL abstracts from technology-specific interface description languages such as OpenAPI/Swagger, GraphQL, and Protocol Buffers, but provides tool-supported bindings to them.