Ocultar un endpoint significa dejarlo fuera del documento OpenAPI que genera la aplicación, así que nunca aparece en Swagger UI. El endpoint en sí sigue funcionando: todas las técnicas que veremos, salvo [NonAction], dejan la ruta accesible por HTTP.
Cuál usar depende de cuánto queramos ocultar y de dónde. Los atributos como [ApiExplorerSettings(IgnoreApi = true)] actúan sobre el API Explorer del framework y ocultan una acción a todos los generadores a la vez. DocInclusionPredicate() y los filtros de documentos actúan dentro de Swashbuckle, y el generador de OpenAPI que incluyen .NET 9 y .NET 10 tiene sus propios equivalentes para ambos.
¿Por qué ocultar un endpoint en Swagger?
Ocultar un endpoint significa dejar su operación fuera del documento OpenAPI que genera la aplicación. Swagger UI solo muestra lo que contiene ese documento, así que una operación que no está en él tampoco está en la página, y no hay ningún botón “Try it out” en el que hacer clic.
En la ruta en sí no cambia nada. El endpoint sigue respondiendo a las solicitudes, sigue aplicando su autorización y sigue estando en la tabla de enrutamiento. La única excepción es [NonAction], que le indica a MVC que el método no es una acción en absoluto, así que la ruta desaparece junto con la documentación y la URL empieza a devolver 404.
Toda la cuestión de la seguridad se reduce a esa diferencia, y conviene decirlo sin rodeos. Ocultar una operación es una decisión de documentación, no un control de seguridad. Cualquiera que conozca la URL puede seguir llamando a un endpoint oculto, así que uno sensible necesita primero una autorización real, y ocultarlo sirve, como mucho, de segunda capa.
Swagger es el conjunto de herramientas construido en torno a ese documento, y la configuración que damos por hecha aquí sale del artículo sobre cómo configurar Swagger UI en una Web API de ASP.NET Core.
Puede haber varios motivos para no querer exponer un endpoint en la documentación:
- Operaciones sensibles
- Endpoints obsoletos
- Endpoints internos
- Endpoints que no están implementados del todo
¿Cómo ocultar un endpoint con Swashbuckle?
Veremos cinco formas de ocultar un endpoint, que se dividen en dos grupos con comportamientos distintos.
Tres de ellas funcionan a través del API Explorer, que es el inventario que el propio framework tiene de nuestros endpoints. [NonAction], [ApiExplorerSettings(IgnoreApi = true)] y una IActionModelConvention que establece ApiExplorer.IsVisible en false quitan la acción antes de que ningún generador de documentos llegue a verla.
Las otras dos funcionan dentro del propio Swashbuckle. DocInclusionPredicate() decide, endpoint por endpoint, si una acción pertenece a un documento con nombre, y un IDocumentFilter edita el documento terminado y quita rutas por su nombre.
La diferencia práctica es el alcance. El grupo del API Explorer oculta un endpoint a todos los generadores que tengamos instalados y lo saca de todos los documentos a la vez. El grupo de Swashbuckle solo lo oculta a Swashbuckle, y solo en los documentos que configuremos, que es justo lo que queremos cuando un documento debe mostrar un endpoint y otro no.
Para empezar, vamos a crear un proyecto nuevo de Web API de ASP.NET Core. Podemos hacerlo con la plantilla ASP.NET Core Web API de Visual Studio o con la CLI de .NET.
Desde .NET 9, esa plantilla ya no incluye Swashbuckle. Lo que hace es instalar Microsoft.AspNetCore.OpenApi y llamar a AddOpenApi() y MapOpenApi(), que generan el documento OpenAPI, pero no ofrecen ninguna interfaz de usuario. Así que creamos el proyecto con controladores y añadimos Swashbuckle nosotros mismos:
dotnet new webapi --use-controllers dotnet add package Swashbuckle.AspNetCore
Después, tres líneas en Program.cs registran el generador y la interfaz de usuario:
builder.Services.AddSwaggerGen(); app.UseSwagger(); app.UseSwaggerUI();
Para mostrar distintas formas de ocultar un endpoint, vamos a ampliar el controlador WeatherForecast predeterminado con algunos métodos propios y a reemplazar su acción Get():
[HttpGet("GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return GetWeatherForecastData();
}
[HttpGet("GetMethodOne")]
public IEnumerable<WeatherForecast> GetMethodOne()
{
return GetWeatherForecastData();
}
[HttpGet("GetMethodTwo")]
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();
}
Ampliamos el controlador WeatherForecast existente con cuatro métodos más con los que podemos experimentar a la hora de ocultar endpoints. Para simplificar, hemos dejado sencillos los nombres de los métodos y las URI de los endpoints, aunque en casos reales deberíamos seguir el formato de URI de REST.
Fíjate en que a cada método le damos un segmento de ruta en lugar del nombre de ruta de la plantilla, de modo que cada endpoint queda en una ruta propia.
Ahora, si ejecutamos la aplicación y abrimos http://localhost:<port>/swagger/index.html, podemos ver cómo todas las rutas aparecen documentadas en Swagger:

Ahora que lo tenemos todo listo, vamos a intentar ocultar cada uno de estos métodos de una forma distinta.
Usar DocInclusionPredicate
La primera forma de ocultar un endpoint en Swagger es usar DocInclusionPredicate().
DocInclusionPredicate() es un delegado que se invoca para cada ApiDescription que expone la aplicación. Recibe dos parámetros: docName y apiDesc. docName hace referencia al nombre del documento de Swagger, lo que puede ser útil para distinguir entre varios documentos de Swagger.
Por su parte, el parámetro apiDesc representa la descripción de la API, que contiene información sobre el endpoint que se está procesando.

Ebook gratis
¿Tu Web API está lista para producción?
33 puntos que comprobar antes de desplegarla, con la solución de cada uno. Un PDF gratuito de 76 páginas para .NET 10.
El ebook está en inglés.
Descarga la checklist gratisPDF gratuito. Un solo correo para enviártelo. Puedes darte de baja cuando quieras.
Podemos definir DocInclusionPredicate() al configurar Swagger y personalizarlo para filtrar los endpoints y las operaciones que se incluyen en la documentación de Swagger generada.
Supongamos que queremos ocultar el primer endpoint, llamado GetWeatherForecast:
builder.Services.AddSwaggerGen(c =>
{
c.DocInclusionPredicate((docName, apiDesc) =>
{
var routeTemplate = apiDesc.RelativePath;
if (routeTemplate == "WeatherForecast/GetWeatherForecast")
return false;
return true;
});
});
Primero, guardamos en la variable routeTemplate la ruta relativa del endpoint de la API que se está evaluando. Después, comprobamos si el routeTemplate del endpoint coincide con "WeatherForecast/GetWeatherForecast".
Si coincide, devolvemos false, lo que significa que el endpoint de la API se excluirá de la documentación de Swagger. En cualquier otro caso, devolvemos true, es decir, el endpoint se incluirá en la documentación de Swagger.
Usar el atributo NonAction
Otra cosa que podemos hacer para ocultar un endpoint en Swagger es aplicar el atributo NonAction al método de ese endpoint:
[HttpGet("GetMethodOne")]
[NonAction]
public IEnumerable<WeatherForecast> GetMethodOne()
{
return GetWeatherForecastData();
}
Con el atributo NonAction indicamos que el método del controlador no es un método de acción. Como Swagger se basa en las acciones de la API para generar la documentación, durante el análisis ignorará cualquier endpoint que marquemos con este atributo y, por tanto, el endpoint no aparecerá en la documentación de Swagger. Además, la acción deja de estar disponible públicamente.
Solo podemos aplicar este atributo a los endpoints del controlador, no al controlador entero.
Usar el atributo ApiExplorerSettings con el parámetro IgnoreApi
Otra forma de ocultar un endpoint en Swagger es usar el atributo ApiExplorerSettings con el parámetro IgnoreApi establecido en true:
[HttpGet("GetMethodTwo")]
[ApiExplorerSettings(IgnoreApi = true)]
public IEnumerable<WeatherForecast> GetMethodTwo()
{
return GetWeatherForecastData();
}
Con el atributo [ApiExplorerSettings(IgnoreApi = true)], le indicamos al API Explorer, que es el que proporciona los endpoints a la documentación de Swagger, que excluya un endpoint concreto de la documentación generada.
A diferencia del atributo NonAction, este podemos usarlo a nivel de controlador y ocultar todos los endpoints que contiene.
Usar IActionModelConvention
Otra opción que puede venir bien cuando queremos ocultar un endpoint en Swagger es IActionModelConvention.
En general, IActionModelConvention es una interfaz que podemos usar para aplicar convenciones a métodos de acción individuales. Para usarla, tenemos que implementar la interfaz y el método Apply(), que recibe un objeto ActionModel como parámetro y le aplica las convenciones que queramos:
using Microsoft.AspNetCore.Mvc.ApplicationModels;
public class HideControllerConvention : IActionModelConvention
{
public void Apply(ActionModel action)
{
if (action.ActionName == "GetMethodThree")
{
action.ApiExplorer.IsVisible = false;
}
}
}
En nuestro caso, queremos ocultar el endpoint GetMethodThree. Primero, comprobamos la propiedad ActionName de la acción para encontrar el nombre de acción que buscamos y, una vez que lo tenemos, establecemos su visibilidad en false.
Ahora que hemos definido la convención, también tenemos que registrarla en Program.cs al añadir los controladores para que todo funcione como esperamos:
builder.Services.AddControllers(s => s.Conventions.Add(new HideControllerConvention() ));
Usar IDocumentFilter
La última vía que vamos a seguir para ocultar el endpoint en Swagger es usar IDocumentFilter.
La interfaz IDocumentFilter forma parte del espacio de nombres Swashbuckle.AspNetCore.SwaggerGen y nos permite modificar el documento de Swagger generado antes de que se muestre. En nuestro caso, creamos la clase SwaggerDocumentFilter, que implementa la interfaz IDocumentFilter:
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.SwaggerGen;
public class SwaggerDocumentFilter : IDocumentFilter
{
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
swaggerDoc.Paths.Remove("/WeatherForecast/GetMethodFour");
}
}
Dentro del método Apply(), tenemos acceso a OpenApiDocument y a DocumentFilterContext. OpenApiDocument representa el documento de Swagger generado, y DocumentFilterContext nos proporciona contexto adicional durante el proceso de generación del documento.
Al llamar a swaggerDoc.Paths.Remove("/WeatherForecast/GetMethodFour"), eliminamos de la propiedad Paths del documento de Swagger la entrada de este endpoint concreto. Así nos aseguramos de que el método quede oculto en la documentación de Swagger generada.
Eliminar una ruta es solo una de las tareas que hace un filtro. Otro punto de enganche de la misma familia, IOperationFilter, es el que usamos para añadir un parámetro de encabezado a todos los endpoints.
Por último, tenemos que añadir el filtro de documentos al configurar Swagger en 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;
});
});
Ahora, si volvemos a ejecutar la aplicación, vemos que el archivo de especificación generado no muestra ninguno de los endpoints:

El grupo WeatherForecast vacío y su esquema siguen apareciendo porque el filtro de documentos solo elimina la ruta, no la etiqueta ni el esquema que Swashbuckle generó para ella.

Ebook gratis
¿Tu Web API está lista para producción?
33 puntos que comprobar antes de desplegarla, con la solución de cada uno. Un PDF gratuito de 76 páginas para .NET 10.
El ebook está en inglés.
Descarga la checklist gratisPDF gratuito. Un solo correo para enviártelo. Puedes darte de baja cuando quieras.
¿Cómo ocultar un endpoint con el generador de OpenAPI integrado?
Microsoft.AspNetCore.OpenApi es el generador que instala hoy la plantilla Web API, y todas las técnicas anteriores tienen su equivalente en él. Ya viene instalado en un proyecto nuevo, y por eso en la sección de configuración hemos tenido que añadir Swashbuckle a mano.
Las tres técnicas del API Explorer no necesitan absolutamente ningún cambio. [NonAction], [ApiExplorerSettings(IgnoreApi = true)] y una IActionModelConvention ocultan aquí una acción exactamente igual que con Swashbuckle, porque ninguna de ellas toca el generador.
Las dos propias de Swashbuckle tienen un reemplazo directo. DocInclusionPredicate() pasa a ser el delegado ShouldInclude de OpenApiOptions, y IDocumentFilter pasa a ser IOpenApiDocumentTransformer, cuyo método TransformAsync() recibe el mismo OpenApiDocument y elimina rutas de la misma forma.
Con ShouldInclude hay una trampa en la que es fácil caer. El predicado que se le asigna reemplaza al predeterminado en lugar de sumarse a él, y es ese predicado predeterminado el que mantiene los endpoints agrupados en sus propios documentos. Si lo sobrescribes sin repetir esa comprobación, todos los endpoints agrupados aparecen en todos los documentos.
Todo esto se configura en Program.cs:
builder.Services.AddOpenApi(options =>
{
options.ShouldInclude = apiDesc => apiDesc.RelativePath != "WeatherForecast/GetWeatherForecast";
options.AddDocumentTransformer<HideEndpointDocumentTransformer>();
});
Y el transformador sustituye al filtro de documentos:
using Microsoft.AspNetCore.OpenApi;
using Microsoft.OpenApi;
public class HideEndpointDocumentTransformer : IOpenApiDocumentTransformer
{
public Task TransformAsync(OpenApiDocument document,
OpenApiDocumentTransformerContext context,
CancellationToken cancellationToken)
{
document.Paths.Remove("/WeatherForecast/GetMethodFour");
return Task.CompletedTask;
}
}
Si lo ponemos todo junto, una sola tabla recoge cada técnica en los dos generadores e indica si el endpoint sigue respondiendo después de ocultarlo:
| Qué ocultar | Con Swashbuckle | Con el generador integrado | ¿Sigue accesible por HTTP? |
|---|---|---|---|
| Una acción | [ApiExplorerSettings(IgnoreApi = true)] | El mismo atributo | Sí |
| Una acción, y además desactivarla | [NonAction] | El mismo atributo | No, la ruta devuelve 404 |
| Todas las acciones de un controlador | [ApiExplorerSettings(IgnoreApi = true)] en la clase | El mismo atributo | Sí |
| Un endpoint de API mínima | .ExcludeFromDescription() | .ExcludeFromDescription() | Sí |
| Acciones que cumplen una regla que escribimos | DocInclusionPredicate((docName, apiDesc) => …) | options.ShouldInclude = apiDesc => … | Sí |
| Acciones que cumplen una regla, antes de que se ejecute el generador | IActionModelConvention que establece ApiExplorer.IsVisible en false | La misma convención | Sí |
| Una ruta que ya está en el documento terminado | IDocumentFilter que llama a Paths.Remove(path) | IOpenApiDocumentTransformer que llama a Paths.Remove(path) | Sí |
Los endpoints de API mínimas tienen su propia vía: app.MapGet("/internal", …).ExcludeFromDescription() deja un endpoint fuera del documento con los dos generadores. También existe un atributo [ExcludeFromDescription], pero se trata de metadatos de API mínimas. Aplicarlo a una acción de un controlador MVC no tiene ningún efecto, y la acción sigue en el documento.
Si lo que realmente necesitamos es “documentación interna y pública a partir de una sola API” y no “ocultar esto para siempre”, AddOpenApi("internal") junto con AddOpenApi("v1") nos da dos documentos, y [ApiExplorerSettings(GroupName = "internal")] en un controlador decide en cuál de ellos acaba un endpoint. Un transformador de documentos registrado en un documento no se ejecuta en el otro.
El generador integrado escribe el documento y nada más. app.MapOpenApi() lo sirve en /openapi/v1.json y no hay ninguna página que mirar, así que, para ver el resultado, hay que leer el JSON o añadir un paquete de interfaz de usuario como Swagger UI o Scalar. La propia guía de Microsoft para generar documentos OpenAPI describe esa misma separación entre generar el documento y mostrarlo.
Dejar una operación completa fuera del documento es la mitad de este trabajo, y la otra mitad consiste en ignorar propiedades del modelo con Swagger, algo que oculta un campo dentro del esquema en lugar de la operación en sí.
¿Cuándo conviene usar cada método?
Empieza por el atributo, porque es lo mínimo que resuelve el problema. [ApiExplorerSettings(IgnoreApi = true)] oculta una acción, o todas las acciones de un controlador si lo aplicamos a la clase, y no necesita configuración en ninguna otra parte de la aplicación.
Recurre a [NonAction] solo cuando quieras que el endpoint desaparezca, no simplemente que quede oculto. Es la única opción de las que vemos aquí que también elimina la ruta, así que la URL responde con 404 en lugar de devolver datos.
Usa una convención cuando la regla se refiera a las propias acciones: ocultar todo lo que hay en un espacio de nombres, todo lo que lleva un atributo marcador, todo lo que pertenece a un equipo interno. Se ejecuta una sola vez al arrancar, y ningún generador llega a ver esas acciones.
Usa ShouldInclude o DocInclusionPredicate() cuando el mismo endpoint deba aparecer en un documento y no en otro, y un transformador o un filtro de documentos cuando la regla se refiera al documento terminado y no al endpoint.
En los casos sencillos en los que necesitamos ocultar endpoints concretos, puede bastar con usar el parámetro IgnoreApi del atributo ApiExplorerSettings o el atributo NonAction. Son los más fáciles de usar.
Conviene tener en cuenta que el atributo NonAction saca el endpoint de la documentación y, además, lo desactiva por completo, de modo que no podemos llegar a él con llamadas HTTP, a diferencia de las demás técnicas, con las que el endpoint queda oculto en la documentación, pero sigue siendo accesible para las llamadas HTTP dirigidas a él.
En situaciones que requieren filtrados o transformaciones más avanzados, IActionModelConvention puede ser una opción excelente. Podemos ocultar un endpoint en Swagger según cualquier filtro personalizado sobre todas las propiedades disponibles en la clase ActionModel.
Se ejecutan en momentos distintos. A DocInclusionPredicate() se le pregunta por un endpoint cada vez, antes de que exista el documento, y responde sí o no. Un IDocumentFilter se ejecuta una sola vez al final, con el documento terminado, cada ApiDescription incluida y el nombre del documento a su disposición, y edita lo que ya existe; por eso puede eliminar una ruta que el predicado ya había dejado pasar. Una ventaja de DocInclusionPredicate() es que se define directamente al configurar Swagger y no requiere implementar ninguna interfaz adicional.
Conclusión
En este artículo, hemos visto distintas formas de ocultar endpoints de la API en la documentación de Swagger. Hemos analizado el uso de DocInclusionPredicate() para una configuración directa, así como opciones más sencillas, como el parámetro IgnoreApi y el atributo NonAction. Por último, hemos tratado una personalización más avanzada con las interfaces IDocumentFilter y IActionModelConvention, que nos dan distintas alternativas para ocultar endpoints. Todas ellas, o sus equivalentes en el generador integrado, siguen siendo válidas en .NET 10, tanto si generamos el documento con Swashbuckle como si lo hacemos con el paquete Microsoft.AspNetCore.OpenApi que instala hoy la plantilla Web API.
Probado con .NET 10.0.10, Swashbuckle.AspNetCore 10.2.3 y Microsoft.AspNetCore.OpenApi 10.0.12.