From de6ab566f050d1a4efa949bfeb23dd261bd6495f Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Mon, 21 Oct 2019 22:40:16 +0000 Subject: [PATCH] --- server/AyaNova/ConfigureSwaggerOptions.cs | 54 +++++++++++++++++++ .../Controllers/DataFilterController.cs | 9 ++-- .../Controllers/FormCustomController.cs | 5 +- .../AyaNova/Controllers/LocaleController.cs | 5 +- server/AyaNova/Controllers/UserController.cs | 5 +- .../AyaNova/Controllers/WidgetController.cs | 16 +++--- server/AyaNova/Startup.cs | 9 ++-- 7 files changed, 81 insertions(+), 22 deletions(-) create mode 100644 server/AyaNova/ConfigureSwaggerOptions.cs diff --git a/server/AyaNova/ConfigureSwaggerOptions.cs b/server/AyaNova/ConfigureSwaggerOptions.cs new file mode 100644 index 00000000..26c7bb33 --- /dev/null +++ b/server/AyaNova/ConfigureSwaggerOptions.cs @@ -0,0 +1,54 @@ +namespace AyaNova +{ + using Microsoft.AspNetCore.Mvc.ApiExplorer; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Options; + using Microsoft.OpenApi.Models; + using Swashbuckle.AspNetCore.SwaggerGen; + using System; + + /// + /// Configures the Swagger generation options. + /// + /// This allows API versioning to define a Swagger document per API version after the + /// service has been resolved from the service container. + public class ConfigureSwaggerOptions : IConfigureOptions + { + readonly IApiVersionDescriptionProvider provider; + + /// + /// Initializes a new instance of the class. + /// + /// The provider used to generate Swagger documents. + public ConfigureSwaggerOptions( IApiVersionDescriptionProvider provider ) => this.provider = provider; + + /// + public void Configure( SwaggerGenOptions options ) + { + // add a swagger document for each discovered API version + // note: you might choose to skip or document deprecated API versions differently + foreach ( var description in provider.ApiVersionDescriptions ) + { + options.SwaggerDoc( description.GroupName, CreateInfoForApiVersion( description ) ); + } + } + + static OpenApiInfo CreateInfoForApiVersion( ApiVersionDescription description ) + { + var info = new OpenApiInfo() + { + Title = "AyaNova API", + Version = description.ApiVersion.ToString(), + Description = "AyaNova service management software API", + + }; + + if ( description.IsDeprecated ) + { + info.Description += " This API version has been deprecated."; + } + + return info; + } + } +} \ No newline at end of file diff --git a/server/AyaNova/Controllers/DataFilterController.cs b/server/AyaNova/Controllers/DataFilterController.cs index 1bb6b6d8..b4450f14 100644 --- a/server/AyaNova/Controllers/DataFilterController.cs +++ b/server/AyaNova/Controllers/DataFilterController.cs @@ -15,7 +15,7 @@ using AyaNova.Biz; namespace AyaNova.Api.Controllers { - + /// /// /// @@ -95,7 +95,7 @@ namespace AyaNova.Api.Controllers //Instantiate the business object handler DataFilterBiz biz = DataFilterBiz.GetBiz(ct, HttpContext); - + var l = await biz.GetPickListAsync(ListKey); return Ok(ApiOkResponse.Response(l, true)); @@ -154,9 +154,10 @@ namespace AyaNova.Api.Controllers /// BizAdminFull, InventoryFull, TechFull /// /// + /// Automatically filled from route path, no need to specify in body /// [HttpPost] - public async Task PostDataFilter([FromBody] DataFilter inObj) + public async Task PostDataFilter([FromBody] DataFilter inObj, ApiVersion apiVersion) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason)); @@ -176,7 +177,7 @@ namespace AyaNova.Api.Controllers if (o == null) return BadRequest(new ApiErrorResponse(biz.Errors)); else - return CreatedAtAction("GetDataFilter", new { id = o.Id }, new ApiCreatedResponse(o)); + return CreatedAtAction(nameof(DataFilterController.GetDataFilter), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(o)); } diff --git a/server/AyaNova/Controllers/FormCustomController.cs b/server/AyaNova/Controllers/FormCustomController.cs index 9a2e17b4..17fa2119 100644 --- a/server/AyaNova/Controllers/FormCustomController.cs +++ b/server/AyaNova/Controllers/FormCustomController.cs @@ -227,9 +227,10 @@ namespace AyaNova.Api.Controllers /// Required roles: BizAdminFull /// /// + /// Automatically filled from route path, no need to specify in body /// [HttpPost] - public async Task PostFormCustom([FromBody] FormCustom inObj) + public async Task PostFormCustom([FromBody] FormCustom inObj, ApiVersion apiVersion) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason)); @@ -249,7 +250,7 @@ namespace AyaNova.Api.Controllers if (o == null) return BadRequest(new ApiErrorResponse(biz.Errors)); else - return CreatedAtAction("GetFormCustom", new { formkey = o.FormKey }, new ApiCreatedResponse(o)); + return CreatedAtAction(nameof(FormCustomController.GetFormCustom), new { formkey = o.FormKey, version = apiVersion.ToString() }, new ApiCreatedResponse(o)); } diff --git a/server/AyaNova/Controllers/LocaleController.cs b/server/AyaNova/Controllers/LocaleController.cs index c0768c34..169cf925 100644 --- a/server/AyaNova/Controllers/LocaleController.cs +++ b/server/AyaNova/Controllers/LocaleController.cs @@ -169,9 +169,10 @@ namespace AyaNova.Api.Controllers /// /// /// NameIdItem object containing source locale Id and new name + /// Automatically filled from route path, no need to specify in body /// Error response or newly created locale [HttpPost("Duplicate")] - public async Task Duplicate([FromBody] NameIdItem inObj) + public async Task Duplicate([FromBody] NameIdItem inObj, ApiVersion apiVersion) { if (serverState.IsClosed) { @@ -191,7 +192,7 @@ namespace AyaNova.Api.Controllers } else { - return CreatedAtAction("GetLocale", new { id = o.Id }, new ApiCreatedResponse(o)); + return CreatedAtAction(nameof(LocaleController.GetLocale), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(o)); } } diff --git a/server/AyaNova/Controllers/UserController.cs b/server/AyaNova/Controllers/UserController.cs index ed5920a4..665bc0f8 100644 --- a/server/AyaNova/Controllers/UserController.cs +++ b/server/AyaNova/Controllers/UserController.cs @@ -316,9 +316,10 @@ namespace AyaNova.Api.Controllers /// /// /// + /// Automatically filled from route path, no need to specify in body /// [HttpPost] - public async Task PostUser([FromBody] User inObj) + public async Task PostUser([FromBody] User inObj, ApiVersion apiVersion) { if (!serverState.IsOpen) { @@ -355,7 +356,7 @@ namespace AyaNova.Api.Controllers //return success and link //NOTE: this is a USER object so we don't want to return some key fields for security reasons //which is why the object is "cleaned" before return - return CreatedAtAction("GetUser", new { id = o.Id }, new ApiCreatedResponse(UserBiz.CleanUserForReturn(o))); + return CreatedAtAction(nameof(UserController.GetUser), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(UserBiz.CleanUserForReturn(o))); } } diff --git a/server/AyaNova/Controllers/WidgetController.cs b/server/AyaNova/Controllers/WidgetController.cs index 6f171957..87bd33de 100644 --- a/server/AyaNova/Controllers/WidgetController.cs +++ b/server/AyaNova/Controllers/WidgetController.cs @@ -265,6 +265,7 @@ namespace AyaNova.Api.Controllers /// BizAdminFull, InventoryFull /// /// + /// Automatically filled from route path, no need to specify in body /// [HttpPost] public async Task PostWidget([FromBody] Widget inObj, ApiVersion apiVersion) @@ -286,13 +287,9 @@ namespace AyaNova.Api.Controllers Widget o = await biz.CreateAsync(inObj); if (o == null) return BadRequest(new ApiErrorResponse(biz.Errors)); - else - { - //originally but throwing exception since move to 3.1 - //return CreatedAtAction("GetWidget", new { id = o.Id }, new ApiCreatedResponse(o)); + else return CreatedAtAction(nameof(WidgetController.GetWidget), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(o)); - - } + } @@ -302,10 +299,11 @@ namespace AyaNova.Api.Controllers /// Required roles: /// BizAdminFull, InventoryFull /// - /// Create a duplicate of this item id + /// Create a duplicate of this items id + /// Automatically filled from route path, no need to specify in body /// [HttpPost("duplicate/{id}")] - public async Task DuplicateWidget([FromRoute] long id) + public async Task DuplicateWidget([FromRoute] long id, ApiVersion apiVersion) { if (!serverState.IsOpen) return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason)); @@ -329,7 +327,7 @@ namespace AyaNova.Api.Controllers if (o == null) return BadRequest(new ApiErrorResponse(biz.Errors)); else - return CreatedAtAction("GetWidget", new { id = o.Id }, new ApiCreatedResponse(o)); + return CreatedAtAction(nameof(WidgetController.GetWidget), new { id = o.Id, version = apiVersion.ToString() }, new ApiCreatedResponse(o)); } diff --git a/server/AyaNova/Startup.cs b/server/AyaNova/Startup.cs index 8d655405..b16bca5a 100644 --- a/server/AyaNova/Startup.cs +++ b/server/AyaNova/Startup.cs @@ -174,8 +174,8 @@ namespace AyaNova { Description = "JWT Authorization header using the Bearer scheme.", Type = SecuritySchemeType.Http, //We set the scheme type to http since we're using bearer authentication - Scheme = "bearer" //The name of the HTTP Authorization scheme to be used in the Authorization header. In this case "bearer". - }); + Scheme = "bearer" //The name of the HTTP Authorization scheme to be used in the Authorization header. In this case "bearer". + }); c.AddSecurityRequirement(new OpenApiSecurityRequirement{ { @@ -262,10 +262,13 @@ namespace AyaNova { _log.LogDebug("BOOT: configuring request pipeline..."); + //this *may* be useful in the event of an issue so uncomment if necessary but errors during dev are handled equally by the logging, I think // if (env.IsDevelopment()) // { // app.UseDeveloperExceptionPage(); // } + + //Store a reference to the dependency injection service for static classes ServiceProviderProvider.Provider = app.ApplicationServices; @@ -457,7 +460,7 @@ namespace AyaNova static string XmlCommentsFilePath { get - { + { var basePath = AppContext.BaseDirectory; var fileName = typeof(Startup).GetTypeInfo().Assembly.GetName().Name + ".xml"; return Path.Combine(basePath, fileName);