From 5e53edafad1704b2955efaa2f8c8eb1337da0caf Mon Sep 17 00:00:00 2001 From: StevanFreeborn Date: Mon, 20 Jun 2022 23:09:47 -0500 Subject: [PATCH] added support for versioning the api --- .editorconfig | 3 ++ .../{ => v1}/EpisodesController.cs | 15 +++---- .../Controllers/{ => v1}/SeasonsController.cs | 5 ++- server/Options/ConfigureSwaggerOptions.cs | 39 +++++++++++++++++++ server/Program.cs | 34 +++++++++++++--- server/server.csproj | 2 + 6 files changed, 81 insertions(+), 17 deletions(-) rename server/Controllers/{ => v1}/EpisodesController.cs (73%) rename server/Controllers/{ => v1}/SeasonsController.cs (93%) create mode 100644 server/Options/ConfigureSwaggerOptions.cs diff --git a/.editorconfig b/.editorconfig index dba896c..ab869c3 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,3 +2,6 @@ # CS0472: The result of the expression is always the same since a value of this type is never equal to 'null' dotnet_diagnostic.CS0472.severity = none + +# CS8604: Possible null reference argument. +dotnet_diagnostic.CS8604.severity = none diff --git a/server/Controllers/EpisodesController.cs b/server/Controllers/v1/EpisodesController.cs similarity index 73% rename from server/Controllers/EpisodesController.cs rename to server/Controllers/v1/EpisodesController.cs index 7dc03a2..5c024aa 100644 --- a/server/Controllers/EpisodesController.cs +++ b/server/Controllers/v1/EpisodesController.cs @@ -1,15 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; using server.Models; using server.Persistence.Repositories; -namespace server.Controllers +namespace server.Controllers.v1 { [ApiController] + [ApiVersion("1.0")] [Route("/api/episodes")] [Produces("application/json")] public class EpisodesController : ControllerBase @@ -21,16 +17,15 @@ namespace server.Controllers _episodeRepository = episodeRepository; } + [MapToApiVersion("1.0")] [HttpGet] [ProducesResponseType(typeof(List), 200)] [ProducesResponseType(500)] - public async Task>> GetEpisodesAsync([FromQuery]EpisodeFilter? filter) + public async Task>> GetEpisodesAsync([FromQuery] EpisodeFilter? filter) { try { -#pragma warning disable CS8604 // Possible null reference argument. var seasons = await _episodeRepository.GetEpisodesAsync(filter); -#pragma warning restore CS8604 // Possible null reference argument. return Ok(seasons); } catch (Exception e) diff --git a/server/Controllers/SeasonsController.cs b/server/Controllers/v1/SeasonsController.cs similarity index 93% rename from server/Controllers/SeasonsController.cs rename to server/Controllers/v1/SeasonsController.cs index a182394..c294c74 100644 --- a/server/Controllers/SeasonsController.cs +++ b/server/Controllers/v1/SeasonsController.cs @@ -2,9 +2,10 @@ using server.Models; using server.Persistence.Repositories; -namespace server.Controllers +namespace server.Controllers.v1 { [ApiController] + [ApiVersion("1.0")] [Route("/api/seasons")] [Produces("application/json")] public class SeasonsController : ControllerBase @@ -16,6 +17,7 @@ namespace server.Controllers _seasonRepository = seasonRepository; } + [MapToApiVersion("1.0")] [HttpGet] [ProducesResponseType(typeof(List), 200)] [ProducesResponseType(500)] @@ -33,6 +35,7 @@ namespace server.Controllers } } + [MapToApiVersion("1.0")] [HttpGet("{number:int}")] [ProducesResponseType(typeof(Season), 200)] [ProducesResponseType(typeof(ErrorResponse), 404)] diff --git a/server/Options/ConfigureSwaggerOptions.cs b/server/Options/ConfigureSwaggerOptions.cs new file mode 100644 index 0000000..f4af72f --- /dev/null +++ b/server/Options/ConfigureSwaggerOptions.cs @@ -0,0 +1,39 @@ +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.Extensions.Options; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace server.Options +{ + public class ConfigureSwaggerOptions : IConfigureOptions + { + private readonly IApiVersionDescriptionProvider _provider; + + public ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider) + { + _provider = provider; + } + + public void Configure(SwaggerGenOptions options) + { + foreach (var description in _provider.ApiVersionDescriptions) + { + var versionInfo = CreateVersionInfo(description); + + options.SwaggerDoc(description.GroupName, versionInfo); + } + } + + private OpenApiInfo CreateVersionInfo(ApiVersionDescription description) + { + var info = new OpenApiInfo + { + Title = "criminalmindsapi", + Version = description.ApiVersion.ToString(), + Description = "An api that provides information about the Criminal Minds series." + }; + + return info; + } + } +} diff --git a/server/Program.cs b/server/Program.cs index 0c2a842..5c05cd5 100644 --- a/server/Program.cs +++ b/server/Program.cs @@ -1,5 +1,9 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.AspNetCore.Mvc.Versioning; using Microsoft.Extensions.Options; using Microsoft.OpenApi.Models; +using server.Options; using server.Persistence; using server.Persistence.Repositories; using server.Persistence.Seed; @@ -17,8 +21,6 @@ if (args.Length == 2 && args[0].ToLower() == "seed") { await seeder.SeedEpisodesAsync(); } - - } var builder = WebApplication.CreateBuilder(args); @@ -39,18 +41,38 @@ builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(c => +builder.Services.AddSwaggerGen(); + +builder.Services.ConfigureOptions(); + +builder.Services.AddApiVersioning(config => { - c.SwaggerDoc("v1", new OpenApiInfo { Title = "criminalmindsapi", Version = "v1" }); + config.DefaultApiVersion = new ApiVersion(1, 0); + config.AssumeDefaultVersionWhenUnspecified = true; + config.ReportApiVersions = true; + config.ApiVersionReader = new HeaderApiVersionReader("x-api-version"); +}); + +builder.Services.AddVersionedApiExplorer(config => +{ + config.GroupNameFormat = "'v'VVV"; }); var app = builder.Build(); app.UseSwagger(); -app.UseSwaggerUI(c => +app.UseSwaggerUI(options => { - c.SwaggerEndpoint("/swagger/v1/swagger.json", "criminalmindsapi v1"); + var provider = app.Services.GetRequiredService(); + + foreach (var description in provider.ApiVersionDescriptions) + { + var url = $"/swagger/{description.GroupName}/swagger.json"; + var name = $"criminalmindsapi v{description.ApiVersion.ToString()}"; + + options.SwaggerEndpoint(url, name); + } }); app.UseHttpsRedirection(); diff --git a/server/server.csproj b/server/server.csproj index 3ca00a4..f22ee52 100644 --- a/server/server.csproj +++ b/server/server.csproj @@ -11,6 +11,8 @@ + +