-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Swashbuckle/Swagger integration #27
Comments
I'll have to spin-up a sample project to see what's going on. Will try and get to it this week. |
@JamesCrann: here's a sample that works with Somewhere in Startup.cspublic void ConfigureServices(IServiceCollection services)
{
services.AddSwaggerGen(x =>
{
// x.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" });
x.OperationFilter<HybridOperationFilter>();
});
} Quickly hacked-together filter to make Hybrid-sources appear the same as [FromBody] sourcespublic class HybridOperationFilter : IOperationFilter
{
public void Apply(Operation operation, OperationFilterContext context)
{
var hybridParameters = context.ApiDescription.ParameterDescriptions
.Where(x => x.Source.Id == "Hybrid")
.Select(x => new
{
name = x.Name,
schema = context.SchemaRegistry.GetOrRegister(x.Type)
}).ToList();
for (var i = 0; i < operation.Parameters.Count; i++)
{
for (var j = 0; j < hybridParameters.Count; j++)
{
if (hybridParameters[j].name == operation.Parameters[i].Name)
{
var name = operation.Parameters[i].Name;
var isRequired = operation.Parameters[i].Required;
operation.Parameters.RemoveAt(i);
operation.Parameters.Insert(i, new BodyParameter()
{
Name = name,
Required = isRequired,
Schema = hybridParameters[j].schema,
});
}
}
}
}
} Some relevant references: |
v5.x version... At least its working for me... public class HybridOperationFilter : IOperationFilter
{
public void Apply(Operation operation, OperationFilterContext context)
{
var hybridParameters = context.ApiDescription.ParameterDescriptions
.Where(x => x.Source.Id == "Hybrid")
.Select(x => new { name = x.Name }).ToList();
for (var i = 0; i < operation.Parameters.Count; i++)
{
for (var j = 0; j < hybridParameters.Count; j++)
{
if (hybridParameters[j].name == operation.Parameters[i].Name)
{
var name = operation.Parameters[i].Name;
var isRequired = operation.Parameters[i].Required;
var hybridMediaType = new OpenApiMediaType { Schema = operation.Parameters[i].Schema };
operation.Parameters.RemoveAt(i);
operation.RequestBody = new OpenApiRequestBody
{
Content = new Dictionary<string, OpenApiMediaType>
{
//You are not limited to "application/json"...
//If you add more just ensure they use the same hybridMediaType
{ "application/json", hybridMediaType }
},
Required = isRequired
};
}
}
}
}
} NOTE: Since you probably don't want the properties that are going to be mapped from other sources to show up in your Swashbuckle UI schema definition you might want to implement the following two classes also... [AttributeUsage(AttributeTargets.Property)]
public class SwaggerIgnoreAttribute: Attribute { } And... public class SwaggerIgnoreFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (!(context.ApiModel is ApiObject))
{
return;
}
var model = context.ApiModel as ApiObject;
if (schema?.Properties == null || model?.ApiProperties == null)
{
return;
}
var excludedProperties = model.Type
.GetProperties()
.Where(
t => t.GetCustomAttribute<SwaggerIgnoreAttribute>() != null
);
var excludedSchemaProperties = model.ApiProperties
.Where(
ap => excludedProperties.Any(
pi => pi.Name == ap.MemberInfo.Name
)
);
foreach (var propertyToExclude in excludedSchemaProperties)
{
schema.Properties.Remove(propertyToExclude.ApiName);
}
}
} Don't forget to add the following to your Startup.cs => services.AddSwaggerGen() method. c.SchemaFilter<SwaggerIgnoreFilter>();
c.OperationFilter<HybridOperationFilter>(); Add the Parameter summary comments, to your Action method, for the Hybrid model properties that are NOT coming from the RequestBody, and add them to the Action method signature... /// <summary>
/// Create/Update Record
/// </summary>
/// <param name="filetype">FileType</param>
/// <param name="filenumber">FileNumber</param>
/// <param name="recordVM"><see cref="RecordViewModel"/></param>
/// <returns><see cref="OkObjectResult"/> or an Error Result</returns>
[HttpPost("~/api/record/{filetype}/{filenumber}")]
public IActionResult Upsert(
[FromHybrid, Required]RecordViewModel recordVM,
[Required]string filetype,
[Required]string filenumber)
{
return Ok(_recordService.Upsert(recordVM));
} And add the SwaggerIgnore Attribute (Defined above) to the Hybrid model properties that are NOT coming from the RequestBody public class RecordViewModel
{
[Required]
public string Text { get; set; } //Will be added by the HybridModelBinder from the Request Body
[Required]
public DateTime TransactionDate { get; set; } //Will be added by the HybridModelBinder from the Request Body
[Required]
[MaxLength(10)]
public string UserId { get; set; } //Will be added by the HybridModelBinder from the Request Body
[Required]
[SwaggerIgnore]
public string FileType { get; set; } //Will be added by the HybridModelBinder from the Path
[Required]
[SwaggerIgnore]
public string FileNumber { get; set; } //Will be added by the HybridModelBinder from the Path
} |
Thanks, @dkimbell13, for the update/code sample. I haven't forgotten about this issue. Been going through and doing some house-cleaning on the project today. I've got a list of TODOs getting the project ready for a |
Thanks for these filters, they work well. If anyone knows a way to source the route parameter comments from the model property, that would be great. I see the comment above about leaving the parameters on the method and commenting them there, but the parameters are completely unused (due to being bound to the model) and I'd love to be able to remove them from the method. |
Same issues here... I wish there was a workaround. |
Any updates on this? |
Hi,
I am having great success in using hybrid model binding to bind from route and body to a single model.
However the downside is that swashbuckle no longer functions correctly when generating swagger documentation.
Instead of the document example being displayed we just see the empty
{}
- also noting that the body thinks its coming from the queryHas anybody previously looked at adding a swashbuckle filter to correctly display the properties bound on the body?
The text was updated successfully, but these errors were encountered: