The Round Trip Problem
Consider a new feature added to the Product API version 1.1.0. For example, version 1.1.0 may add a property guaranteeType
to the product
, createProduct
, and updateProduct
schemas.
Thus, the corresponding Product
, CreateProduct
and UpdateProduct
classes in the SDK for API version 1.1.0 will also define guaranteeType
.
Apiture Digital Banking APIs account for clients that are still using the older SDK for Product API 1.0.0, even though the
API is now running 1.1.0.
The TypeScript SDK for the Product API 1.0.0 includes TypeScript classes for 1.0.0 which do not include guaranteeType
.
If the client receives an product
response
or is passed a JSON representation of a product
instance, it will contain the new property:
{
"_profile": "https://api.apiture.com/schemas/products/product/v1.1.0/profile.json",
"guaranteeType": "fdic",
"..." : " ... other properties ..."
}
When the client (via the SDK) marshals that JSON into a Product
1.0.0 object,
the guaranteeType
property is dropped because the Product
class has has no such property.
The same would happen in other client programming languages, such as a class named Product
in a Java SDK.
If the client modifies the representation, then submits a PUT
request, the reverse object mapping occurs: the client
must convert the UpdateProduct
object to JSON. However, when using SDK 1.0.0,
the UpdateProduct
class and schema will not contain
guaranteeType
property. Without version information in the request, a PUT
update will change the persisted value of the guaranteeType
property for that product instance from "fdic"
to null
. (This is the defined behavior of
PUT
operations: PUT
is always a complete
replacement of the resource representation.) In the absence of any version information in the request,
if guaranteeType
is not present in the request, the server would not know the difference
between an older 1.0.0 client invoking the PUT
and a 1.1.0 client attempting to remove the value of guaranteeType
;
it would change the persistent value of guaranteeType
to null
.
This is the Round Trip Problem with GET
and PUT
.
This round trip problem only occurs for clients which map JSON to strongly typed objects (programming languages objects,
not JSON objects), manipulate the objects, and then map objects back to JSON. Round tripping is not an issue when
clients operate on JSON objects directly instead of marshaling the JSON into and out of native objects. In this case,
the guaranteeType
property remains in the client’s JSON object and is returned in the PUT
request body, even though the
client is unaware of it.
PATCH
operations do not have
this round trip problem, as values that are omitted from the PATCH
request body are
ignored and do not change the value on the server.
That is, the behavior of PATCH
works whether guaranteeType
was intentionally omitted in the request body, or because
the 1.0.0 SDK does not have a corresponding property.
To solve this when using the SDK or marshaling, the Apiture Digital Banking API SDK does the following two operations:
- The SDK injects the correct
_profile
in the representation. The_profile
URL includes to the resource version associated with API version for that SDK - i.e. it identifies theProduct
instance version as 1.0.0. If_profile
was omitted, the resource would is interpreted as version 1.1.0 of the Product schema, and thePUT
request would clear out the value ofguaranteeType
rather than leave it unmodified. The SDK constructs the new request body with an accurate_profile
value associated with the SDK version, and thus it does not round-trip the_profile
in the input. - The SDK for Product 1.0.0 passes the
Apiture-Version: 1.0.0
header in the request. - The SDK passes the API key request header; this value is also a surrogate for the
Apiture-Version
.
If a client does not use the SDK, it should account for the round trip problem in the same way: include the _profile
that reflects the expected version number of the resource, and pass the correct Apiture-Version
header corresponding
to the schema version associated with the resource and the client’s API key.