Reputation: 6531
As per the title - I've found examples of how to do this using regular .NET
E.g: Web Api How to add a Header parameter for all API in Swagger
However, I can't find any examples, or documentation, showing how to accomplish the same thing when using .NET Core 2.0.
Upvotes: 12
Views: 17712
Reputation: 389
There are two type of headers in swagger/OpenApi request headers and response headers.
Request headers are straightforward to implement, all you need to do is decorate your controller and/or operation like this:
[Route("api/[controller]")]
public class RequestHeadersController : Controller
{
[FromHeader(Name = "x-my-controller-wide-header")]
public string MyControllerWideHeader { get; set; }
[HttpGet]
public string Get([FromHeader(Name = "x-my-operation-header")]string myOperationHeader)
{
return myOperationHeader;
}
}
Swashbuckle.AspNetCore will automatically pick up any headers defined with
FromHeaderAttribute
and apply it to the swagger document.
There are no declarative way of specifying response headers in Asp.Net Core or Swashbuckle, so you'll have to do this manually.
Below example will return a custom header name x-my-header.
[Route("api/[controller]")]
public class ResponseHeadersController : Controller
{
[HttpGet]
public string Get()
{
HttpContext.Response.Headers["x-my-header"] = "header value";
return "value";
}
}
We now need to instruct swagger to include the response header. This is done through the IOperationFilter, please see Swashbuckle documentation on how filters work. Filters can be applied globally or per operation, however you can't customize the behavior by passing parameters into its constructor, do to the way filters are declared (by type only). As a consequence you'll have to write an operation filter per API method that returns one or more response headers. Alternatively you can define an attribute to declare response headers for an operation.
public enum HeaderResponseType { String, Number }
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class ProducesResponseHeaderAttribute : Attribute
{
public ProducesResponseHeaderAttribute(string name, int statusCode)
{
Name = name ?? throw new ArgumentNullException(nameof(name));
StatusCode = statusCode;
Type = HeaderResponseType.String;
}
public string Name { get; set; }
public int StatusCode { get; set; }
public HeaderResponseType Type { get; set; }
public string Description { get; set; }
}
This gives us the ability to declare per response code one or more headers.
[HttpGet]
[ProducesResponseHeader("x-my-header", (int)HttpStatusCode.OK)]
public string Get()
{
HttpContext.Response.Headers["x-my-header"] = "header value";
return "string";
}
Now that we have an attribute that defines our intend we can make a generic operation filter.
public class ResponseHeadersFilter : IOperationFilter
{
public void Apply(Operation operation, OperationFilterContext context)
{
// Get all response header declarations for a given operation
var actionResponsesWithHeaders = context.ApiDescription.ActionAttributes()
.OfType<ProducesResponseHeaderAttribute>()
.ToArray();
if (!actionResponsesWithHeaders.Any())
return;
foreach (var responseCode in operation.Responses.Keys)
{
// Do we have one or more headers for the specific response code
var responseHeaders = actionResponsesWithHeaders.Where(resp => resp.StatusCode.ToString() == responseCode);
if (!responseHeaders.Any())
continue;
var response = operation.Responses[responseCode];
if (response.Headers == null)
response.Headers = new Dictionary<string, Header>();
foreach (var responseHeader in responseHeaders)
{
response.Headers[responseHeader.Name] = new Header
{
Type = responseHeader.Type.ToString(),
Description = responseHeader.Description
};
}
}
}
}
All we need to do now is wire-up the operation filter to swagger generation.
// Startup.cs
services.AddSwaggerGen(c =>
{
...
c.OperationFilter<ResponseHeadersFilter>();
};
I hope this is enough to get you going.
Upvotes: 21