When developing APIs, it is common to come across scenarios where we need to hide an endpoint from the public. In this article, we will explore various methods to achieve this goal, focusing on the Swashbuckle library in an ASP.NET application.

To download the source code for this article, you can visit our GitHub repository.

So let’s dive into the details and learn how to effectively hide API methods in Swagger.

Hiding Endpoint in Swagger

In general, Swagger is an open-source framework that helps us design, build, document, and consume RESTful Web services. It provides us with clear and detailed documentation of API endpoints and their expected inputs and outputs. All this leads to an easier way to share and maintain our web services.

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!

There can be a variety of reasons why we wouldn’t want to expose an endpoint in our documentation:

  • Sensitive operations
  • Deprecated endpoints
  • Internal endpoints
  • Not fully implemented endpoints

When we hide an endpoint in Swagger, we exclude it from the Swagger-generated API documentation, and it won’t be visible in the API documentation’s user interface. As a result, we won’t be able to explore the endpoint’s details and test it using Swagger.

Now that we know a little bit more about Swagger and potential reasons why we would want to hide an endpoint, let’s see it in action.

Project Setup

To start it off, we will create a new ASP.NET Core Web API project. We can do it using the ASP.NET Core Web API template in Visual Studio, or using .NET CLI:

dotnet new webapi

To show different ways of hiding an endpoint, let’s extend the default WeatherForecast controller with a few methods of our own:

[HttpGet("GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
    return GetWeatherForecastData();
}

[HttpGet("GetMethodOne")]
[NonAction]
public IEnumerable<WeatherForecast> GetMethodOne()
{
    return GetWeatherForecastData();
}

[HttpGet("GetMethodTwo")]
[ApiExplorerSettings(IgnoreApi = true)]
public IEnumerable<WeatherForecast> GetMethodTwo()
{
    return GetWeatherForecastData();
}

[HttpGet("GetMethodThree")]
public IEnumerable<WeatherForecast> GetMethodThree()
{
    return GetWeatherForecastData();
}

[HttpGet("GetMethodFour")]
public IEnumerable<WeatherForecast> GetMethodFour()
{
    return GetWeatherForecastData();
}

private IEnumerable<WeatherForecast> GetWeatherForecastData()
{
    return Enumerable.Range(1, 5).Select(index => new WeatherForecast
    {
        Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
        TemperatureC = Random.Shared.Next(-20, 55),
        Summary = Summaries[Random.Shared.Next(Summaries.Length)]
    })
   .ToArray();
}

We expand the existing GetWeatherForecast controller with four more methods that we can use to experiment with hiding endpoints. It’s important to note that we have kept the names of the methods and the endpoint URIs straightforward for simplicity and in real-life scenarios we should follow the REST URI formatting.

Now, if we run our application, we will end up on http://localhost:<port>/swagger/index.html where we can see how all the routes are documented in Swagger:

Generated Swagger endpoints

Since now we have everything ready, let’s try to hide each one of these methods differently. 

Using DocInclusionPredicate

The first way we can go about hiding an endpoint in Swagger is to use DocInclusionPredicate().

DocInclusionPredicate() is a delegate that is invoked against every ApiDescription that’s surfaced by our application. It takes two parameters, docName and apiDesc. docName refers to the name of the Swagger document, which can be useful to distinguish between multiple Swagger documents.

Meanwhile, apiDesc parameter represents the API description, which contains information about the processed endpoint.

We can set up DocInclusionPredicate() when configuring Swagger, and customize it to filter the endpoints and operations included in the generated Swagger documentation.

So let’s say we want to hide our first endpoint named GetWeatherForecast:

builder.Services.AddSwaggerGen(c =>
{
    c.DocInclusionPredicate((docName, apiDesc) =>
    {
        var routeTemplate = apiDesc.RelativePath;

        if (routeTemplate == "WeatherForecast/GetWeatherForecast")
            return false;

        return true;
    });
});

First, we extract the relative path of the API endpoint that is being evaluated in the routeTemplate variable. After that, we check if the endpoint routeTemplate matches "WeatherForecast/GetWeatherForecast".

If it matches, we return false, which means that the API endpoint will be excluded from the Swagger documentation. In any other case, we return true, meaning that the endpoint will be included in the Swagger documentation.

Using NonAction Attribute

One more thing we can do when we want to hide an endpoint from Swagger is to use NonAction attribute on the endpoint method we want to hide:

[HttpGet("GetMethodOne")]
[NonAction]
public IEnumerable<WeatherForecast> GetMethodOne()
{
    return GetWeatherForecastData();
}

By using NonAction attribute we indicate that the controller method is not an action method. Since Swagger relies on the API actions to generate the documentation, it will ignore any endpoint we mark with this attribute during the scanning process, and therefore the endpoint will not appear in the Swagger documentation. It also hides the public availability of the action.

It is important to note that we can apply this attribute only to controller endpoints and not the whole controller itself.

Using ApiExplorerSettings Attribute With the IgnoreApi Parameter

Another way to hide an endpoint from Swagger is to use the ApiExplorerSettings attribute with the IgnoreApi parameter set to true:

[HttpGet("GetMethodTwo")]
[ApiExplorerSettings(IgnoreApi = true)]
public IEnumerable<WeatherForecast> GetMethodTwo()
{
    return GetWeatherForecastData();
}

When using the [ApiExplorerSettings(IgnoreApi = true)] attribute, we instruct the API Explorer responsible for generating the Swagger documentation, to exclude a specific endpoint from the generated documentation.

Contrary to the NonAction attribute, we can use this attribute on the controller level, and hide all endpoints inside it.

Using IActionModelConvention

What can also come in handy when trying to hide an endpoint in Swagger is IActionModelConvention.

In general, IActionModelConvention is an interface that we can use to apply conventions to individual action methods. To use it, we need to implement the interface and the Apply() method that takes an ActionModel object as a parameter and applies desired conventions to it:

public class HideControllerConvention : IActionModelConvention
{
    public void Apply(ActionModel action)
    {
        if (action.ActionName == "GetMethodThree")
        {
            action.ApiExplorer.IsVisible = false;
        }
    }
}

In our case, we want to hide the GetMethodThree endpoint. First, we check the action ActionName property to find the wanted action name, and after we have it, we set its visibility to false.

Now, when we set up the desired convention, we also need to register it in our Program.cs when adding controllers to make everything work as expected:

builder.Services.AddControllers(s =>
   s.Conventions.Add(new HideControllerConvention()
));

Using IDocumentFilter

The last route we will take in hiding the Swagger endpoint is to use IDocumentFilter.

The IDocumentFilter interface is part of Swashbuckle.AspNetCore.SwaggerGen namespace and it allows us to modify the generated Swagger document before it’s presented. In our case, we create SwaggerDocumentFilter class which implements the IDocumentFilter interface:

public class SwaggerDocumentFilter : IDocumentFilter
{
    public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
    {
        swaggerDoc.Paths.Remove("/WeatherForecast/GetMethodFour");
    }
}

Inside the Apply() method, we have access to the OpenApiDocument and the DocumentFilterContext. The OpenApiDocument represents the generated Swagger document, and DocumentFilterContext provides us with additional context during the document generation process.

By calling swaggerDoc.Paths.Remove("/WeatherForecast/GetMethodFour"), we remove the entry for this specific endpoint from the Paths property of the Swagger document, In this way, we are making sure that the method will be hidden from the generated Swagger documentation.

Lastly, we need to add the document filter when configuring Swagger in our Program.cs:

builder.Services.AddSwaggerGen(c =>
{
   c.DocumentFilter<SwaggerDocumentFilter>();
   c.DocInclusionPredicate((docName, apiDesc) =>
   {
       var routeTemplate = apiDesc.RelativePath;

       if (routeTemplate == "WeatherForecast/GetWeatherForecast")
           return false;

       return true;
   });
});

Now, if we rerun our application, we can see that the generated spec file does not present any of the endpoints:

Generated Swagger endpoints

When to Use Each Method

In conclusion, the choice of which method to use depends on our requirements and the level of control we need.

For simple cases where we need to hide individual endpoints, using the IgnoreApi parameter of the ApiExplorerSettings attribute or the NonAction attribute can be sufficient. Their usage is the most straightforward one.

It’s worth noting that, the NonAction attribute hides the endpoint from the documentation and it completely disables it and we can’t reach it with HTTP calls, unlike the other techniques where the endpoint is hidden from the documentation but will stay reachable by HTTP calls targeting it. 

For situations requiring more advanced filtering or transformations, the IActionModelConvention can be an excellent choice. We can hide an endpoint in Swagger based on any custom filter on all the properties available in the ActionModel class.

Using DocInclusionPredicate() and IDocumentFilter work similarly. They both give us access to the Swagger document name and the ApiDescription object. One benefit of the DocInclusionPredicate() is that it is configured directly when setting up a Swagger, and it doesn’t require any additional interface implementations.  

Conclusion

In this article, we looked at different ways to hide API endpoints in Swagger documentation. We explored using DocInclusionPredicate() for direct configuration, as well as simpler options like the IgnoreApi parameter and the NonAction attribute. Lastly, we covered more advanced customization using IDocumentFilter and IActionModelConvention interfaces, that provide us with a range of choices to hide endpoints.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!