DEV Community

Navin Prasad
Navin Prasad

Posted on • Originally published at codelila.com on

Mastering API Versioning in ASP.NET Core WebAPI: 3 Proven Methods to implement it

Introduction

When I started learning Asp.net WebAPIs few year back for a client project, I learned how to implement webAPI and how that can be exposed. There was a chapter in the book which talked about API versioning. I read that but I thought it might be for letter stage of application, or large applications only.

But what I realized while doing actual API project development , The API versioning is as important as exposing the API for the client to consume. It gives your application the direction for the future enhancements without lots of breaking changes due to technical debts.

You might have came across third party APIs like “/api/v1/Products” , where “v1” is actually API version1. So, here we are going to learn all about API versioning in this blog with actual implemetation in a sample project.

Ways to implement API Versioning

We can implement Api vesioning basically in three ways :-

  • URL based API Versioning
  • Header based API Versioning
  • Query Parameter based API Versioning

Sample Project to implement API versioning.

  1. Open Visual studio 2022 , go to File->New->Project, select ASP.NET Core Web API Project template and click on Next.

  1. Give a name to the project , for instance “api-versioning-example” and click on Next.

  1. Select “.Net 7.0 (Standard Term Support)” as a Framework and Click on Create.

  1. After successful creation, you would able to see a window somewhat like the below one.

We will add another assembly project to keep the API projects Models seperate. It is always a good practice to divide the code based on their logic and functions.

Select the solution and then Right click then Add->New Project and select the DLL category and then select the Class Library(.Net Framework) Project template from the List.

Click on Next. You need to provide the name for the DLL project now. name it like “api-versioning-Models” and click on Create.

A new Project should be added to your solution now.

Delete the “Class1.cs” file and add the two folders names “Domains” and “DTOs” in it.

In Domains folder add a new Class name “Product” and update its code to have some sample properties as below.

using System;

namespace api_example_Models.Domains
{
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public string Category { get; set; }

        public double Price { get; set; }
    }
}

Enter fullscreen mode Exit fullscreen mode

In DTOs folder add a new class name “ProductDTO” and update it as below.

using System;

namespace api_example_Models.DTOs
{
    public class ProductDTO
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public string Category { get; set; }
        public double Price { get; set; }
    }
}

Enter fullscreen mode Exit fullscreen mode

The final structure should be as below.

Now add a new DLL project in solution and name it “api-example-DataContext” , once Done, delete the “Class1.cs” file from it.

Now Select the “api-example-DataContext” Project and add the “api-example-Models” project as reference in it.

Add a new Class “Products” in “api-example-DataContext” and update its code to return a sample product list. In actual application this would be returned from some storage(databases).

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml.Linq;
using api_example_Models;
using api_example_Models.Domains;

namespace api_example_DataContext
{
    public class Products
    {
        public List<Product> GetProducts()
        {
            // Sample Product List
            var products = new List<Product>();
            products.Add(new Product()
            {
                Id = 1,
                Name = "Product 1",
                Description = "Product 1 descrition",
                Category = "Fasion",
                Price = 250
            }
            );
            products.Add(new Product()
            {
                Id = 1,
                Name = "Product 2",
                Description = "Product 2 descrition",
                Category = "Electronics",
                Price = 150
            });

            return new List<Product>();
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

Now select the api project and add other two projects as reference.

Now select the “Controllers” and add a new API controller , name it “ProductController”. Now we will be creating a GET api which should returns all products, Update the ProductController with below code.

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using api_example_Models.DTOs;
using api_example_DataContext;

namespace api_versioning_example.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ProductController : ControllerBase
    {
        [HttpGet]
        public ActionResult<List<ProductDTO>> GetAllProducts()
        {
            var productDTOs = new List<ProductDTO>();
            var products = new Products().GetProducts(); 
            if(products != null)
            {
                foreach (var product in products)
                {
                    productDTOs.Add(new ProductDTO()
                    {
                        Id = product.Id,
                        Name = product.Name,
                        Description = product.Description,
                        Price = product.Price,
                        Category = product.Category,
                    });
                }
            }
            return productDTOs;
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

Out basic API is ready now. Lets test it once on browser.

URL based API Versioning

Now Lets start implementing the URL based API Versioning .

Right click on “api-versioning-example” project and then click on “manage Nuget package”. Search for “Microsoft.AspNetCore.Mvc.Versioning” package and install in your project.

Once installed, you should see message as below.

Now Open Program.cs file and enable api versioning by adding below line of code just after the “builder.Services.AddControllers();” line

builder.Services.AddApiVersioning();
Enter fullscreen mode Exit fullscreen mode

Now go we have to build two version of DTOs as the new DTO would going to return the resired changes in newer API version.

Lets go to “api-example-DataModels” Project and create new folder under the DTOs folder, I have named it “V2”, next add a new class file named “ProductDTOV2”. Update it code with below code given. Let us suppose we need to rename few fields in new api version

using System;

namespace api_example_Models.DTOs.V2
{
    public class ProductDTOV2
    {
        public int Id { get; set; }
        public string ProductName { get; set; }
        public string LongDescription { get; set; }
        public string Category { get; set; }
        public double Price { get; set; }
    }
}

Enter fullscreen mode Exit fullscreen mode

In above code I have update the Name to ProductName and Description to LongDescription.

Next go to ProductController in Controllers folder and add a new HTTPGET method to return add Product with updated names. Here is the code.

        [HttpGet]
        public ActionResult<List<ProductDTOV2>> GetAllProductsV2()
        {
            var productDTOs = new List<ProductDTOV2>();
            var products = new Products().GetProducts();
            if (products != null)
            {
                foreach (var product in products)
                {
                    productDTOs.Add(new ProductDTOV2()
                    {
                        Id = product.Id,
                        ProductName = product.Name,
                        LongDescription = product.Description,
                        Price = product.Price,
                        Category = product.Category,
                    });
                }
            }
            return productDTOs;
        }
Enter fullscreen mode Exit fullscreen mode

Now, we want to serve this new GET method when someone type “/api/v2/Product” and return the previous Get method (GetAllProducts) response when someone type “/api/v1/Product”. Let us update the ProductController to achieve this.

In Product Controller just above the class Name add below line.

    [Route("api/v{version:apiVersion}/[controller]")]
    [ApiController]
    [ApiVersion("1.0")]
    [ApiVersion("2.0")]
Enter fullscreen mode Exit fullscreen mode

Add below line just above the [HttpGET] for the “GetAllProducts” method.

[MapToApiVersion("1.0")]
Enter fullscreen mode Exit fullscreen mode

Add below line above the [HttpGet] for the “GetAllProductsV2” method.

[MapToApiVersion("2.0")]
Enter fullscreen mode Exit fullscreen mode

Here is how the final ProductController looks like.

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using api_example_Models.DTOs;
using api_example_DataContext;
using api_example_Models.DTOs.V2;

namespace api_versioning_example.Controllers
{
    [Route("api/v{version:apiVersion}/[controller]")]
    [ApiController]
    [ApiVersion("1.0")]
    [ApiVersion("2.0")]
    public class ProductController : ControllerBase
    {
        [MapToApiVersion("1.0")]
        [HttpGet]
        public ActionResult<List<ProductDTO>> GetAllProducts()
        {
            var productDTOs = new List<ProductDTO>();
            var products = new Products().GetProducts(); 
            if(products != null)
            {
                foreach (var product in products)
                {
                    productDTOs.Add(new ProductDTO()
                    {
                        Id = product.Id,
                        Name = product.Name,
                        Description = product.Description,
                        Price = product.Price,
                        Category = product.Category,
                    });
                }
            }
            return productDTOs;
        }

        [MapToApiVersion("2.0")]
        [HttpGet]
        public ActionResult<List<ProductDTOV2>> GetAllProductsV2()
        {
            var productDTOs = new List<ProductDTOV2>();
            var products = new Products().GetProducts();
            if (products != null)
            {
                foreach (var product in products)
                {
                    productDTOs.Add(new ProductDTOV2()
                    {
                        Id = product.Id,
                        ProductName = product.Name,
                        LongDescription = product.Description,
                        Price = product.Price,
                        Category = product.Category,
                    });
                }
            }
            return productDTOs;
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

Now run the application you will see swagger is giving some error, which we will fix later.

Now go to the browser and the the Product url with V1(http://localhost:5062/api/v1/Product) as below. you should have response as below.

Now type the new V2 Api for Product “http://localhost:5062/api/v2/Product”

If you notice the two outputs, you would fine the V1 is returning the same response but V2 is returning the updated response. but if you type the old url(http://localhost:5062/api/Product) without version which was published then you may get error.

This is how you can add support for api versioning in you asp.net WebAPI project.

We have seen how we can add support for API versioning in route which is more popular and obvious way but there are other ways as well which can be also be used.

Header based API Versioning

To implement header based versioning we need to make following changes in application.

Replace the “builder.Services.AddApiVersioning()” line in program.cs file with below code.

builder.Services.AddApiVersioning(options =>
{
    options.ApiVersionReader = new HeaderApiVersionReader("api-version");
    options.ReportApiVersions = true;
});
Enter fullscreen mode Exit fullscreen mode

Replace the “[Route(“api/v{version:apiVersion}/[controller]”)]” in ProductController file with “[Route(“api/[controller]”)]”.

Now run the application, you need to use some rest client like postman to pass the header information.

Api Versioning

You can try changing the “api-version” header to 2.0, you should be getting the 2.0 products output.

Query Parameter based API Versioning

Now let us take a look on how to implement Query Parameter based API Versioning.

Let us go to program.cs file and update the below line of code.

builder.Services.AddApiVersioning(options =>
{
    options.ApiVersionReader = new HeaderApiVersionReader("api-version");
    options.ReportApiVersions = true;
});
Enter fullscreen mode Exit fullscreen mode

Change the “HeaderApiVersionReader” to “QueryStringApiVersionReader”, the updated code should be looks like below.

builder.Services.AddApiVersioning(options =>
{
    options.ApiVersionReader = new QueryStringApiVersionReader("api-version");
    options.ReportApiVersions = true;
});
Enter fullscreen mode Exit fullscreen mode

browse the url with api-version as parameter. You should have similar output as below.

This is how you can implement the API versioning in asp.net core API.

Summary

In this comprehensive guide, we dive deep into the world of API versioning within ASP.NET Core WebAPI. You’ll discover three battle-tested methods for implementing API versioning effectively, ensuring seamless compatibility across your applications. Whether you’re an experienced developer or just starting your journey, this post provides invaluable insights to help you manage and optimize your APIs with confidence. Explore the latest techniques and best practices to stay ahead in the ever-evolving landscape of ASP.NET Core WebAPI.

The post Mastering API Versioning in ASP.NET Core WebAPI: 3 Proven Methods to implement it appeared first on CodeLila.

Top comments (0)