Lee Lee - 3 months ago 11
Java Question

How to respond with warning on REST API version mismatch?

I have a Java project which uses Jersey + Grizzly HTTP Server to work as a REST server. The version strategy I used is to put header "server-api-version" in response and requires client to put header "accept-api-version" in request.

Based on this implementation, I want to provide two levels of version check:


  1. Reject the request if major version from request 'accept-api-version' is less than the major version from server's API version.

  2. Accept the request but warn the client "we are going to stop supporting the REST API version you uses in X months" if minor version from request 'accept-api-version' is less than the minor version from server's API version.



I achieved version check 1 by implementing javax.ws.rs.container.ContainerRequestFilter. However how to achieve version check 2 that response normally with an extra warning which is easy to be noticed by the client?

Answer

For check 2 it depends on how or where your client is used. It also depends on whether the client code is under your control

If your client is

  • a java library then add deprecated warning logs.
  • a js library running is browser then console warnings/errors may help, but mostly these go unnoticed.
  • Any other language - use their respective warning or deprecation system.
  • If it is an enterprise app with a UI then showing a error message on UI can get the right attention as well. For non-enterprise customer facing apps errors on UI for this won't help as regular users can't do anything mostly.

Another Hard way (this may not be acceptable in customer facing cases)

If the client source is in your control then you can start breaking the calls to older version api before you actually remove it from server. Let me explain what I mean here.

Now your client has a calling function getData(params: ParamType), also your client has a flat setter function as useDeprecated(value: Boolean)

Your getData(params: ParamType) in client checks if client can call the deprecated API, if client is not permitted then throw error.

interface Client {

  //Clients extend this interface

  void useDeprecated(boolean deprecated);

  default boolean isDeprecated(int serverVersion, int clientVersion) {
    // you can string for representing versions as well.
    // complicated logic of deprecation here
    return result;
  }

  boolean isAllowedToUseDeprecated();

  default Object getData() {
    if(isDeprecated(serverVersion, clientVersion)) {
      if(isAllowedToUseDeprecated()) {
        return getDataFromServer();
      } else {
        throw new DeprecatedException(expectedVersion, actualVersion, message);
      }
    } else {
      return getDataFromServer();
    }

  }

  Object getDataFromServer(); //Clients implement this
}

Say your current version is 2.1.1 (211 in int) and you want to deprecate a previous version 2.0.0 (200). Then clients using 2.0.0 will start getting DeprecatedException

How does this help?

When an API is deprecated the clients will start getting DeprecatedException and their calls will fail, but they can apply the useDeprecated(value: Boolean) to set the flag and continue using deprecated API. This brings the deprecation to clients notice, also provides them a short term emergency mitigation.

This hard method will work best for internal teams and only if the client source is in your control.

Make sure to communicate the deprecation well in advance through warnings and console messages, and by mailers etc.