From f7a6e775545c9f00c42c6e5edd361a399e3666f4 Mon Sep 17 00:00:00 2001 From: Pierre Ferreira Date: Tue, 7 Mar 2023 19:26:03 +0100 Subject: [PATCH 1/2] =?UTF-8?q?:bookmark:=20D=C3=A9but=20du=20versionning,?= =?UTF-8?q?=20probl=C3=A8me=20au=20niveau=20de=20swagger,=20voir=20le=20co?= =?UTF-8?q?de=20du=20prof=20ou=20tenter=20un=20SwaggerOption,=20qui=20rest?= =?UTF-8?q?e=20compliquer.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sources/API_LoL/API_LoL.csproj | 2 + .../Controllers/ChampionsController.cs | 4 +- .../ChampionsControllerVersioned.cs | 106 ++++++++++++++++++ Sources/API_LoL/Program.cs | 41 ++++++- 4 files changed, 149 insertions(+), 4 deletions(-) create mode 100644 Sources/API_LoL/Controllers/ChampionsControllerVersioned.cs diff --git a/Sources/API_LoL/API_LoL.csproj b/Sources/API_LoL/API_LoL.csproj index 5ada54d..a8c4de7 100644 --- a/Sources/API_LoL/API_LoL.csproj +++ b/Sources/API_LoL/API_LoL.csproj @@ -9,6 +9,8 @@ + + diff --git a/Sources/API_LoL/Controllers/ChampionsController.cs b/Sources/API_LoL/Controllers/ChampionsController.cs index 9aefc31..acad597 100644 --- a/Sources/API_LoL/Controllers/ChampionsController.cs +++ b/Sources/API_LoL/Controllers/ChampionsController.cs @@ -9,7 +9,9 @@ using System.CodeDom.Compiler; namespace API_LoL.Controllers { - [Route("api/[controller]")] + //[Route("api/[controller]")] + [ApiVersion("1.0")] + [Route("api/v{version:apiVersion}/[controller]")] [ApiController] public class ChampionsController : ControllerBase { diff --git a/Sources/API_LoL/Controllers/ChampionsControllerVersioned.cs b/Sources/API_LoL/Controllers/ChampionsControllerVersioned.cs new file mode 100644 index 0000000..e8b3a24 --- /dev/null +++ b/Sources/API_LoL/Controllers/ChampionsControllerVersioned.cs @@ -0,0 +1,106 @@ +using Microsoft.AspNetCore.Mvc; +using Model; +using StubLib; +using DTO; +using DTO.Mapper; +using System.CodeDom.Compiler; + +namespace API_LoL.Controllers +{ + [ApiVersion("2.0")] + [ApiVersion("2.2")] + [Route("api/v{version:apiVersion}/versioned")] + [ApiController] + public class ChampionsControllerVersioned : ControllerBase + { + public ChampionsControllerVersioned(IDataManager Manager) + { + this.ChampionsManager = Manager.ChampionsMgr; + } + + private IChampionsManager ChampionsManager; + + // GET api//5 + + [HttpGet] + public async Task Get(String? name = null, String? skill = null, String? characteristic = null, int index = 0, int size = 10) + { + if (size - index > 10) + { + return BadRequest(); + } + if (!string.IsNullOrEmpty(name)) + { + var list = await ChampionsManager.GetItemsByName(name, index, size); + if (list.Count() != 0) + { + return Ok(list.Select(champion => champion?.ToDTO())); + } + else { return NoContent(); } + } + else if (!string.IsNullOrEmpty(skill)) + { + var list = await ChampionsManager.GetItemsBySkill(skill, index, size); + if (list.Count() != 0) + { + return Ok(list.Select(champion => champion?.ToDTO())); + } + else { return NoContent(); } + } + else if (!string.IsNullOrEmpty(characteristic)) + { + var list = await ChampionsManager.GetItems(index, size); + if (list.Count() != 0) + { + return Ok(list.Select(champion => champion?.ToDTO())); + } + else { return NoContent(); } + } + else + { + var list = await ChampionsManager.GetItems(index, size); + if (list.Count() != 0) + { + return Ok(list.Select(champion => champion?.ToDTO())); + } + else { return NoContent(); } + } + } + + + // POST api/ + [HttpPost] + public async Task Post(ChampionDTO champion) + { + if (champion == null) + { + return UnprocessableEntity(); + } + else + { + await ChampionsManager.AddItem(champion.ToChampion()); + return CreatedAtAction("Post", champion); + } + } + + // PUT api//5 + [HttpPut("{id}")] + public void Put(int id, [FromBody] string value) + { + } + + // DELETE api//5 + [HttpDelete("{id}")] + public void Delete(int id) + { + } + + + ///---------- Versioning ----------/// + [HttpGet] + public string GetThatOnlySayHello() => "Hello v2.0!"; + + [HttpGet, MapToApiVersion("2.2")] + public string GetThatOnlySayHelloV2() => "Hello but i'm from v2.2!"; + } +} diff --git a/Sources/API_LoL/Program.cs b/Sources/API_LoL/Program.cs index d4fb3b8..b8f9f47 100644 --- a/Sources/API_LoL/Program.cs +++ b/Sources/API_LoL/Program.cs @@ -1,24 +1,59 @@ +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.AspNetCore.Mvc.Versioning; using Model; using StubLib; var builder = WebApplication.CreateBuilder(args); -// Add services to the container. -builder.Services.AddControllers(); +//Versioning + +///NOT WORKING WHEN CHANGING VERSIONS : +/// voir sur https://blog.christian-schou.dk/how-to-use-api-versioning-in-net-core-web-api/ rubrique "Configure SwaggerOptions" +/// (mais requiere l'injection de dépendance). +/// Sinon, code plus simple disponible par le prof + + + +// Add ApiExplorer to discover versions +builder.Services.AddVersionedApiExplorer(setup => +{ + setup.GroupNameFormat = "'v'VVV"; + setup.SubstituteApiVersionInUrl = true; +}); + // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); + +builder.Services.AddApiVersioning(o => o.ApiVersionReader = new UrlSegmentApiVersionReader()); + +// Add services to the container. +builder.Services.AddControllers(); + + + builder.Services.AddScoped(); var app = builder.Build(); +var apiVersionDescriptionProvider = app.Services.GetRequiredService(); + + // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); - app.UseSwaggerUI(); + app.UseSwaggerUI(options => + { + + foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions) + { + options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", + description.GroupName.ToUpperInvariant()); + } + }); } app.UseHttpsRedirection(); From 0260d4afd0328909204459ba5125aaf1f82f0f25 Mon Sep 17 00:00:00 2001 From: Pierre Ferreira Date: Mon, 13 Mar 2023 16:23:27 +0100 Subject: [PATCH 2/2] :bookmark: fin du versionning ! 3 versions differentes : V1, V2, V2.2 ! --- .../ChampionsControllerVersioned.cs | 140 +++++++++--------- Sources/API_LoL/Program.cs | 6 + Sources/API_LoL/SwaggerOptions.cs | 61 ++++++++ 3 files changed, 138 insertions(+), 69 deletions(-) create mode 100644 Sources/API_LoL/SwaggerOptions.cs diff --git a/Sources/API_LoL/Controllers/ChampionsControllerVersioned.cs b/Sources/API_LoL/Controllers/ChampionsControllerVersioned.cs index e8b3a24..87598d9 100644 --- a/Sources/API_LoL/Controllers/ChampionsControllerVersioned.cs +++ b/Sources/API_LoL/Controllers/ChampionsControllerVersioned.cs @@ -22,84 +22,86 @@ namespace API_LoL.Controllers // GET api//5 - [HttpGet] - public async Task Get(String? name = null, String? skill = null, String? characteristic = null, int index = 0, int size = 10) - { - if (size - index > 10) - { - return BadRequest(); - } - if (!string.IsNullOrEmpty(name)) - { - var list = await ChampionsManager.GetItemsByName(name, index, size); - if (list.Count() != 0) - { - return Ok(list.Select(champion => champion?.ToDTO())); - } - else { return NoContent(); } - } - else if (!string.IsNullOrEmpty(skill)) - { - var list = await ChampionsManager.GetItemsBySkill(skill, index, size); - if (list.Count() != 0) - { - return Ok(list.Select(champion => champion?.ToDTO())); - } - else { return NoContent(); } - } - else if (!string.IsNullOrEmpty(characteristic)) - { - var list = await ChampionsManager.GetItems(index, size); - if (list.Count() != 0) - { - return Ok(list.Select(champion => champion?.ToDTO())); - } - else { return NoContent(); } - } - else - { - var list = await ChampionsManager.GetItems(index, size); - if (list.Count() != 0) - { - return Ok(list.Select(champion => champion?.ToDTO())); - } - else { return NoContent(); } - } - } + //[HttpGet] + //public async Task Get(String? name = null, String? skill = null, String? characteristic = null, int index = 0, int size = 10) + //{ + // if (size - index > 10) + // { + // return BadRequest(); + // } + // if (!string.IsNullOrEmpty(name)) + // { + // var list = await ChampionsManager.GetItemsByName(name, index, size); + // if (list.Count() != 0) + // { + // return Ok(list.Select(champion => champion?.ToDTO())); + // } + // else { return NoContent(); } + // } + // else if (!string.IsNullOrEmpty(skill)) + // { + // var list = await ChampionsManager.GetItemsBySkill(skill, index, size); + // if (list.Count() != 0) + // { + // return Ok(list.Select(champion => champion?.ToDTO())); + // } + // else { return NoContent(); } + // } + // else if (!string.IsNullOrEmpty(characteristic)) + // { + // var list = await ChampionsManager.GetItems(index, size); + // if (list.Count() != 0) + // { + // return Ok(list.Select(champion => champion?.ToDTO())); + // } + // else { return NoContent(); } + // } + // else + // { + // var list = await ChampionsManager.GetItems(index, size); + // if (list.Count() != 0) + // { + // return Ok(list.Select(champion => champion?.ToDTO())); + // } + // else { return NoContent(); } + // } + //} - // POST api/ - [HttpPost] - public async Task Post(ChampionDTO champion) - { - if (champion == null) - { - return UnprocessableEntity(); - } - else - { - await ChampionsManager.AddItem(champion.ToChampion()); - return CreatedAtAction("Post", champion); - } - } + //// POST api/ + //[HttpPost] + //public async Task Post(ChampionDTO champion) + //{ + // if (champion == null) + // { + // return UnprocessableEntity(); + // } + // else + // { + // await ChampionsManager.AddItem(champion.ToChampion()); + // return CreatedAtAction("Post", champion); + // } + //} - // PUT api//5 - [HttpPut("{id}")] - public void Put(int id, [FromBody] string value) - { - } + //// PUT api//5 + //[HttpPut("{id}")] + //public void Put(int id, [FromBody] string value) + //{ + //} - // DELETE api//5 - [HttpDelete("{id}")] - public void Delete(int id) - { - } + //// DELETE api//5 + //[HttpDelete("{id}")] + //public void Delete(int id) + //{ + //} ///---------- Versioning ----------/// - [HttpGet] + [HttpGet, MapToApiVersion("2.0")] public string GetThatOnlySayHello() => "Hello v2.0!"; + + //! FIXME : not working, mais avec la version 2.0 ca marche ! [HttpGet, MapToApiVersion("2.2")] public string GetThatOnlySayHelloV2() => "Hello but i'm from v2.2!"; } diff --git a/Sources/API_LoL/Program.cs b/Sources/API_LoL/Program.cs index b8f9f47..c192eac 100644 --- a/Sources/API_LoL/Program.cs +++ b/Sources/API_LoL/Program.cs @@ -1,3 +1,4 @@ +using API_LoL; using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.Versioning; using Model; @@ -26,6 +27,8 @@ builder.Services.AddVersionedApiExplorer(setup => builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); +builder.Services.ConfigureOptions(); + builder.Services.AddApiVersioning(o => o.ApiVersionReader = new UrlSegmentApiVersionReader()); @@ -36,6 +39,9 @@ builder.Services.AddControllers(); builder.Services.AddScoped(); + + + var app = builder.Build(); var apiVersionDescriptionProvider = app.Services.GetRequiredService(); diff --git a/Sources/API_LoL/SwaggerOptions.cs b/Sources/API_LoL/SwaggerOptions.cs new file mode 100644 index 0000000..46ad759 --- /dev/null +++ b/Sources/API_LoL/SwaggerOptions.cs @@ -0,0 +1,61 @@ +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.Extensions.Options; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace API_LoL +{ + public class ConfigureSwaggerOptions : IConfigureNamedOptions + { + private readonly IApiVersionDescriptionProvider _provider; + + public ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider) + { + _provider = provider; + } + + /// + /// Configure each API discovered for Swagger Documentation + /// + /// + public void Configure(SwaggerGenOptions options) + { + // add swagger document for every API version discovered + foreach (var description in _provider.ApiVersionDescriptions) + { + options.SwaggerDoc(description.GroupName, CreateVersionInfo(description)); + } + } + + /// + /// Configure Swagger Options. Inherited from the Interface + /// + /// + /// + public void Configure(string name, SwaggerGenOptions options) + { + Configure(options); + } + + /// + /// Create information about the version of the API + /// + /// + /// Information about the API + private OpenApiInfo CreateVersionInfo(ApiVersionDescription desc) + { + var info = new OpenApiInfo() + { + Title = ".NET Core (.NET 6) Web API", + Version = desc.ApiVersion.ToString() + }; + + if (desc.IsDeprecated) + { + info.Description += " This API version has been deprecated. Please use one of the new APIs available from the explorer."; + } + + return info; + } + } +}