forked from loafle/openapi-generator-original
Added Base Path support as well as PathParameterValidation (#7120)
* Ran bin/aspnetcore-petstore-server.sh * Added BasePath filter and Validation filter * Updated filters and added Attribute generators * Removed newline * Updated samples
This commit is contained in:
parent
3c8293bbcf
commit
d881cb39bf
@ -120,6 +120,9 @@ public class AspNetCoreServerCodegen extends AbstractCSharpCodegen {
|
|||||||
|
|
||||||
supportingFiles.add(new SupportingFile("Properties" + File.separator + "launchSettings.json", packageFolder + File.separator + "Properties", "launchSettings.json"));
|
supportingFiles.add(new SupportingFile("Properties" + File.separator + "launchSettings.json", packageFolder + File.separator + "Properties", "launchSettings.json"));
|
||||||
|
|
||||||
|
supportingFiles.add(new SupportingFile("Filters" + File.separator + "BasePathDocumentFilter.mustache", packageFolder + File.separator + "Filters", "BasePathDocumentFilter.cs"));
|
||||||
|
supportingFiles.add(new SupportingFile("Filters" + File.separator + "PathParameterValidationFilter.mustache", packageFolder + File.separator + "Filters", "PathParameterValidationFilter.cs"));
|
||||||
|
|
||||||
supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "README.md", packageFolder + File.separator + "wwwroot", "README.md"));
|
supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "README.md", packageFolder + File.separator + "wwwroot", "README.md"));
|
||||||
supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "index.html", packageFolder + File.separator + "wwwroot", "index.html"));
|
supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "index.html", packageFolder + File.separator + "wwwroot", "index.html"));
|
||||||
supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "web.config", packageFolder + File.separator + "wwwroot", "web.config"));
|
supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "web.config", packageFolder + File.separator + "wwwroot", "web.config"));
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using Swashbuckle.AspNetCore.Swagger;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
|
||||||
|
namespace {{packageName}}.Filters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// BasePath Document Filter sets BasePath property of Swagger and removes it from the individual URL paths
|
||||||
|
/// </summary>
|
||||||
|
public class BasePathDocumentFilter : IDocumentFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="basePath">BasePath to remove from Operations</param>
|
||||||
|
public BasePathDocumentFilter(string basePath)
|
||||||
|
{
|
||||||
|
BasePath = basePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the BasePath of the Swagger Doc
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The BasePath of the Swagger Doc</returns>
|
||||||
|
public string BasePath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Apply the filter
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="swaggerDoc">SwaggerDocument</param>
|
||||||
|
/// <param name="context">FilterContext</param>
|
||||||
|
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
|
||||||
|
{
|
||||||
|
swaggerDoc.BasePath = this.BasePath;
|
||||||
|
|
||||||
|
var pathsToModify = swaggerDoc.Paths.Where(p => p.Key.StartsWith(this.BasePath)).ToList();
|
||||||
|
|
||||||
|
foreach (var path in pathsToModify)
|
||||||
|
{
|
||||||
|
if (path.Key.StartsWith(this.BasePath))
|
||||||
|
{
|
||||||
|
string newKey = Regex.Replace(path.Key, $"^{this.BasePath}", string.Empty);
|
||||||
|
swaggerDoc.Paths.Remove(path.Key);
|
||||||
|
swaggerDoc.Paths.Add(newKey, path.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||||
|
using Swashbuckle.AspNetCore.Swagger;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
|
||||||
|
namespace {{packageName}}.Filters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Path Parameter Validation Filter
|
||||||
|
/// </summary>
|
||||||
|
public class PathParameterValidationFilter : IOperationFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="operation">Operation</param>
|
||||||
|
/// <param name="context">OperationFilterContext</param>
|
||||||
|
public void Apply(Operation operation, OperationFilterContext context)
|
||||||
|
{
|
||||||
|
var pars = context.ApiDescription.ParameterDescriptions;
|
||||||
|
|
||||||
|
foreach (var par in pars)
|
||||||
|
{
|
||||||
|
var swaggerParam = operation.Parameters.SingleOrDefault(p => p.Name == par.Name);
|
||||||
|
|
||||||
|
var attributes = ((ControllerParameterDescriptor)par.ParameterDescriptor).ParameterInfo.CustomAttributes;
|
||||||
|
|
||||||
|
if (attributes != null && attributes.Count() > 0 && swaggerParam != null)
|
||||||
|
{
|
||||||
|
// Required - [Required]
|
||||||
|
var requiredAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RequiredAttribute));
|
||||||
|
if (requiredAttr != null)
|
||||||
|
{
|
||||||
|
swaggerParam.Required = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regex Pattern [RegularExpression]
|
||||||
|
var regexAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RegularExpressionAttribute));
|
||||||
|
if (regexAttr != null)
|
||||||
|
{
|
||||||
|
string regex = (string)regexAttr.ConstructorArguments[0].Value;
|
||||||
|
if (swaggerParam is NonBodyParameter)
|
||||||
|
{
|
||||||
|
((NonBodyParameter)swaggerParam).Pattern = regex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String Length [StringLength]
|
||||||
|
int? minLenght = null, maxLength = null;
|
||||||
|
var stringLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(StringLengthAttribute));
|
||||||
|
if (stringLengthAttr != null)
|
||||||
|
{
|
||||||
|
if (stringLengthAttr.NamedArguments.Count == 1)
|
||||||
|
{
|
||||||
|
minLenght = (int)stringLengthAttr.NamedArguments.Single(p => p.MemberName == "MinimumLength").TypedValue.Value;
|
||||||
|
}
|
||||||
|
maxLength = (int)stringLengthAttr.ConstructorArguments[0].Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
var minLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(MinLengthAttribute));
|
||||||
|
if (minLengthAttr != null)
|
||||||
|
{
|
||||||
|
minLenght = (int)minLengthAttr.ConstructorArguments[0].Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
var maxLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(MaxLengthAttribute));
|
||||||
|
if (maxLengthAttr != null)
|
||||||
|
{
|
||||||
|
maxLength = (int)maxLengthAttr.ConstructorArguments[0].Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (swaggerParam is NonBodyParameter)
|
||||||
|
{
|
||||||
|
((NonBodyParameter)swaggerParam).MinLength = minLenght;
|
||||||
|
((NonBodyParameter)swaggerParam).MaxLength = maxLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range [Range]
|
||||||
|
var rangeAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RangeAttribute));
|
||||||
|
if (rangeAttr != null)
|
||||||
|
{
|
||||||
|
int rangeMin = (int)rangeAttr.ConstructorArguments[0].Value;
|
||||||
|
int rangeMax = (int)rangeAttr.ConstructorArguments[1].Value;
|
||||||
|
|
||||||
|
if (swaggerParam is NonBodyParameter)
|
||||||
|
{
|
||||||
|
((NonBodyParameter)swaggerParam).Minimum = rangeMin;
|
||||||
|
((NonBodyParameter)swaggerParam).Maximum = rangeMax;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,6 +10,7 @@ using Newtonsoft.Json.Converters;
|
|||||||
using Newtonsoft.Json.Serialization;
|
using Newtonsoft.Json.Serialization;
|
||||||
using Swashbuckle.AspNetCore.Swagger;
|
using Swashbuckle.AspNetCore.Swagger;
|
||||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
using {{packageName}}.Filters;
|
||||||
|
|
||||||
namespace {{packageName}}
|
namespace {{packageName}}
|
||||||
{
|
{
|
||||||
@ -62,6 +63,12 @@ namespace {{packageName}}
|
|||||||
c.CustomSchemaIds(type => type.FriendlyId(true));
|
c.CustomSchemaIds(type => type.FriendlyId(true));
|
||||||
c.DescribeAllEnumsAsStrings();
|
c.DescribeAllEnumsAsStrings();
|
||||||
c.IncludeXmlComments($"{AppContext.BaseDirectory}{Path.DirectorySeparatorChar}{_hostingEnv.ApplicationName}.xml");
|
c.IncludeXmlComments($"{AppContext.BaseDirectory}{Path.DirectorySeparatorChar}{_hostingEnv.ApplicationName}.xml");
|
||||||
|
{{#basePathWithoutHost}}
|
||||||
|
// Sets the basePath property in the Swagger document generated
|
||||||
|
c.DocumentFilter<BasePathDocumentFilter>("{{{basePathWithoutHost}}}");
|
||||||
|
{{/basePathWithoutHost}}
|
||||||
|
// Do validation of path parameters w. DataAnnotation attributes
|
||||||
|
c.OperationFilter<PathParameterValidationFilter>();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ using Microsoft.Extensions.Logging;
|
|||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using {{packageName}}.Attributes;
|
using {{packageName}}.Attributes;
|
||||||
using {{packageName}}.Models;
|
using {{packageName}}.Models;
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
{{#isFormParam}}[FromForm]{{&dataType}} {{paramName}}{{/isFormParam}}
|
{{#isFormParam}}[FromForm]{{#required}}[Required()]{{/required}}{{#pattern}}[RegularExpression("{{{pattern}}}")]{{/pattern}}{{#minLength}}{{#maxLength}}[StringLength({{maxLength}}, MinimumLength={{minLength}}){{/maxLength}}{{/minLength}}{{#minLength}}{{^maxLength}} [MinLength({{minLength}})]{{/maxLength}}{{/minLength}}{{^minLength}}{{#maxLength}} [MaxLength({{maxLength}})]{{/maxLength}}{{/minLength}}{{#minimum}}{{#maximum}}[Range({{minimum}}, {{maximum}})]{{/maximum}}{{/minimum}}{{&dataType}} {{paramName}}{{/isFormParam}}
|
@ -1 +1 @@
|
|||||||
{{#isHeaderParam}}[FromHeader]{{&dataType}} {{paramName}}{{/isHeaderParam}}
|
{{#isHeaderParam}}[FromHeader]{{#required}}[Required()]{{/required}}{{#pattern}}[RegularExpression("{{{pattern}}}")]{{/pattern}}{{#minLength}}{{#maxLength}}[StringLength({{maxLength}}, MinimumLength={{minLength}}){{/maxLength}}{{/minLength}}{{#minLength}}{{^maxLength}} [MinLength({{minLength}})]{{/maxLength}}{{/minLength}}{{^minLength}}{{#maxLength}} [MaxLength({{maxLength}})]{{/maxLength}}{{/minLength}}{{#minimum}}{{#maximum}}[Range({{minimum}}, {{maximum}})]{{/maximum}}{{/minimum}}{{&dataType}} {{paramName}}{{/isHeaderParam}}
|
@ -1 +1 @@
|
|||||||
{{#isPathParam}}[FromRoute]{{&dataType}} {{paramName}}{{/isPathParam}}
|
{{#isPathParam}}[FromRoute]{{#required}}[Required]{{/required}}{{#pattern}}[RegularExpression("{{{pattern}}}")]{{/pattern}}{{#minLength}}{{#maxLength}}[StringLength({{maxLength}}, MinimumLength={{minLength}}){{/maxLength}}{{/minLength}}{{#minLength}}{{^maxLength}} [MinLength({{minLength}})]{{/maxLength}}{{/minLength}}{{^minLength}}{{#maxLength}} [MaxLength({{maxLength}})]{{/maxLength}}{{/minLength}}{{#minimum}}{{#maximum}}[Range({{minimum}}, {{maximum}})]{{/maximum}}{{/minimum}}{{&dataType}} {{paramName}}{{/isPathParam}}
|
@ -1 +1 @@
|
|||||||
{{#isQueryParam}}[FromQuery]{{&dataType}} {{paramName}}{{/isQueryParam}}
|
{{#isQueryParam}}[FromQuery]{{#required}}[Required()]{{/required}}{{#pattern}}[RegularExpression("{{{pattern}}}")]{{/pattern}}{{#minLength}}{{#maxLength}}[StringLength({{maxLength}}, MinimumLength={{minLength}}){{/maxLength}}{{/minLength}}{{#minLength}}{{^maxLength}} [MinLength({{minLength}})]{{/maxLength}}{{/minLength}}{{^minLength}}{{#maxLength}} [MaxLength({{maxLength}})]{{/maxLength}}{{/minLength}}{{#minimum}}{{#maximum}}[Range({{minimum}}, {{maximum}})]{{/maximum}}{{/minimum}}{{&dataType}} {{paramName}}{{/isQueryParam}}
|
@ -20,6 +20,7 @@ using Microsoft.Extensions.Logging;
|
|||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using IO.Swagger.Attributes;
|
using IO.Swagger.Attributes;
|
||||||
using IO.Swagger.Models;
|
using IO.Swagger.Models;
|
||||||
|
|
||||||
@ -60,7 +61,7 @@ namespace IO.Swagger.Controllers
|
|||||||
[Route("/v2/pet/{petId}")]
|
[Route("/v2/pet/{petId}")]
|
||||||
[ValidateModelState]
|
[ValidateModelState]
|
||||||
[SwaggerOperation("DeletePet")]
|
[SwaggerOperation("DeletePet")]
|
||||||
public virtual IActionResult DeletePet([FromRoute]long? petId, [FromHeader]string apiKey)
|
public virtual IActionResult DeletePet([FromRoute][Required]long? petId, [FromHeader]string apiKey)
|
||||||
{
|
{
|
||||||
//TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
//TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||||
// return StatusCode(400);
|
// return StatusCode(400);
|
||||||
@ -82,7 +83,7 @@ namespace IO.Swagger.Controllers
|
|||||||
[SwaggerOperation("FindPetsByStatus")]
|
[SwaggerOperation("FindPetsByStatus")]
|
||||||
[SwaggerResponse(200, typeof(List<Pet>), "successful operation")]
|
[SwaggerResponse(200, typeof(List<Pet>), "successful operation")]
|
||||||
[SwaggerResponse(400, typeof(List<Pet>), "Invalid status value")]
|
[SwaggerResponse(400, typeof(List<Pet>), "Invalid status value")]
|
||||||
public virtual IActionResult FindPetsByStatus([FromQuery]List<string> status)
|
public virtual IActionResult FindPetsByStatus([FromQuery][Required()]List<string> status)
|
||||||
{
|
{
|
||||||
//TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
//TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||||
// return StatusCode(200, default(List<Pet>));
|
// return StatusCode(200, default(List<Pet>));
|
||||||
@ -112,7 +113,7 @@ namespace IO.Swagger.Controllers
|
|||||||
[SwaggerOperation("FindPetsByTags")]
|
[SwaggerOperation("FindPetsByTags")]
|
||||||
[SwaggerResponse(200, typeof(List<Pet>), "successful operation")]
|
[SwaggerResponse(200, typeof(List<Pet>), "successful operation")]
|
||||||
[SwaggerResponse(400, typeof(List<Pet>), "Invalid tag value")]
|
[SwaggerResponse(400, typeof(List<Pet>), "Invalid tag value")]
|
||||||
public virtual IActionResult FindPetsByTags([FromQuery]List<string> tags)
|
public virtual IActionResult FindPetsByTags([FromQuery][Required()]List<string> tags)
|
||||||
{
|
{
|
||||||
//TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
//TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||||
// return StatusCode(200, default(List<Pet>));
|
// return StatusCode(200, default(List<Pet>));
|
||||||
@ -144,7 +145,7 @@ namespace IO.Swagger.Controllers
|
|||||||
[SwaggerResponse(200, typeof(Pet), "successful operation")]
|
[SwaggerResponse(200, typeof(Pet), "successful operation")]
|
||||||
[SwaggerResponse(400, typeof(Pet), "Invalid ID supplied")]
|
[SwaggerResponse(400, typeof(Pet), "Invalid ID supplied")]
|
||||||
[SwaggerResponse(404, typeof(Pet), "Pet not found")]
|
[SwaggerResponse(404, typeof(Pet), "Pet not found")]
|
||||||
public virtual IActionResult GetPetById([FromRoute]long? petId)
|
public virtual IActionResult GetPetById([FromRoute][Required]long? petId)
|
||||||
{
|
{
|
||||||
//TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
//TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||||
// return StatusCode(200, default(Pet));
|
// return StatusCode(200, default(Pet));
|
||||||
@ -203,7 +204,7 @@ namespace IO.Swagger.Controllers
|
|||||||
[Route("/v2/pet/{petId}")]
|
[Route("/v2/pet/{petId}")]
|
||||||
[ValidateModelState]
|
[ValidateModelState]
|
||||||
[SwaggerOperation("UpdatePetWithForm")]
|
[SwaggerOperation("UpdatePetWithForm")]
|
||||||
public virtual IActionResult UpdatePetWithForm([FromRoute]long? petId, [FromForm]string name, [FromForm]string status)
|
public virtual IActionResult UpdatePetWithForm([FromRoute][Required]long? petId, [FromForm]string name, [FromForm]string status)
|
||||||
{
|
{
|
||||||
//TODO: Uncomment the next line to return response 405 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
//TODO: Uncomment the next line to return response 405 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||||
// return StatusCode(405);
|
// return StatusCode(405);
|
||||||
@ -225,7 +226,7 @@ namespace IO.Swagger.Controllers
|
|||||||
[ValidateModelState]
|
[ValidateModelState]
|
||||||
[SwaggerOperation("UploadFile")]
|
[SwaggerOperation("UploadFile")]
|
||||||
[SwaggerResponse(200, typeof(ApiResponse), "successful operation")]
|
[SwaggerResponse(200, typeof(ApiResponse), "successful operation")]
|
||||||
public virtual IActionResult UploadFile([FromRoute]long? petId, [FromForm]string additionalMetadata, [FromForm]System.IO.Stream file)
|
public virtual IActionResult UploadFile([FromRoute][Required]long? petId, [FromForm]string additionalMetadata, [FromForm]System.IO.Stream file)
|
||||||
{
|
{
|
||||||
//TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
//TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||||
// return StatusCode(200, default(ApiResponse));
|
// return StatusCode(200, default(ApiResponse));
|
||||||
|
@ -20,6 +20,7 @@ using Microsoft.Extensions.Logging;
|
|||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using IO.Swagger.Attributes;
|
using IO.Swagger.Attributes;
|
||||||
using IO.Swagger.Models;
|
using IO.Swagger.Models;
|
||||||
|
|
||||||
@ -41,7 +42,7 @@ namespace IO.Swagger.Controllers
|
|||||||
[Route("/v2/store/order/{orderId}")]
|
[Route("/v2/store/order/{orderId}")]
|
||||||
[ValidateModelState]
|
[ValidateModelState]
|
||||||
[SwaggerOperation("DeleteOrder")]
|
[SwaggerOperation("DeleteOrder")]
|
||||||
public virtual IActionResult DeleteOrder([FromRoute]string orderId)
|
public virtual IActionResult DeleteOrder([FromRoute][Required]string orderId)
|
||||||
{
|
{
|
||||||
//TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
//TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||||
// return StatusCode(400);
|
// return StatusCode(400);
|
||||||
@ -92,7 +93,7 @@ namespace IO.Swagger.Controllers
|
|||||||
[SwaggerResponse(200, typeof(Order), "successful operation")]
|
[SwaggerResponse(200, typeof(Order), "successful operation")]
|
||||||
[SwaggerResponse(400, typeof(Order), "Invalid ID supplied")]
|
[SwaggerResponse(400, typeof(Order), "Invalid ID supplied")]
|
||||||
[SwaggerResponse(404, typeof(Order), "Order not found")]
|
[SwaggerResponse(404, typeof(Order), "Order not found")]
|
||||||
public virtual IActionResult GetOrderById([FromRoute]long? orderId)
|
public virtual IActionResult GetOrderById([FromRoute][Required][Range(1, 5)]long? orderId)
|
||||||
{
|
{
|
||||||
//TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
//TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||||
// return StatusCode(200, default(Order));
|
// return StatusCode(200, default(Order));
|
||||||
|
@ -20,6 +20,7 @@ using Microsoft.Extensions.Logging;
|
|||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using IO.Swagger.Attributes;
|
using IO.Swagger.Attributes;
|
||||||
using IO.Swagger.Models;
|
using IO.Swagger.Models;
|
||||||
|
|
||||||
@ -98,7 +99,7 @@ namespace IO.Swagger.Controllers
|
|||||||
[Route("/v2/user/{username}")]
|
[Route("/v2/user/{username}")]
|
||||||
[ValidateModelState]
|
[ValidateModelState]
|
||||||
[SwaggerOperation("DeleteUser")]
|
[SwaggerOperation("DeleteUser")]
|
||||||
public virtual IActionResult DeleteUser([FromRoute]string username)
|
public virtual IActionResult DeleteUser([FromRoute][Required]string username)
|
||||||
{
|
{
|
||||||
//TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
//TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||||
// return StatusCode(400);
|
// return StatusCode(400);
|
||||||
@ -125,7 +126,7 @@ namespace IO.Swagger.Controllers
|
|||||||
[SwaggerResponse(200, typeof(User), "successful operation")]
|
[SwaggerResponse(200, typeof(User), "successful operation")]
|
||||||
[SwaggerResponse(400, typeof(User), "Invalid username supplied")]
|
[SwaggerResponse(400, typeof(User), "Invalid username supplied")]
|
||||||
[SwaggerResponse(404, typeof(User), "User not found")]
|
[SwaggerResponse(404, typeof(User), "User not found")]
|
||||||
public virtual IActionResult GetUserByName([FromRoute]string username)
|
public virtual IActionResult GetUserByName([FromRoute][Required]string username)
|
||||||
{
|
{
|
||||||
//TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
//TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||||
// return StatusCode(200, default(User));
|
// return StatusCode(200, default(User));
|
||||||
@ -159,7 +160,7 @@ namespace IO.Swagger.Controllers
|
|||||||
[SwaggerOperation("LoginUser")]
|
[SwaggerOperation("LoginUser")]
|
||||||
[SwaggerResponse(200, typeof(string), "successful operation")]
|
[SwaggerResponse(200, typeof(string), "successful operation")]
|
||||||
[SwaggerResponse(400, typeof(string), "Invalid username/password supplied")]
|
[SwaggerResponse(400, typeof(string), "Invalid username/password supplied")]
|
||||||
public virtual IActionResult LoginUser([FromQuery]string username, [FromQuery]string password)
|
public virtual IActionResult LoginUser([FromQuery][Required()]string username, [FromQuery][Required()]string password)
|
||||||
{
|
{
|
||||||
//TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
//TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||||
// return StatusCode(200, default(string));
|
// return StatusCode(200, default(string));
|
||||||
@ -206,7 +207,7 @@ namespace IO.Swagger.Controllers
|
|||||||
[Route("/v2/user/{username}")]
|
[Route("/v2/user/{username}")]
|
||||||
[ValidateModelState]
|
[ValidateModelState]
|
||||||
[SwaggerOperation("UpdateUser")]
|
[SwaggerOperation("UpdateUser")]
|
||||||
public virtual IActionResult UpdateUser([FromRoute]string username, [FromBody]User body)
|
public virtual IActionResult UpdateUser([FromRoute][Required]string username, [FromBody]User body)
|
||||||
{
|
{
|
||||||
//TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
//TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||||
// return StatusCode(400);
|
// return StatusCode(400);
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using Swashbuckle.AspNetCore.Swagger;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
|
||||||
|
namespace IO.Swagger.Filters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// BasePath Document Filter sets BasePath property of Swagger and removes it from the individual URL paths
|
||||||
|
/// </summary>
|
||||||
|
public class BasePathDocumentFilter : IDocumentFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="basePath">BasePath to remove from Operations</param>
|
||||||
|
public BasePathDocumentFilter(string basePath)
|
||||||
|
{
|
||||||
|
BasePath = basePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the BasePath of the Swagger Doc
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The BasePath of the Swagger Doc</returns>
|
||||||
|
public string BasePath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Apply the filter
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="swaggerDoc">SwaggerDocument</param>
|
||||||
|
/// <param name="context">FilterContext</param>
|
||||||
|
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
|
||||||
|
{
|
||||||
|
swaggerDoc.BasePath = this.BasePath;
|
||||||
|
|
||||||
|
var pathsToModify = swaggerDoc.Paths.Where(p => p.Key.StartsWith(this.BasePath)).ToList();
|
||||||
|
|
||||||
|
foreach (var path in pathsToModify)
|
||||||
|
{
|
||||||
|
if (path.Key.StartsWith(this.BasePath))
|
||||||
|
{
|
||||||
|
string newKey = Regex.Replace(path.Key, $"^{this.BasePath}", string.Empty);
|
||||||
|
swaggerDoc.Paths.Remove(path.Key);
|
||||||
|
swaggerDoc.Paths.Add(newKey, path.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||||
|
using Swashbuckle.AspNetCore.Swagger;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
|
||||||
|
namespace IO.Swagger.Filters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Path Parameter Validation Filter
|
||||||
|
/// </summary>
|
||||||
|
public class PathParameterValidationFilter : IOperationFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="operation">Operation</param>
|
||||||
|
/// <param name="context">OperationFilterContext</param>
|
||||||
|
public void Apply(Operation operation, OperationFilterContext context)
|
||||||
|
{
|
||||||
|
var pars = context.ApiDescription.ParameterDescriptions;
|
||||||
|
|
||||||
|
foreach (var par in pars)
|
||||||
|
{
|
||||||
|
var swaggerParam = operation.Parameters.SingleOrDefault(p => p.Name == par.Name);
|
||||||
|
|
||||||
|
var attributes = ((ControllerParameterDescriptor)par.ParameterDescriptor).ParameterInfo.CustomAttributes;
|
||||||
|
|
||||||
|
if (attributes != null && attributes.Count() > 0 && swaggerParam != null)
|
||||||
|
{
|
||||||
|
// Required - [Required]
|
||||||
|
var requiredAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RequiredAttribute));
|
||||||
|
if (requiredAttr != null)
|
||||||
|
{
|
||||||
|
swaggerParam.Required = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regex Pattern [RegularExpression]
|
||||||
|
var regexAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RegularExpressionAttribute));
|
||||||
|
if (regexAttr != null)
|
||||||
|
{
|
||||||
|
string regex = (string)regexAttr.ConstructorArguments[0].Value;
|
||||||
|
if (swaggerParam is NonBodyParameter)
|
||||||
|
{
|
||||||
|
((NonBodyParameter)swaggerParam).Pattern = regex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String Length [StringLength]
|
||||||
|
int? minLenght = null, maxLength = null;
|
||||||
|
var stringLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(StringLengthAttribute));
|
||||||
|
if (stringLengthAttr != null)
|
||||||
|
{
|
||||||
|
if (stringLengthAttr.NamedArguments.Count == 1)
|
||||||
|
{
|
||||||
|
minLenght = (int)stringLengthAttr.NamedArguments.Single(p => p.MemberName == "MinimumLength").TypedValue.Value;
|
||||||
|
}
|
||||||
|
maxLength = (int)stringLengthAttr.ConstructorArguments[0].Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
var minLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(MinLengthAttribute));
|
||||||
|
if (minLengthAttr != null)
|
||||||
|
{
|
||||||
|
minLenght = (int)minLengthAttr.ConstructorArguments[0].Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
var maxLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(MaxLengthAttribute));
|
||||||
|
if (maxLengthAttr != null)
|
||||||
|
{
|
||||||
|
maxLength = (int)maxLengthAttr.ConstructorArguments[0].Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (swaggerParam is NonBodyParameter)
|
||||||
|
{
|
||||||
|
((NonBodyParameter)swaggerParam).MinLength = minLenght;
|
||||||
|
((NonBodyParameter)swaggerParam).MaxLength = maxLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range [Range]
|
||||||
|
var rangeAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RangeAttribute));
|
||||||
|
if (rangeAttr != null)
|
||||||
|
{
|
||||||
|
int rangeMin = (int)rangeAttr.ConstructorArguments[0].Value;
|
||||||
|
int rangeMax = (int)rangeAttr.ConstructorArguments[1].Value;
|
||||||
|
|
||||||
|
if (swaggerParam is NonBodyParameter)
|
||||||
|
{
|
||||||
|
((NonBodyParameter)swaggerParam).Minimum = rangeMin;
|
||||||
|
((NonBodyParameter)swaggerParam).Maximum = rangeMax;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,6 +19,7 @@ using Newtonsoft.Json.Converters;
|
|||||||
using Newtonsoft.Json.Serialization;
|
using Newtonsoft.Json.Serialization;
|
||||||
using Swashbuckle.AspNetCore.Swagger;
|
using Swashbuckle.AspNetCore.Swagger;
|
||||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
using IO.Swagger.Filters;
|
||||||
|
|
||||||
namespace IO.Swagger
|
namespace IO.Swagger
|
||||||
{
|
{
|
||||||
@ -71,6 +72,10 @@ namespace IO.Swagger
|
|||||||
c.CustomSchemaIds(type => type.FriendlyId(true));
|
c.CustomSchemaIds(type => type.FriendlyId(true));
|
||||||
c.DescribeAllEnumsAsStrings();
|
c.DescribeAllEnumsAsStrings();
|
||||||
c.IncludeXmlComments($"{AppContext.BaseDirectory}{Path.DirectorySeparatorChar}{_hostingEnv.ApplicationName}.xml");
|
c.IncludeXmlComments($"{AppContext.BaseDirectory}{Path.DirectorySeparatorChar}{_hostingEnv.ApplicationName}.xml");
|
||||||
|
// Sets the basePath property in the Swagger document generated
|
||||||
|
c.DocumentFilter<BasePathDocumentFilter>("/v2");
|
||||||
|
// Do validation of path parameters w. DataAnnotation attributes
|
||||||
|
c.OperationFilter<PathParameterValidationFilter>();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user