কেন Versioning?
Breaking change করতে হলে পুরনো client ভাঙবে না — নতুন version-এ deploy। সবাই ধীরে ধীরে migrate করে।
Setup
dotnet add package Asp.Versioning.Mvc dotnet add package Asp.Versioning.Mvc.ApiExplorer
Program.cs
builder.Services.AddApiVersioning(opt => {
opt.DefaultApiVersion = new ApiVersion(1, 0);
opt.AssumeDefaultVersionWhenUnspecified = true;
opt.ReportApiVersions = true; // response header
opt.ApiVersionReader = ApiVersionReader.Combine(
new UrlSegmentApiVersionReader(), // /v1/
new QueryStringApiVersionReader("api-version"),
new HeaderApiVersionReader("X-Api-Version"),
new MediaTypeApiVersionReader("ver")
);
}).AddApiExplorer(opt => {
opt.GroupNameFormat = "'v'VVV"; // v1, v2, v3
opt.SubstituteApiVersionInUrl = true;
});
Versioned Controllers
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class ProductsController : ControllerBase {
[HttpGet]
public IActionResult Get() => Ok(new {
version = "1.0",
data = new[] { "old format" }
});
}
[ApiController]
[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class ProductsV2Controller : ControllerBase {
[HttpGet]
public IActionResult Get() => Ok(new {
version = "2.0",
data = new { items = new[] { "new format" }, meta = new {} }
});
}
Same Controller, Multiple Versions
[ApiController]
[ApiVersion("1.0")]
[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class UsersController : ControllerBase {
[HttpGet, MapToApiVersion("1.0")]
public IActionResult GetV1() => Ok(new { id = 1, name = "Rahim" });
[HttpGet, MapToApiVersion("2.0")]
public IActionResult GetV2() => Ok(new {
id = 1,
firstName = "Rahim",
lastName = "Uddin"
});
}
Deprecated Versions
[ApiVersion("1.0", Deprecated = true)]
[ApiVersion("2.0")]
public class ProductsController : ControllerBase { ... }
// Response header:
// api-supported-versions: 2.0
// api-deprecated-versions: 1.0
Calling Different Versions
# URL segment ⭐ (recommended) GET /api/v1/products GET /api/v2/products # Query string GET /api/products?api-version=2.0 # Header GET /api/products X-Api-Version: 2.0 # Media type GET /api/products Accept: application/json;ver=2.0
Swagger Multi-version
builder.Services.AddSwaggerGen();
builder.Services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions> {
private readonly IApiVersionDescriptionProvider _provider;
public ConfigureSwaggerOptions(IApiVersionDescriptionProvider p) => _provider = p;
public void Configure(SwaggerGenOptions opt) {
foreach (var desc in _provider.ApiVersionDescriptions) {
opt.SwaggerDoc(desc.GroupName, new OpenApiInfo {
Title = $"My API {desc.ApiVersion}",
Version = desc.ApiVersion.ToString()
});
}
}
}
app.UseSwaggerUI(opt => {
foreach (var desc in app.DescribeApiVersions()) {
opt.SwaggerEndpoint($"/swagger/{desc.GroupName}/swagger.json",
desc.GroupName.ToUpperInvariant());
}
});
Versioning Strategy Tips
- Major version বাড়ান breaking change-এ
- Old version কমপক্ষে ৬-১২ মাস maintain
- Deprecation header + docs-এ সতর্কতা
- Same business logic, ভিন্ন controller — ভাল practice