API Versioning and Enable Authorization in Swagger UI .NET Core

API Versioning

API versioning is a technique by which we can create multiple versions of an API to coexist simultaneously. Using this technique, we can maintain backward compatibility with older clients while enabling new features and improvements for newer clients. As your application evolves, you may need to introduce breaking changes to your API. It helps to manage these changes in a way that doesn't impact existing users who depend on an older version of API's.

There are various ways to implement API versioning in .NET Core web API. The most common ways to implement API versioning are:

  • URL versioning: This is the most common approach to implementing API versioning. In this technique, the version is part of the endpoint itself.
    For Example: /api/v1/purchaseOrders
  • Query String Versioning: In this technique, the version is passed as a query parameter. This approach maintains the same URL path, with the version indicated by an additional query parameter.
    For Example: /api/purchaseOrders?api-version=1.0
  • Header Versioning: In this technique, the version is passed in a custom request header. The version is included in the request headers rather than the URL.
    For Example
    GET /api/purchaseOrders
  • Headers: x-api-version: 1.0Media Type Versioning (Accept Header Versioning): In this technique, the version is passed via content negotiation. The version is included in the Accept header with a custom media type. The client requests a specific version of the API by setting the Accept header to a custom MIME type.
    For Example
    GET /api/purchaseOrder
  • Headers: Accept: application/vnd.companyname.v1+json

How to implement API versioning?

How to implement API versioning using URL versioning and enable the token authorization option in Swagger step by step. For this, I am using .NET Core 8.

  1. Create a web API: Create a .NET Core web API and name it "APIVersioingPOC".
  2. Add required packages: Add the below-required packages for API versioning using the Nuget package manager.
    Install-Package Asp.Versioning.Mvc
    Install-Package Asp.Versioning.Mvc.ApiExplorer
  3. Create Entity Class: Create a folder with the name "Entity" and add an entity class named "PurchaseDetails"
    namespace APIVersioingPOC.Entity
    {
        public class PurchaseDetails
        {
            public string ProductName { get; set; }
            public int Rate { get; set; }
            public int Qty { get; set; }
            public int Amount { get; set; }
        }
    }
    
  4. Create Service: Create a folder with the name "Service" and add an interface with the name "IPurchaseOrderService" and a service class with the name "PurchaseOrderService" as below.
    using APIVersioingPOC.Entity;
    
    namespace APIVersioingPOC.Service
    {
        public interface IPurchaseOrderService
        {
            List<PurchaseDetails> GetPurchaseOrders();
        }
    }
    using APIVersioingPOC.Entity;
    
    namespace APIVersioingPOC.Service
    {
        public class PurchaseOrderService: IPurchaseOrderService
        {
            public List<PurchaseDetails> GetPurchaseOrders()
            {
                return new List<PurchaseDetails>
                {
                   new PurchaseDetails { ProductName="Laptop", Rate=80000, Qty=2, Amount=160000},
                   new PurchaseDetails { ProductName="Dekstop", Rate=40000, Qty=1, Amount=40000},
                   new PurchaseDetails { ProductName="Hard Disk", Rate=4000, Qty=10, Amount=40000},
                   new PurchaseDetails { ProductName="Pen Drive", Rate=600, Qty=10, Amount=6000},
                };
            }
        }
    }
    
  5. To resolve the dependency, register the service in Program.cs as below.
    // Add custom services
    builder.Services.AddScoped<IPurchaseOrderService, PurchaseOrderService>();
  6. Configure the versioning: In Program.cs file, add the below code.
    var builder = WebApplication.CreateBuilder(args);
    
    // Add API Explorer that provides information about the versions available
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddApiVersioning(options =>
    {
        options.DefaultApiVersion = new ApiVersion(1, 0); // Default API version (v1.0)
        options.AssumeDefaultVersionWhenUnspecified = true; // Assume the default version if not specified
        options.ReportApiVersions = true; // Report API versions in response headers
        options.ApiVersionReader = new UrlSegmentApiVersionReader(); // Use URL segment versioning (e.g., /api/v1/resource)
    
    }).AddApiExplorer(options =>
    {
        options.GroupNameFormat = "'v'VVV";
        options.SubstituteApiVersionInUrl = true;
    });
    
    builder.Services.AddSwaggerGen();
    
    var app = builder.Build();
    
    app.UseSwagger();
    app.UseSwaggerUI(options =>
    {
        var provider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>();
    
        foreach (var description in provider.ApiVersionDescriptions)
        {
            options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
        }
    });
    
  7. ConfigureSwaggerOptions: Create a folder with the name "OpenApi" and add the ConfigureSwaggerOptions class to configure swagger options.
    using Asp.Versioning.ApiExplorer;
    using Microsoft.Extensions.Options;
    using Microsoft.OpenApi.Models;
    using Swashbuckle.AspNetCore.SwaggerGen;
    
    namespace APIVersioingPOC.OpenApi
    {
        public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions>
        {
            private readonly IApiVersionDescriptionProvider _provider;
    
            public ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider)
            {
                _provider = provider;
            }
    
            public void Configure(SwaggerGenOptions options)
            {
                foreach (var description in _provider.ApiVersionDescriptions)
                {
                    options.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description));
                }
    
                // Add token authentication option to pass bearer token
                options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    In = ParameterLocation.Header,
                    Description = "Please enter token",
                    Name = "Authorization",
                    Type = SecuritySchemeType.Http,
                    BearerFormat = "JWT",
                    Scheme = "bearer"
                });
    
                // Add security scheme
                options.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference
                            {
                                Type = ReferenceType.SecurityScheme,
                                Id = "Bearer"
                            }
                        },
                        new string[] { }
                    }
                });
            }
    
            private static OpenApiInfo CreateInfoForApiVersion(ApiVersionDescription apiVersionDescription)
            {
                var info = new OpenApiInfo
                {
                    Title = "API Versioning",
                    Version = apiVersionDescription.ApiVersion.ToString(),
                    Description = "Swagger document for API Versioning.",
                };
    
                // Add deprecated API description
                if (apiVersionDescription.IsDeprecated)
                {
                    info.Description += " This API version has been deprecated.";
                }
    
                return info;
            }
        }
    }
  8. Add the code below to the Program.cs
    // Add custom services
    builder.Services.AddSingleton<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
  9. Create Controller: Create a controller with the name "PurchaseOrderController". For demo purposes, I have created two versions of the same API endpoint.
    using APIVersioingPOC.Service;
    using Asp.Versioning;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    
    namespace APIVersioingPOC.Controllers
    {
        [ApiController]
        [Route("api/v{version:apiVersion}/[controller]")]
        [ApiVersion("1.0")]
        [ApiVersion("2.0")]
        [Authorize]
        public class PurchaseOrderController : ControllerBase
        {
            private readonly IPurchaseOrderService _purchaseOrderService;
    
            public PurchaseOrderController(IPurchaseOrderService purchaseOrderService)
            {
                _purchaseOrderService = purchaseOrderService;
            }
    
            [HttpGet("GetPurchaseOrders")]
            [MapToApiVersion("1.0")]
            public IActionResult GetPurchaseOrders()
            {
                var users = _purchaseOrderService.GetPurchaseOrders();
                return Ok(users);
            }
    
            [HttpGet("GetPurchaseOrders")]
            [MapToApiVersion("2.0")]
            public IActionResult GetPurchaseOrdersV2()
            {
                var purchaseDetails = _purchaseOrderService.GetPurchaseOrders();
                return Ok(purchaseDetails);
            }
        }
    }

Let's run the project

For default version V1 you will get the swagger document as below.

Swagger document

For version V2, select the V2 option from the "Select a Definition" dropdown box, you will get the swagger document as below.

Select a Definition

You can pass the authentication token as below and click on the Authorize button.

Authorize button

In this way, we learned how to implement API versioning and enable authorization in Swagger UI.

Happy Learning!