Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET Core 2.0 Web API - How to add a custom header parameter in Swagger

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.

like image 872
marcusstarnes Avatar asked Nov 29 '17 15:11

marcusstarnes


People also ask

Can we pass header in swagger?

In ASP.NET Web API, the simplest way to pass-in a header on Swagger UI is to implement the Apply(...) method on the IOperationFilter interface.

How do I add a header in Web API?

Adding Custom Header for Individual Response We create a very basic HTTP GET endpoint. Within this endpoint, we access the Response object through the HttpContext object. Then, we add a new header, with the name of x-my-custom-header and a value of individual response .

How do you add multiple headers to Swagger UI?

You can pass multiple header params on a single request, just use unique names for them (key is used in the above example). To be clear, both headers are added to Access-Control-Allow-Headers, and both can be recived separatelly by server, the case is that i'm not able to send them together.


1 Answers

There are two type of headers in swagger/OpenApi request headers and response headers.

Request 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.

Response Headers

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.

like image 111
Lars Skovslund Avatar answered Sep 27 '22 00:09

Lars Skovslund