In this post, we will look into how to add custom headers to your Swagger documentation using Swashbuckle.
We will add well-known “Accept-Language” header with conditionally visibility based on API method!
Setup application culture based on Accept-Language header
First, add CultureHandler and enable it into WEB API pipeline (for better understanding on how ASP.NET WEB API pipeline works and what are delegating handler, please refer to the-asp-net-web-api-2-http-message-lifecycle-in-43-easy-steps-2/
public class CultureHandler : DelegatingHandler { private static readonly string[] _acceptedCultures = { "en-GB", "de-DE" }; private static readonly string _defaultCulture = "en-GB"; protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { Thread.CurrentThread.CurrentCulture = new CultureInfo(_defaultCulture); if (request.Headers.AcceptLanguage != null) { foreach (var v in request.Headers.AcceptLanguage.OrderBy(al => al.Quality)) { if (_acceptedCultures.Contains(v.Value)) { Thread.CurrentThread.CurrentCulture = new CultureInfo(v.Value); } } } return base.SendAsync(request, cancellationToken); } }
Next, register CultureHandler in WebApiConfig:
public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.MapHttpAttributeRoutes(); config.MessageHandlers.Add(new CultureHandler()); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } }
Display Accept-Language header in Swagger UI
Ok, now it is time to add the possibility to display new header in Swagger UI.
For that, we will extend Swashbuckle behavior by introducing CultureAwareOperationFilter:
public class CultureAwareOperationFilter : IOperationFilter { public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription) { if (operation.parameters == null) { operation.parameters = new List<Parameter>(); } operation.parameters.Add(new Parameter { name = "Accept-Language", @in = "header", type = "string", required = true, @enum = new [] { "en-GB", "de-DE"} }); } }
Register new Operation filter in SwaggerConfig
c.OperationFilter<CultureAwareOperationFilter>();
To test new behavior let’s add new controller with simple localized content
public class ProductController : ApiController { [Route("products")] public IHttpActionResult Get() { if (Thread.CurrentThread.CurrentCulture.Name == "de-DE") { return Ok("I am German product!"); } return Ok("I am English product!"); } }
Now, it is time to run the project, if go by URI: http://localhost:50217/swagger/ui/index#!/Product/Product_Get, you could now see Accept-Language dropdown with English and German culture inside:
Now if select de-DE there, as a response you will get “I am German product!”.
Restricting Accept-Language header for specific APIs
If you now look at Discount API, you will see that it also got new header selection. That is quite misleading as API does not provide localization. Let’s try to fix this by extending CultureAwareOperationFilter. To make OperationFilter configuration decoupled from actual actions we will be using CultureAwareAttribute that will decorate specific methods.
public class CultureAwareAttribute : Attribute { }
Extend CultureAwareOperationFilter
public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription) { if (!apiDescription.ActionDescriptor.GetCustomAttributes<CultureAwareAttribute>().Any()) { return; } ... }
The last step is to decorate required actions with CultureAwareAttribute,
[Route("products")] [CultureAware] public IHttpActionResult Get()
Now if we open Swagger, we will see language header selection only for Products API, but it won’t appear for others.
Another usage example of operation filter
The operation is displayed as dropdown if @enum property is specified.
Another alternative is to specify @defaultValue
operation.parameters.Add(new Parameter { name = "X-Custom-Header", @in = "header", type = "string", required = true, @default = "Default value" });
In that case operation is displayed as textbox. That representation is often used to supply security key for API usage.
Summary:
We have looked into how to use operation filters to display custom headers in Swagger UI.
For basic usage, remember that @enum option is rendered as dropdown of choices, and as textbox otherwise.