Evolution space

This page list all the manner in which a RESTful API can evolve. It includes interface and behavioral changes.

This page list all the manner in which a RESTful API can evolve. It includes interface and behavioral changes.

Behavioral changes relate to how operations should be composed to execute business processes, access rights and resource state related pre-conditions.

Two scientific contributions detail how RESTful APIs evolve. These are reported here. In last section I add elements I consider to be missing from the literature.

This enumeration aims at listing all possible HTTP API evolutions. It is not limited to breaking changes.

First 10 changes are described as compile-time breaking changes. The last 4 are listed as run-time breaking changes.

Examples describing APIs follow the OpenApi specification in a lighter version to omit useless details.

Grey block representing quotes contains the text describing the change from the paper.

1 - Add or remove parameter

The below example shows an example of adding and removing a parameter.

Missing point: parameter is optional or required ? optional parameters are not breaking changes.

/greeting:
  get:
    parameters:
      - name: string
      - font: string

2 - Change type of parameter

Description from authors:

This kind of change only appears in Amazon MWS API evolution, such as merging several independent simple parameters into one complex composite parameter. For changes in this category, developers can easily migrate the client application in most cases. Usually, the new parameter can be synthesized by old parameters directly, and this process can be done automatically if developers know the synthesis rule from old parameters to new parameters.

// request body, not response 
// because parameters are considered here
{
  id: 1234,
  title: "Buy groceries",
  due_date: "2020-01-01",
  due_time: "8:00"
}

3 - Change type of return value

This pattern is similar to Change Type of Parameter and appears in Google API and Amazon API.

See example above, this time the JSON would be the response body and not the request body.

4 - Delete method

For most cases, methods are deleted because their functionality is subsumed by other methods. However, there are cases where a method is removed and no replacement can be found. In the latter case, the migration of clients relying on the method becomes a big problem. This is also quite different from local API migration, as clients of local API could run with a copy of the old library and call the deleted method in the old library.

5 - Rename method & 6 - Rename parameter

These two patterns are quite common in all APIs we surveyed. The main reason is to give self-explanatory names to methods and parameters. The migration for such changes is relatively easy comparing with other change patterns, and it can be fully automated with existing tools.

/projects/{id}?token={token}:
  get:
    parameters:
      - id: string
      - token: bearer_token

Parameters can be path parameters, query, headers or body parameters. No kind of parameter is excluded.

7 - Change format of parameter & 8 - Change format of return value

These two patterns mean the type of a parameter or a return value does not change, but the format of them changes. For example, in Google Calendar API, a method accepts a string type parameter that needs to be encoded using URLEncode in the version 2.0. But in version 3.0, developers need only pass a string type parameter without encoding. These patterns are discovered in four APIs except Twitter API. In most cases, the goal of the changes is to facilitate the development of new client applications.

createdBefore:
  schema:
    type: string
    format: date

9 - Change XML tag

This pattern only occurs in Google Calendar API, where the value name used in the new JSON format differ from the original tags used in the XML messages. This pattern can be solved automatically.

<?xml version="1.0" encoding="UTF-8" ?>
<project id="1234">
    <name>The 0 project</name>
</project>

10 - Combine methods

This pattern means several methods are combined into one method. We find this pattern in the evolution of Amazon API. Amazon MWS API is a data-intensive API, there are a large amount of data need to be exchanged. In the old version of this API, developers need to interact with the server more than one times to get required data. But after evolution, developers can acquire the data from only one invocation. This decreases the latency in communication. However, the migration for this change can hardly be automated, since we need to find out possible consecutive invocations to the involved methods and group them into one.

/projects/{project_id}:
  get:
    responseBody:
      - project_id: string
      - title: string
      - collaborators: userId[]
/analytics/{project_id}:
  get:
    responseBody:
      - project_id: string
      - creation_date: datetime
      - updates_count: number
      - last_update: datetime

11 - Split method

We find this pattern in Amazon API evolution. It does not mean that one method split into several methods, but that one method was replaced by two different methods in different conditions. In Amazon API, the functionality of a method named 'PutInboundShipment' is to create or update an item about shipment in the database. If the item already exists, its record is updated; otherwise is created. In the new version, if the user wants to create an item, they should use the method named 'CreateInboundShipment', otherwise they should use 'UpdateInboundShipment' for updating the record of that item.

The second case of the above example, for change n°8 illustrate this if we go from v2 to v1.

12 - Expose data

Could not understand the point

This pattern appears in Google Calendar API, which provides data service. Data can be placed in a deep hierarchy, or can be organized in a flatter hierarchy. For ex- ample, in version 2.0 of Google Calendar API the resource path of ‘originalEventId’ and ‘originalStartTime’ are represented in the Atom format as follows:

<atom:entry>
    <gd:originalEvent href="originalEventAtomId" id="originalEventId">
      <gd:when startTime="originalStartTime"/>
    </gd:originalEvent>
</atom:entry>

And in version 3.0 the resource path of these two methods represented as JSON format as follows:

{
  "recurringEventId": originalEventId,
  "originalStartTime": originalStartTime
}

13 - Unsupport request method

Not relevant to me. More information below.

HTTP request methods include get, post, put and delete. In Sina Weibo API and Twitter API evolution, some methods in these APIs change from supporting two request methods in old version to supporting only one request method.If client applications just use a request mode that is supported by new version of an API, we need to do nothing. But if we use other unsupported request methods, we should modify the request method in our applications.

Removing a request method (GET, POST, PUT, DELETE, etc.) implies removing a method (also named operation) from the API, because one operation is identified by the couple <verb; url>. Consequently, from my understanding of this change, it is the same as 4.

14 - Change default value of parameter

This pattern appears in Sina Weibo API evolution. In an HTTP request, parameters may have default values. Most of these parameters are about quantity, such as how many tweets can be displayed in one page. When the default values of such parameters change, we classify these changes in this category. The reason is that changes of default values may break the (potentially well-designed) layouts of a page, and such problems can only be captured at runtime.

Example:

parameters:
  - name: limit
    description: Page size of this collection
    schema:
      type: integer
      minimum: 1
      maximum: 40
      default: 20 # default page size

15 - Change upper bound of parameter

This pattern only appears in Sina Weibo API evolution. Some particular parameters have upper bounds, e.g., a parameter may indicate how many tweets should be returned in one method invocation, and the upper bound is set for the maximum number of tweets that can be returned. When an upper bound becomes smaller, we classify this change as this pattern. Note that when an upper bound becomes larger, it is not a breaking change. Whether this pattern will cause problem in migration depends on the argument passed to the corresponding methods. If the argument is always smaller than the new upper bounds, nothing needs to be done for the migration. Otherwise, several invocations may be needed to retrieve all the needed data.

tags:
  type: array
  items:
    type: string
  maxItems: 40

16 - Restrict access to API

This pattern appears in Sina Weibo API evolution. Some methods are sensitive to information such as a method acquiring the private message of a person. So in new version of Sina Weibo API, the API providers improve the access authority of these methods. If developers want to access these methods, they should apply the authorization from API providers.

In this case, automatically migrating client applications is almost impossible, but a good migrating tool could provide useful help for developers.

/projects/{project_id}:
  get:
    responseBody:
      - project_id: string
      - title: string
      - collaborators: userId[]

Changes from "A Case Study of Web API Evolution"

Examples describing APIs follow the OpenApi specification in a lighter version to omit useless details.

17 - Move API elements

We found 114 occurrences of element moves, where API elements are moved under new hierarchy or renamed. For example, Stripe API moved two objects under a new API element as found in the following change log from version 2013-08-13:

“Remove fee and fee details properties on charge and transfer objects. Instead, fee information is now stored on the corresponding balance transaction. ”

This point is relatively similar to "10 - Combine methods". However, the data is moved to a third, already existing, resource instead of one of the two already existing mentioned.

/projects/{project_id}:
  get:
    responseBody:
      - project_id: string
      - title: string
      - creation_date: datetime
      - tasks_completed_count: number
/tasks?project_id={project_id}
  get:
    parameters:
      - project_id: string
    responseBody:
      - last_task_creation_date: datetime
      - points_count: number
      - tasks: 
          type: Task[]

18 - Rename API elements

We found that 31 API elements were renamed for consistency. The following example from the Facebook API shows a rename 3:

“Facebook will be renaming the adgroup status value AD- GROUP PAUSED TO PAUSED to be consistent with the rest of the object’s APIs. ”

/projects/{project_id}:
  get:
    responseBody:
      - project_id: string
      - title: string
      - collaborators: userId[]

19 - Behavior change

We have found 247 examples where Web APIs changed the resultant data while keeping the API interfaces intact. These are commonly triggered by bug fixes. For example, Wordpress REST API 1.1 changed as follows 4:

“Correct password-protected post handling. Password-protected posts could previously be exposed to all users, however could also have broken behavior with excerpts. Password-protected posts are now hidden to unauthenticated users.”

Another example that demonstrates a behavior change can be found from the 2013-10-29 version of Stripe API 5:

“When we apply a $Y coupon to a $X dollar invoice, we are no longer applying the remainder of the coupon to the account balance if Y > X. Applications of coupons to $0 invoices will no longer count as a redemption of the coupon.”

20 - Post condition change

In the studied Web APIs we found examples where the immediate result of an API call remained unchanged but new post conditions are imposed requiring additional work for the API users. The following change on Facebook platform API illustrates this:

“Starting May 13th, 2014, developers that accept payments will be required to subscribe to and honor Realtime Updates to ensure order fulfillment and appropriate handling of disputes from all payers. If you do not subscribe to and honor these updates, Facebook reserves the right, under our Developer Payment Terms to withhold payouts and/or stop your app from accepting payments. ”

21 - HTTP header change

Web APIs also change the custom HTTP headers that are used as meta data. For example, the following shows a change when the WordPress Web API introduced two new headers to describe the pagination status of an API call:

“Send X-WP-Total and X-WP-TotalPages headers for information on post/pagination counts”

Similarly, the Github API changed their custom headers about pagination in the following example:

“No longer using the X-Next or X-Last headers. Pagination info is returned in the Link header instead.”

To me, this may be considered the same as "3 - Change type of return value".

22 - Error condition change

Web APIs change the error conditions that may require the users to adapt their integration. For example, in Salesforce API Version 29 the error codes were changed :

“...different ExceptionCode and StatusCode values are now re- turned for some error conditions when saving user records. We strongly recommend that you test your code and modify it accordingly if your clients rely on specific ExceptionCode and StatusCode values being returned... ”

➜ more information here page 309

Additions with Fabernovel

From my experience as a software developer I noticed some kinds of changes that are not listed above. These are listed below.

23 - Change request method

Request methods change to denote a change of the idempotent property of the operation. Inverting POST and PUT is the most likely change because their difference is not evident for most developers.

/projects/{project_id}/archive:
  put:
    description: Archive the project
    parameters:
      - archive: boolean
    responseCode: 204

24 - Pre condition change

Preconditions are the conditions determining if the operation targeted by the request can be executed.

To resolve these conditions, the user context and access rights, along with the state of the resource, and more globally the system, are taken into account. From these contextual information business rules are applied to determine if the operation can be executed.

Such a change does not lead a design-time break or run-time break but creates a trap for the user who could delete projects and cannot anymore.

Operation: delete a project

Precondition: the user is a collaborator of the project

25 - The order in which a set of operations must be played to achieve a business process changed

Considering the business process placing an order, the order in which operations must be played to achieve this may change while operations interface do or do not evolve. For example:

  1. Validate cart

  2. Input delivery information

  3. Input payment information

  4. Select delivery option

  5. Confirm order

26 - The set of operations to execute to achieve a business process changed

Considering the same business process as previous change, placing an order, the set of operations to achieve this may change while operations interface do or do not evolve. For example:

  1. Validate cart

  2. Input delivery information

  3. Input payment information

  4. Select delivery option

  5. Confirm order

27 - Add method

THIS IS NOT A BREAKING CHANGE

The title is self-explanatory, no example provided.

28 - Change input parameter constraints

The business constraints applied on a model changed. It does not cause any change of the API interface but requests which where accepted before will be refused after the change takes place.

In the OpenApi specification, JSON Schema is used to describe the constraints to apply on the data models.

/projects:
  post:
    requestBody:
      - title: 
          - type : string
          - minLength: 4
          - maxLength: 140
    responseStatus: 201
    responseBody: empty

Last updated