Versioning RESTful web APIs

You should always version the RESTful web APIs. Versioning of APIs helps you to roll out new releases without affecting the existing customer base as you can continue to offer the old API versions for a certain period of time. Later, a customer can move on to a new version if he/she prefers to do so.

You can version RESTful web APIs in many ways. Three popular techniques for versioning RESTful web APIs are given in this section.

Including the version in resource URI – the URI versioning

In the URI versioning approach, the version is appended along with the URI. An example is as follows:

GET /api/v1/departments HTTP/1.1

A sample RESTful web API implementation that takes a version identifier as part of the resource URI will look like the following:

//Imports are removed for brevity
@Path("v1/departments")
public class DepartmentResourceV1{
    @GET
    @Produces("application/json")
    public List<Department> findDepartmentsInRange(
        @QueryParam("offset") @DefaultValue("1") Integer offset, 
        @QueryParam("limit") @DefaultValue("20") Integer limit) {

        return findAllDepartmentEntities(offset, limit);
    }
    //Other methods are removed for brevity
}

With this approach, if you want to upgrade the version for a resource, you will have to build a new resource class that takes the latest API version as the path parameter. To avoid code duplication, you can subclass the existing resource class and override only the modified resource methods, as shown here:

//Imports are removed for brevity
@Path("v2/departments")
public class DepartmentResourceV2 extends DepartmentResourceV1{
    @GET
    @Produces("application/json")
    @Override
    public List<Department> findDepartmentsInRange(
        @QueryParam("offset") @DefaultValue("1") Integer offset, 
        @QueryParam("limit") @DefaultValue("20") Integer limit) {

        return findAllDepartmentEntities(offset, limit);
    }
    //Other methods are removed for brevity
}

Many big social sites (Twitter, Facebook, and so on) use the URI versioning approach for versioning the APIs.

Conceptually, this is the simplest solution for API versioning. However, there are certain drawbacks associated with this approach:

  • As the resource URI changes with each release, client applications may have to change all the existing URI references in order to migrate to a new release. The impact may be minimal if all the resource URIs are localized and stored in a configuration file.
  • This approach may disrupt the concept of HATEOAS.
  • Since the URI path for an API gets updated for each change in the REST resource class, you may experience a large URI footprint over a period of time. This may result in a code maintenance issue for both the client and the server.
  • If the URI is versioned, the cache may contain multiple copies of each resource, one for every version of the API.

Including the version in a custom HTTP request header – HTTP header versioning

The HTTP header versioning approach uses a custom header field to hold the API version. While requesting for a resource, the client sets the version in the header along with other information (if any). The server can be built to use the version information sent by the client in order to identify the correct version of the resource.

The following example uses a custom header to specify the API version that the client is looking for:

GET /api/departments HTTP/1.1
api-version: 1.0

The API implementation can read the request header via @javax.ws.rs.HeaderParam.

//Other imports are omitted for brevity
import javax.ws.rs.HeaderParam;
@GET
@Produces("application/json")
public List<Department> findAllDepartments(
    @HeaderParam("api-version") String version){
    //Method body is omitted for brevity
}

Including the version in a HTTP Accept header – the media type versioning

The media type versioning approach adds the version information to the media content type. You can do this by introducing custom vendor media types that hold the version information along with the media type details. The version information in the Accept header takes the following form:

Accept: application/vnd.{app_name}.{version}+{response_type}

The vnd part that you see in the Accept header is based on RFC 6838. The vnd keyword indicates the custom vendor-specific media types. More details are available at https://tools.ietf.org/html/rfc6838.

When you use this approach for versioning APIs, the client has to specify the version in the HTTP Accept header, as shown in the following example:

GET /api/v1/departments
Accept: application/vnd.packtpubapi.v1+json

A sample RESTful web API implementation that uses the media type versioning approach is shown here for your reference:

@Path("departments")
@Produces({"application/json", "application/vnd.packtpub.v1+json"})
@Consumes({"application/json", "application/vnd.packtpub.v1+json"})
public class DepartmentResource{
    //The following method is a modified implementation
    //to read the list of employees, so the version number has been
    //incremented
    @GET
    @Produces({"application/vnd.packtpub.v2+json"})
    public List<Department> findDepartmentsInRangeV2(
        @QueryParam("offset") @DefaultValue("1") Integer offset, 
        @QueryParam("limit") @DefaultValue("20") Integer limit) {
        return findDepartmentEntitiesWithDetails(offset, limit);
    }

    @GET
    public List<Department> findDepartmentsInRangeV1( 
        @QueryParam("offset") @DefaultValue("1") Integer offset, 
        @QueryParam("limit") @DefaultValue("20") Integer limit){
        return findDepartmentEntities(offset, limit);
    }

}

The preceding implementation has two methods annotated with different media type versions. At runtime, the Jersey framework automatically picks up a method to serve a request on the basis of the media type version information present in the Accept header parameter.

Many new API vendors have started supporting this approach. For example, GitHub uses the Accept header approach for versioning its APIs.

Note

Although this approach works for many of the common use cases, there are challenges associated with the caching of results returned by these kinds of APIs. Many user agents do not consider the Accept header while reading the cached contents. For instance, when using the same URI for multiple versions of APIs, there are chances of caching proxies to return wrong representations from the cache. Although you can configure caching proxies to consider the Accept headers along with the URI, doing so may add complexity to your network configuration.

Hybrid approach for versioning APIs

Some API vendors choose a combination of URI versioning and HTTP header versioning approaches, where the major version information is kept along with the URI and the minor version information for subresources is stored in the custom header field. In this case, the major version information indicates the structural stability of the API as a whole, while the minor versions indicate smaller changes at the implementation level.

To summarize the discussion, there is no wrong and right approach for versioning APIs. You can choose one of the options that we have discussed here for your application as long as it meets your application's needs.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.91.44