Web API versioning using Accept Header

by Sachin Singh


Posted on Tuesday, 19 May 2020

Tags: Web api versioning using accept header

This is the continuation of the Web API Versioning Series, in the previous four articles we have learned
  • why Versioning is required Read here and
  • Versioning using URI Read here
  • Versioning using Query String Read Here
  • Versioning using Custom Header Read Here

In this article we will learn how to implement versioning using Accept Header. We already have two API Controllers :-
  1. SilverEmployeeController, which returns Employee's Name ,Id and Salary.
  2. GoldEmployeeController , which returns Employee's First Name ,Last Name, Id and Salary.

Our Clients know nothing about the real implementation, they just know that they are consuming EmployeeService and there exist two versions of the service. To consume the service they have to pass the version number too along with the URL, it's our duty to tell our client how they can pass the version number. There are many ways with which version number can be passed like:-
  1. In the Form of routed data .(versioning using URI)
  2. In the form of query string (versioning using query string)
  3. In the form of Custom Header (versioning using custom header)
  4. In the form of Accept Header (versioning using accept header)
  5. In the form of Custom Media Types (versioning using Custom media types).

In the previous article, we had created a custom header for versioning, actually creating a custom header just for versioning is not that required as we can achieve the same with the standard Accept header as well. The Accept header can carry any additional data along with the request to the server, so we can utilize this feature and could add the version parameter. we can send the version of the service we want using the version parameter as shown below.

Web API versioning using Accept Header simply means the clients are going to specify the version number as a parameter with the help of Accept Header.

Versioning using Accept Header
Passing Version Number as parameter with Accept Header

So, our work is to tell web API to select the appropriate controller based on the version number specified by the client in the Accept Header as an additional Parameter.
  • If the client passes, Accept: application/json;version=1, then we have to tell web API to select SilverEmployeeService Controller.
  • If the client passes, Accept: application/json;version=2, then we have to tell web API to select GoldEmployeeService Controller.

From the previous article, we know how web API selects the controller based on the information from URL, we also know how to override the default behavior of controller selection.

In the previous article, we have implemented a CustomControllerSelector. At the moment, this CustomControllerSelector is retrieving the version number from the custom Accept Header.

To implement versioning using an Accept Header, all we have to do is change the logic slightly into the CustomControllerSelector class to read the version number from the Accept header instead of from the Custom version header.


   namespace MyFirstAPIProject.Custom
     {
    
        public class CustomControllerSelector : DefaultHttpControllerSelector
        {
            private HttpConfiguration _config;
            public CustomControllerSelector(HttpConfiguration config)
                : base(config)
            {
                _config = config;
            }

            public override HttpControllerDescriptor
                SelectController(HttpRequestMessage request)
            {
                // Get all the available Web API controllers
                var controllers = GetControllerMapping();
                // Get the controller name and parameter values from the request URI
                var routeData = request.GetRouteData();

                // Get the controller name from route data.
                // The name of the controller in our case is "EmployeeService"
                var controllerName = routeData.Values["controller"].ToString();

                // Default version number to 1
                string versionNumber = "1";
                 //Get the version number from the Accept header

                                // Users can include multiple Accept headers in the request
                                // Check if any of the Accept headers has a parameter with name version
                                var acceptHeader = request.Headers.Accept.Where(a => a.Parameters
                                                    .Count(p => p.Name.ToLower() == "version") > 0);

                                // If there is atleast one header with a "version" parameter
                                if (acceptHeader.Any())
                                {
                                    // Get the version parameter value from the Accept header
                                    versionNumber = acceptHeader.First().Parameters
                                                    .First(p => p.Name.ToLower() == "version").Value;
                                }
                

               
                if (versionNumber == "1")
                {
                    // if version number is 1, then prepend "Silver" to the controller name.
                    // So at this point the, controller name will become SilverEmployeeService
                    controllerName = "Silver"+controllerName;
                }
                else
                {
                    // if the version number is 2, then prepend "Gold" to the controller name.
                    // So at this point the, controller name will GoldEmployeeService
                    controllerName ="Gold"+controllerName;
                }

                HttpControllerDescriptor controllerDescriptor;
                if (controllers.TryGetValue(controllerName, out controllerDescriptor))
                {
                    return controllerDescriptor;
                }

                return null;
            }
        }
    
     }

The implementation is simple and straight forward, we are getting version number from Accept header and accordingly changing the controller Name.

Now , run the application and fire two get request on the behalf of two different client like below and test the results.

Versioning with Accept Header
Response for version=2

As you can see ,for the Accept:application/json;version=2, we are getting list of GoldEmployee back ,it means our custom controller selector is successfully working and versioning is successful.