Web Api How to add a Header parameter for all API in Swagger

94,543

Solution 1

Yes you can do it via inheriting from IOperationFilter

You can find the answer on GitHub here: AddRequiredHeaderParameter

using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;

public class AddRequiredHeaderParameter : IOperationFilter
{
    public void Apply(Operation operation, OperationFilterContext context)
    {
        if (operation.Parameters == null)
            operation.Parameters = new List<IParameter>();

        operation.Parameters.Add(new NonBodyParameter
            {
                Name = "X-User-Token",
                In = "header",
                Type = "string",
                Required = false
            });
    }
}

Then you go to your SwaggerConfig.cs file and add the following in the AddSwaggerGen section:

c.OperationFilter<AddRequiredHeaderParameter>();

Rebuild, and enjoy.

Solution 2

What the user "G T" wrote is correct but it is not working with Swagger 5. We have some new changes:

From: Operation to: OpenApiOperation

From: IParameter to: OpenApiParameter

From: NonBodyParameter to: OpenApiParameter, and the most important is...

From: Type = "string" to: Schema = new OpenApiSchema { Type = "String" }

using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace MyAPI
{
    public class AuthorizationHeaderParameterOperationFilter: IOperationFilter
    {
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            var filterPipeline = context.ApiDescription.ActionDescriptor.FilterDescriptors;
            var isAuthorized = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is AuthorizeFilter);
            var allowAnonymous = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is IAllowAnonymousFilter);

            if (isAuthorized && !allowAnonymous)
            {
                if (operation.Parameters == null)
                    operation.Parameters = new List<OpenApiParameter>();

                operation.Parameters.Add(new OpenApiParameter 
                {
                    Name = "Authorization",
                    In = ParameterLocation.Header,
                    Description = "access token",
                    Required = true,
                    Schema = new OpenApiSchema
                    {
                        Type = "string",
                        Default = new OpenApiString("Bearer ")
                    }
                });
            }
        }
    }
}

And in Startup => ConfigureServices => services.AddSwaggerGen()

c.OperationFilter<AuthorizationHeaderParameterOperationFilter>();

Solution 3

Another way to add custom headers is by adding parameters into controller action.
The following example will add x-test parameter to the UI:

[HttpPost]
public IActionResult Test([FromHeader(Name="x-test")][Required] string requiredHeader)
{
    return Ok();
}

enter image description here

Solution 4

I have improved the respectful Wille Esteche's answer a bit. If you want to apply headers not to all methods, but only to your selected controller methods, you can use attributes.

    [HttpPost]
    [Route(nameof(Auth))]
    [SwaggerHeader(Constants.HeaderDomainSid, "Encrypted User.Sid got from client", "abc123", true)]
    public ActionResult<string> Auth([FromHeader(Name = Constants.HeaderDomainSid)] string headerDomainSid = null)
    { .....
    

Attribute class:

public class SwaggerHeaderAttribute : Attribute
{
    public string HeaderName { get; }
    public string Description { get; }
    public string DefaultValue { get; }
    public bool IsRequired { get; }

    public SwaggerHeaderAttribute(string headerName, string description = null, string defaultValue = null, bool isRequired = false)
    {
        HeaderName = headerName;
        Description = description;
        DefaultValue = defaultValue;
        IsRequired = isRequired;
    }
}

Filter:

public class SwaggerHeaderFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        operation.Parameters ??= new List<OpenApiParameter>();

        if (context.MethodInfo.GetCustomAttribute(typeof(SwaggerHeaderAttribute)) is SwaggerHeaderAttribute attribute)
        {
            var existingParam = operation.Parameters.FirstOrDefault(p =>
                p.In == ParameterLocation.Header && p.Name == attribute.HeaderName);
            if (existingParam != null) // remove description from [FromHeader] argument attribute
            {
                operation.Parameters.Remove(existingParam);
            }

            operation.Parameters.Add(new OpenApiParameter
            {
                Name = attribute.HeaderName,
                In = ParameterLocation.Header,
                Description = attribute.Description,
                Required = attribute.IsRequired,
                Schema = string.IsNullOrEmpty(attribute.DefaultValue)
                    ? null
                    : new OpenApiSchema
                    {
                        Type = "String",
                        Default = new OpenApiString(attribute.DefaultValue)
                    }
            });
        }
    }
}
    

enter image description here

Solution 5

For Asp .Net MVC 5 you can use.
Following the need to be done in Swagger Config file.

private class AddAuthorizationHeaderParameter: IOperationFilter   // as a nested class in script config file.
{
    public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
    {
        if (operation.parameters == null)
            operation.parameters = new List<Parameter>();

        operation.parameters.Add(new Parameter
        {
            name = "Authorization",
            @in = "header",
            type = "string",
            required = true
        });
    }
}

c.OperationFilter<AddAuthorizationHeaderParameter>(); // finally add this line in .EnableSwagger

You can also add any no of headers for header implementation in Swagger.

Share:
94,543
Admin
Author by

Admin

Updated on October 31, 2021

Comments

  • Admin
    Admin over 2 years

    I searched for possible ways to add a request header parameter that would be added automatically to every method in my web-api but i couldn't find a clear one.

    While searching i found that the method OperationFilter() has to do something about it.

  • Ramy M. Mousa
    Ramy M. Mousa over 6 years
    @SoftwareEngineer It seems that the problem is in the ` AddRequiredHeaderParameter ` class trying to inherit from ` IOperationFilter ` make sure you installed swagger and referenced it to your project.
  • Ramy M. Mousa
    Ramy M. Mousa about 6 years
    @Saveen I'm not sure If I understand what you mean, but this code will add the same parameter to all the APIs you have. if doesn't cancel your function parameters, it only adds this one with the others associated with each API function.
  • Saveen
    Saveen about 6 years
    @RamyMohamed I Have found the solution to add parameter in specific action method by a little modification in above code. Thanks for providing the reference code above.
  • Rory McCrossan
    Rory McCrossan almost 5 years
    Just a quick note to say that the [FromHeader] attribute is only available for WebAPI instances which use ASP.Net Core, not full .Net.
  • zerox981
    zerox981 over 4 years
    Thx it works, but I had to make the parameter optional (Required=false) in 5.0.0-rc2) - otherwise i could not try it out (looks like it's a swashbucjke bug).
  • CodeHacker
    CodeHacker over 4 years
    @wille-esteche I did it exactly like that, but it doesn't work. It used to work on the older version, where it was done like in the accepted answer. When I do Required true, the UI fails with a validation error, with required false the authorization header is never sent.
  • Wille Esteche
    Wille Esteche over 4 years
    @CodeHacker Think about to put the Authorization for each method and not only for all the controller. With Swagger 4 I used Authorization for the controller but now it is working if a put it on each method. Try it if it's your case!
  • Zein Sleiman
    Zein Sleiman over 4 years
    @RamyMohamed Any idea why we check if operation.Parameters is null? What is the use case that this becomes null?
  • Ramy M. Mousa
    Ramy M. Mousa over 4 years
    @ZeinSleiman it becomes null when a service has zero path or query string parameters.
  • Zein Sleiman
    Zein Sleiman over 4 years
    @RamyMohamed When you say or query string parameters, do you mean no parameters passed or only query parameters passed. Also thanks for replying.
  • Chris Kooken
    Chris Kooken over 4 years
    @CodeHacker Did you ever get this working? Im having the same issue.
  • CodeHacker
    CodeHacker over 4 years
    Answer to stackoverflow.com/questions/58179180/… works! But don't forget to add "Bearer " before your actual token
  • Jeremy
    Jeremy over 4 years
    ASP.Net Core 3 and Swashbuckle.AspNetCore 5.0.0-rc4 does not seem to work. The generated documentation puts the entire class as the request body.
  • capcom923
    capcom923 about 4 years
    It works fine in Swashbuckle.AspNetCore 5.1.0. Thanks
  • John Mc
    John Mc over 3 years
    Just to add that my controller actions were using the AuthorizeAttribute and the above code didn't work as isAuthorized was always false. I added in a check for this as well and it worked: var hasAuthorizeAttribute = context.MethodInfo.DeclaringType.GetCustomAttributes(true).O‌​fType<Microsoft.AspN‌​etCore.Authorization‌​.AuthorizeAttribute>‌​().Any() || context.MethodInfo.GetCustomAttributes(true).OfType<Microsof‌​t.AspNetCore.Authori‌​zation.AuthorizeAttr‌​ibute>().Any();
  • Adam
    Adam over 3 years
    changing Type = "String" to "Type = "string" let's SwaggerUI work again with the required = true attribute!
  • Prasad Raja
    Prasad Raja over 3 years
    @Saveen can you share the piece of code that used the header for specific action
  • Gaurav Kaushik
    Gaurav Kaushik about 3 years
    Do we have anything like FromHeader in WebAPI 2.0 non .net core..?
  • Ramil Aliyev
    Ramil Aliyev about 3 years
    Thanks, it is working for me. I using .NET 5
  • Don B
    Don B over 2 years
    Just FYI, this example does not work with newer versions of Swashbuckle that are using Open API Spec 3 due to changes within the Swagger and how it handles auth. Basically behind the scenes it will remove the Authorization header if it finds it, see this article for more details: swagger.io/docs/specification/describing-parameters/…. The new suggested approach can be found in this article (look for domaindrivendev's response): github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/142‌​5
  • Nitesh
    Nitesh over 2 years
    I tried this. The customer header comes under Results View of httpContext.Request.Headers resultset but when I do var key = httpContext.Request.Headers.Where(z => z.Key == "CUSTOMKEY").FirstOrDefault(); I get key as [null,null]. Any ideas?
  • hawaii
    hawaii over 2 years
    This answer hit the spot for me. Ive done some custom attributes for controller methods that would read additional request parameters and doing this approach I can document those "hidden" parameters in swagger. My take is implementing an interface with methods to get headername, description, isrequired and defaultvalue.
  • Stefan
    Stefan about 2 years
    This approach works only for none DefaultHeader Data like User-Agent, Authorization, etc.
  • FelixSFD
    FelixSFD almost 2 years
    I'm using your solution for a while now, but I've just encountered an issue with this answer: If the header-field is marked as "required", SwaggerUI (maybe other clients as well) won't accept any String-value for the field. Type should instead be string (lowercase) Source