This commit is contained in:
2019-10-21 22:40:16 +00:00
parent 0ae191daca
commit de6ab566f0
7 changed files with 81 additions and 22 deletions

View File

@@ -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;
/// <summary>
/// Configures the Swagger generation options.
/// </summary>
/// <remarks>This allows API versioning to define a Swagger document per API version after the
/// <see cref="IApiVersionDescriptionProvider"/> service has been resolved from the service container.</remarks>
public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions>
{
readonly IApiVersionDescriptionProvider provider;
/// <summary>
/// Initializes a new instance of the <see cref="ConfigureSwaggerOptions"/> class.
/// </summary>
/// <param name="provider">The <see cref="IApiVersionDescriptionProvider">provider</see> used to generate Swagger documents.</param>
public ConfigureSwaggerOptions( IApiVersionDescriptionProvider provider ) => this.provider = provider;
/// <inheritdoc />
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;
}
}
}

View File

@@ -15,7 +15,7 @@ using AyaNova.Biz;
namespace AyaNova.Api.Controllers namespace AyaNova.Api.Controllers
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
@@ -95,7 +95,7 @@ namespace AyaNova.Api.Controllers
//Instantiate the business object handler //Instantiate the business object handler
DataFilterBiz biz = DataFilterBiz.GetBiz(ct, HttpContext); DataFilterBiz biz = DataFilterBiz.GetBiz(ct, HttpContext);
var l = await biz.GetPickListAsync(ListKey); var l = await biz.GetPickListAsync(ListKey);
return Ok(ApiOkResponse.Response(l, true)); return Ok(ApiOkResponse.Response(l, true));
@@ -154,9 +154,10 @@ namespace AyaNova.Api.Controllers
/// BizAdminFull, InventoryFull, TechFull /// BizAdminFull, InventoryFull, TechFull
/// </summary> /// </summary>
/// <param name="inObj"></param> /// <param name="inObj"></param>
/// <param name="apiVersion">Automatically filled from route path, no need to specify in body</param>
/// <returns></returns> /// <returns></returns>
[HttpPost] [HttpPost]
public async Task<IActionResult> PostDataFilter([FromBody] DataFilter inObj) public async Task<IActionResult> PostDataFilter([FromBody] DataFilter inObj, ApiVersion apiVersion)
{ {
if (!serverState.IsOpen) if (!serverState.IsOpen)
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason)); return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
@@ -176,7 +177,7 @@ namespace AyaNova.Api.Controllers
if (o == null) if (o == null)
return BadRequest(new ApiErrorResponse(biz.Errors)); return BadRequest(new ApiErrorResponse(biz.Errors));
else 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));
} }

View File

@@ -227,9 +227,10 @@ namespace AyaNova.Api.Controllers
/// Required roles: BizAdminFull /// Required roles: BizAdminFull
/// </summary> /// </summary>
/// <param name="inObj"></param> /// <param name="inObj"></param>
/// <param name="apiVersion">Automatically filled from route path, no need to specify in body</param>
/// <returns></returns> /// <returns></returns>
[HttpPost] [HttpPost]
public async Task<IActionResult> PostFormCustom([FromBody] FormCustom inObj) public async Task<IActionResult> PostFormCustom([FromBody] FormCustom inObj, ApiVersion apiVersion)
{ {
if (!serverState.IsOpen) if (!serverState.IsOpen)
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason)); return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
@@ -249,7 +250,7 @@ namespace AyaNova.Api.Controllers
if (o == null) if (o == null)
return BadRequest(new ApiErrorResponse(biz.Errors)); return BadRequest(new ApiErrorResponse(biz.Errors));
else 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));
} }

View File

@@ -169,9 +169,10 @@ namespace AyaNova.Api.Controllers
/// ///
/// </summary> /// </summary>
/// <param name="inObj">NameIdItem object containing source locale Id and new name</param> /// <param name="inObj">NameIdItem object containing source locale Id and new name</param>
/// <param name="apiVersion">Automatically filled from route path, no need to specify in body</param>
/// <returns>Error response or newly created locale</returns> /// <returns>Error response or newly created locale</returns>
[HttpPost("Duplicate")] [HttpPost("Duplicate")]
public async Task<IActionResult> Duplicate([FromBody] NameIdItem inObj) public async Task<IActionResult> Duplicate([FromBody] NameIdItem inObj, ApiVersion apiVersion)
{ {
if (serverState.IsClosed) if (serverState.IsClosed)
{ {
@@ -191,7 +192,7 @@ namespace AyaNova.Api.Controllers
} }
else 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));
} }
} }

View File

@@ -316,9 +316,10 @@ namespace AyaNova.Api.Controllers
/// ///
/// </summary> /// </summary>
/// <param name="inObj"></param> /// <param name="inObj"></param>
/// <param name="apiVersion">Automatically filled from route path, no need to specify in body</param>
/// <returns></returns> /// <returns></returns>
[HttpPost] [HttpPost]
public async Task<IActionResult> PostUser([FromBody] User inObj) public async Task<IActionResult> PostUser([FromBody] User inObj, ApiVersion apiVersion)
{ {
if (!serverState.IsOpen) if (!serverState.IsOpen)
{ {
@@ -355,7 +356,7 @@ namespace AyaNova.Api.Controllers
//return success and link //return success and link
//NOTE: this is a USER object so we don't want to return some key fields for security reasons //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 //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)));
} }
} }

View File

@@ -265,6 +265,7 @@ namespace AyaNova.Api.Controllers
/// BizAdminFull, InventoryFull /// BizAdminFull, InventoryFull
/// </summary> /// </summary>
/// <param name="inObj"></param> /// <param name="inObj"></param>
/// <param name="apiVersion">Automatically filled from route path, no need to specify in body</param>
/// <returns></returns> /// <returns></returns>
[HttpPost] [HttpPost]
public async Task<IActionResult> PostWidget([FromBody] Widget inObj, ApiVersion apiVersion) public async Task<IActionResult> PostWidget([FromBody] Widget inObj, ApiVersion apiVersion)
@@ -286,13 +287,9 @@ namespace AyaNova.Api.Controllers
Widget o = await biz.CreateAsync(inObj); Widget o = await biz.CreateAsync(inObj);
if (o == null) if (o == null)
return BadRequest(new ApiErrorResponse(biz.Errors)); return BadRequest(new ApiErrorResponse(biz.Errors));
else else
{
//originally but throwing exception since move to 3.1
//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)); 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: /// Required roles:
/// BizAdminFull, InventoryFull /// BizAdminFull, InventoryFull
/// </summary> /// </summary>
/// <param name="id">Create a duplicate of this item id</param> /// <param name="id">Create a duplicate of this items id</param>
/// <param name="apiVersion">Automatically filled from route path, no need to specify in body</param>
/// <returns></returns> /// <returns></returns>
[HttpPost("duplicate/{id}")] [HttpPost("duplicate/{id}")]
public async Task<IActionResult> DuplicateWidget([FromRoute] long id) public async Task<IActionResult> DuplicateWidget([FromRoute] long id, ApiVersion apiVersion)
{ {
if (!serverState.IsOpen) if (!serverState.IsOpen)
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason)); return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
@@ -329,7 +327,7 @@ namespace AyaNova.Api.Controllers
if (o == null) if (o == null)
return BadRequest(new ApiErrorResponse(biz.Errors)); return BadRequest(new ApiErrorResponse(biz.Errors));
else 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));
} }

View File

@@ -174,8 +174,8 @@ namespace AyaNova
{ {
Description = "JWT Authorization header using the Bearer scheme.", Description = "JWT Authorization header using the Bearer scheme.",
Type = SecuritySchemeType.Http, //We set the scheme type to http since we're using bearer authentication 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{ c.AddSecurityRequirement(new OpenApiSecurityRequirement{
{ {
@@ -262,10 +262,13 @@ namespace AyaNova
{ {
_log.LogDebug("BOOT: configuring request pipeline..."); _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()) // if (env.IsDevelopment())
// { // {
// app.UseDeveloperExceptionPage(); // app.UseDeveloperExceptionPage();
// } // }
//Store a reference to the dependency injection service for static classes //Store a reference to the dependency injection service for static classes
ServiceProviderProvider.Provider = app.ApplicationServices; ServiceProviderProvider.Provider = app.ApplicationServices;
@@ -457,7 +460,7 @@ namespace AyaNova
static string XmlCommentsFilePath static string XmlCommentsFilePath
{ {
get get
{ {
var basePath = AppContext.BaseDirectory; var basePath = AppContext.BaseDirectory;
var fileName = typeof(Startup).GetTypeInfo().Assembly.GetName().Name + ".xml"; var fileName = typeof(Startup).GetTypeInfo().Assembly.GetName().Name + ".xml";
return Path.Combine(basePath, fileName); return Path.Combine(basePath, fileName);