Introducción a NSwag y ASP.NET Core

Por Christoph Nienaber, Rico Suter y Dave Brock

Vea o descargue el código de ejemplo (cómo descargarlo)

NSwag ofrece las siguientes capacidades:

  • Capacidad de usar la interfaz de usuario y el generador de Swagger.
  • Capacidad de generar código con flexibilidad.

Con NSwag, no es necesario que exista una API; se pueden usar API de terceros que incluyan Swagger y que generen una implementación de cliente. NSwag permite acelerar el ciclo de desarrollo y adaptarse fácilmente a los cambios de API.

Instalación del paquete

Instalar NSwag en:

  • Generar la especificación de Swagger para la API web implementada.
  • Proporcionar la interfaz de usuario de Swagger para examinar y probar la API web.
  • Sirve a Redoc para agregar documentación de API para la API web.

Para usar NSwag con middleware de ASP.NET Core, instale el paquete NuGet NSwag.AspNetCore. Este paquete contiene el middleware para generar y proporcionar la especificación de Swagger, la interfaz de usuario de Swagger (v2 y v3) y la interfaz de usuario de ReDoc. NSwag 14 solo admite v3 de la especificación de interfaz de usuario de Swagger.

Use uno de los siguientes métodos para instalar el paquete NuGet de NSwag:

  • En la ventana Consola del Administrador de paquetes:

    • Vaya a Vista>Otras ventanas>Consola del Administrador de paquetes.

    • Vaya al directorio en el que está el archivo NSwagSample.csproj.

    • Ejecute el siguiente comando:

      Install-Package NSwag.AspNetCore
      
  • En el cuadro de diálogo Administrar paquetes NuGet:

    • Haga clic con el botón derecho en el proyecto en el Explorador de soluciones>Administrar paquetes NuGet.
    • Establezca el origen del paquete en "nuget.org".
    • Escriba "NSwag.AspNetCore" en el cuadro de búsqueda.
    • Seleccione el paquete "NSwag.AspNetCore" en la pestaña Examinar y haga clic en Instalar.

Agregar y configurar el middleware de Swagger

Para agregar y configurar Swagger en su aplicación de ASP.NET Core, realice los siguientes pasos:

  • Agregue el generador de OpenApi a la colección de servicios en Program.cs:
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddOpenApiDocument();
  • Habilite el middleware para atender la especificación de OpenApi generada, la interfaz de usuario de Swagger y la interfaz de usuario de Redoc, también en Program.cs:
if (app.Environment.IsDevelopment())
{
    // Add OpenAPI 3.0 document serving middleware
    // Available at: http://localhost:<port>/swagger/v1/swagger.json
    app.UseOpenApi();

    // Add web UIs to interact with the document
    // Available at: http://localhost:<port>/swagger
    app.UseSwaggerUi(); // UseSwaggerUI Protected by if (env.IsDevelopment())
}
  • Inicie la aplicación. Vaya a:
    • http://localhost:<port>/swagger para ver la interfaz de usuario de Swagger.
    • http://localhost:<port>/swagger/v1/swagger.json para ver la especificación de Swagger.

Generación de código

Para aprovechar las capacidades de generación de código de NSwag, elija una de las siguientes opciones:

Generación de código con NSwagStudio

  • Instale NSwagStudio siguiendo las instrucciones del repositorio de GitHub de NSwagStudio. En la página de la versión NSwag, es posible descargar una versión de xcopy que se puede iniciar sin privilegios de administrador y de instalación.
  • Inicie NSwagStudio y escriba la URL del archivo swagger.json en el cuadro de texto URL de especificación de Swagger. Por ejemplo: http://localhost:5232/swagger/v1/swagger.json.
  • Haga clic en el botón Crear copia local para generar una representación JSON de la especificación de Swagger.

NSwag Studio importa la especificación y exporta un cliente CSharp.

  • En el área Salidas, haga clic en la casilla CSharp Client (Cliente de CSharp). En función del proyecto, también puede elegir TypeScript Client (Cliente de TypeScript) o CSharp Web API Controller (Controlador de API web de CSharp). Si selecciona CSharp Web API Controller (Controlador de API web de CSharp), una especificación de servicio volverá a generar el servicio a modo de generación inversa.
  • Haga clic en Generate Outputs (Generar salidas) para producir una implementación completa del cliente de C# del proyecto TodoApi.NSwag. Para ver el código de cliente generado, haga clic en la pestaña CSharp Client (Cliente de CSharp):
namespace MyNamespace
{
    using System = global::System;

    [System.CodeDom.Compiler.GeneratedCode("NSwag", "14.0.1.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")]
    public partial class TodoClient
    {
    #pragma warning disable 8618 // Set by constructor via BaseUrl property
        private string _baseUrl;
    #pragma warning restore 8618 // Set by constructor via BaseUrl property
        private System.Net.Http.HttpClient _httpClient;
        private static System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _settings = new System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(CreateSerializerSettings, true);

        public TodoClient(System.Net.Http.HttpClient httpClient)
        {
            BaseUrl = "http://localhost:5232";
            _httpClient = httpClient;
        }

        private static Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings()
        {
            var settings = new Newtonsoft.Json.JsonSerializerSettings();
            UpdateJsonSerializerSettings(settings);
            return settings;
        }

        public string BaseUrl
        {
            get { return _baseUrl; }
            set
            {
                _baseUrl = value;
                if (!string.IsNullOrEmpty(_baseUrl) && !_baseUrl.EndsWith("/"))
                    _baseUrl += '/';
            }
        }
        // code omitted for brevity

Sugerencia

El código de cliente de C# se genera en función de las selecciones en la pestaña Settings (Configuración). Modifique esta configuración para realizar tareas como cambiar el nombre del espacio de nombres predeterminado y generar un método sincrónico.

  • Copie el código de C# generado en un archivo del proyecto de cliente que usará la API.
  • Empiece a consumir la Web API:
var todoClient = new TodoClient(new HttpClient());

// Gets all to-dos from the API
var allTodos = await todoClient.GetAsync();

// Create a new TodoItem, and save it via the API.
await todoClient.CreateAsync(new TodoItem());

// Get a single to-do by ID
var foundTodo = await todoClient.GetByIdAsync(1);

Personalización de la documentación de API

OpenApi proporciona opciones para documentar el modelo de objetos de cara a facilitar el consumo de Web API.

Información y descripción de la API

En Program.cs, actualice AddOpenApiDocument para configurar la información del documento de la API web e incluya más información, como el autor, la licencia y la descripción. Importe primero el espacio de nombres NSwag para usar las clases OpenApi.

using NSwag;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenApiDocument(options => {
     options.PostProcess = document =>
     {
         document.Info = new OpenApiInfo
         {
             Version = "v1",
             Title = "ToDo API",
             Description = "An ASP.NET Core Web API for managing ToDo items",
             TermsOfService = "https://example.com/terms",
             Contact = new OpenApiContact
             {
                 Name = "Example Contact",
                 Url = "https://example.com/contact"
             },
             License = new OpenApiLicense
             {
                 Name = "Example License",
                 Url = "https://example.com/license"
             }
         };
     };
});

La interfaz de usuario de Swagger muestra información de la versión:

Interfaz de usuario de Swagger con información de la versión.

comentarios XML

Para habilitar los comentarios XML, realice los siguientes pasos:

  • Haga clic con el botón derecho en el Explorador de soluciones y seleccione Edit <project_name>.csproj.
  • Agregue manualmente las líneas resaltadas al archivo .csproj:
<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

Puede habilitar los comentarios XML para proporcionar información de depuración para miembros y tipos públicos sin documentación. Los miembros y tipos que no estén documentados se indican por medio del mensaje de advertencia. Por ejemplo, el siguiente mensaje señala una infracción con el código de advertencia 1591:

warning CS1591: Missing XML comment for publicly visible type or member 'TodoContext'

Para eliminar las advertencias a nivel de proyecto, defina una lista delimitada por punto y coma de códigos de advertencia que se deban omitir en el archivo de proyecto. Al anexar los códigos de advertencia a $(NoWarn);, se aplican también los valores predeterminados de C#.

<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
  <NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>

Para suprimir las advertencias solo para miembros específicos, incluya el código en directivas de preprocesador de advertencias #pragma. Este enfoque es útil para el código que no debe exponerse mediante los documentos de API. En el ejemplo siguiente, se omite el código de advertencia CS1591 para toda la clase TodoContext. La ejecución del código de advertencia se restaura al cerrar la definición de clase. Especifique varios códigos de advertencia con una lista delimitada por comas.

namespace NSwagSample.Models;

#pragma warning disable CS1591
public class TodoContext : DbContext
{
    public TodoContext(DbContextOptions<TodoContext> options) : base(options) { }

    public DbSet<TodoItem> TodoItems => Set<TodoItem>();
}
#pragma warning restore CS1591

Anotaciones de datos

Marque el modelo con atributos, que se encuentran en el espacio de nombres System.ComponentModel.DataAnnotations, para controlar los componentes de la interfaz de usuario de Swagger.

Agregue el atributo [Required] a la propiedad Name de la clase TodoItem:

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace NSwagSample.Models;

public class TodoItem
{
    public long Id { get; set; }

    [Required]
    public string Name { get; set; } = null!;

    [DefaultValue(false)]
    public bool IsComplete { get; set; }
}

La presencia de este atributo cambia el comportamiento de la UI y modifica el esquema JSON subyacente:

"TodoItem": {
  "type": "object",
  "additionalProperties": false,
  "required": [
    "name"
  ],
  "properties": {
    "id": {
      "type": "integer",
      "format": "int64"
    },
    "name": {
      "type": "string",
      "minLength": 1
    },
    "isComplete": {
      "type": "boolean",
      "default": false
    }
  }
}

A medida que aumenta el uso de anotaciones de datos en la API web, la interfaz de usuario y las páginas de ayuda de la API pasan a ser más descriptivas y útiles.

Describir los tipos de respuesta

Lo que más preocupa a los desarrolladores que consumen una API web es lo que se devuelve; sobre todo, los tipos de respuesta y los códigos de error (si no son los habituales). Los tipos de respuesta y los códigos de error se indican en las anotaciones de datos y los comentarios XML.

La acción Create devuelve un código de estado HTTP 201 cuando se ha ejecutado correctamente. Cuando el cuerpo de solicitud enviado es null, se devuelve un código de estado HTTP 400. Sin la documentación correcta en la interfaz de usuario de Swagger, el consumidor no dispone de la información necesaria de estos resultados esperados. Corrija este problema agregando las líneas resaltadas en el siguiente ejemplo:

/// <summary>
/// Creates a TodoItem.
/// </summary>
/// <param name="item"></param>
/// <returns>A newly created TodoItem</returns>
/// <remarks>
/// Sample request:
///
///     POST /Todo
///     {
///        "id": 1,
///        "name": "Item #1",
///        "isComplete": true
///     }
///
/// </remarks>
/// <response code="201">Returns the newly created item</response>
/// <response code="400">If the item is null</response>
[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> Create(TodoItem item)
{
    _context.TodoItems.Add(item);
    await _context.SaveChangesAsync();

    return CreatedAtAction(nameof(Get), new { id = item.Id }, item);
}

Ahora, la interfaz de usuario de Swagger documenta de forma clara los códigos de respuesta HTTP esperados (y también se muestran los comentarios XML):

Interfaz de usuario de Swagger en la que se muestra la descripción de la clase de respuesta POST

Las convenciones se pueden usar como alternativa a la representación explícita de acciones individuales con [ProducesResponseType]. Para más información, consulte Uso de convenciones de API web.

Redoc

Redoc es una alternativa a la interfaz de usuario de Swagger. Es similar porque también proporciona una página de documentación para la API web mediante la especificación OpenAPI. La diferencia es que la interfaz de usuario de Redoc se centra más en la documentación y no proporciona una interfaz de usuario interactiva para probar la API.

Para habilitar Redoc, agregue su middleware a Program.cs:

if (app.Environment.IsDevelopment())
{
    // Add OpenAPI 3.0 document serving middleware
    // Available at: http://localhost:<port>/swagger/v1/swagger.json
    app.UseOpenApi();

    // Add web UIs to interact with the document
    // Available at: http://localhost:<port>/swagger
    app.UseSwaggerUi(); // UseSwaggerUI is called only in Development.
    
    // Add ReDoc UI to interact with the document
    // Available at: http://localhost:<port>/redoc
    app.UseReDoc(options =>
    {
        options.Path = "/redoc";
    });
}

Ejecute la aplicación y navegue a http://localhost:<port>/redoc para ver la interfaz de usuario de Redoc:

Documentación de puesta al día de la API de ejemplo.

Por Christoph Nienaber, Rico Suter y Dave Brock

Vea o descargue el código de ejemplo (cómo descargarlo)

NSwag ofrece las siguientes capacidades:

  • Capacidad de usar la interfaz de usuario y el generador de Swagger.
  • Capacidad de generar código con flexibilidad.

Con NSwag, no es necesario que exista una API; se pueden usar API de terceros que incluyan Swagger y que generen una implementación de cliente. NSwag permite acelerar el ciclo de desarrollo y adaptarse fácilmente a los cambios de API.

Registro del middleware de NSwag

Registre el middleware de NSwag para:

  • Generar la especificación de Swagger para la API web implementada.
  • Proporcionar la interfaz de usuario de Swagger para examinar y probar la API web.

Para usar NSwag con middleware de ASP.NET Core, instale el paquete NuGet NSwag.AspNetCore. Este paquete contiene el middleware para generar y proporcionar la especificación de Swagger, la interfaz de usuario de Swagger (v2 y v3) y la interfaz de usuario de ReDoc.

Use uno de los siguientes métodos para instalar el paquete NuGet de NSwag:

  • En la ventana Consola del Administrador de paquetes:

    • Vaya a Vista>Otras ventanas>Consola del Administrador de paquetes.

    • Vaya al directorio en el que está el archivo TodoApi.csproj.

    • Ejecute el siguiente comando:

      Install-Package NSwag.AspNetCore
      
  • En el cuadro de diálogo Administrar paquetes NuGet:

    • Haga clic con el botón derecho en el proyecto en el Explorador de soluciones>Administrar paquetes NuGet.
    • Establezca el origen del paquete en "nuget.org".
    • Escriba "NSwag.AspNetCore" en el cuadro de búsqueda.
    • Seleccione el paquete "NSwag.AspNetCore" en la pestaña Examinar y haga clic en Instalar.

Agregar y configurar el middleware de Swagger

Para agregar y configurar Swagger en su aplicación de ASP.NET Core, realice los siguientes pasos:

  • En el método Startup.ConfigureServices, registre los servicios necesarios de Swagger:
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<TodoContext>(opt =>
        opt.UseInMemoryDatabase("TodoList"));
    services.AddMvc();

    // Register the Swagger services
    services.AddSwaggerDocument();
}
  • En el método Startup.Configure, habilite el middleware para servir la especificación y la interfaz de usuario de Swagger:
public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles();

    // Register the Swagger generator and the Swagger UI middlewares
    app.UseOpenApi();
    app.UseOpenApi();
    if (env.IsDevelopment())
    {
        app.UseSwaggerUi3();
    }
    app.UseMvc();
}
  • Inicie la aplicación. Vaya a:
    • http://localhost:<port>/swagger para ver la interfaz de usuario de Swagger.
    • http://localhost:<port>/swagger/v1/swagger.json para ver la especificación de Swagger.

Generación de código

Para aprovechar las capacidades de generación de código de NSwag, elija una de las siguientes opciones:

Generación de código con NSwagStudio

  • Instale NSwagStudio siguiendo las instrucciones del repositorio de GitHub de NSwagStudio. En la página de la versión NSwag, puede descargar una versión de XCOPY que se puede iniciar sin privilegios de administrador y de instalación.

  • Inicie NSwagStudio y escriba la URL del archivo swagger.json en el cuadro de texto Swagger Specification URL (URL de especificación de Swagger). Por ejemplo, http://localhost:44354/swagger/v1/swagger.json.

  • Haga clic en el botón Crear copia local para generar una representación JSON de la especificación de Swagger.

    Creación de una copia local de la especificación de Swagger

  • En el área Salidas, haga clic en la casilla CSharp Client (Cliente de CSharp). En función del proyecto, también puede elegir TypeScript Client (Cliente de TypeScript) o CSharp Web API Controller (Controlador de API web de CSharp). Si selecciona CSharp Web API Controller (Controlador de API web de CSharp), una especificación de servicio volverá a generar el servicio a modo de generación inversa.

  • Haga clic en Generate Outputs (Generar salidas) para producir una implementación completa del cliente de C# del proyecto TodoApi.NSwag. Para ver el código de cliente generado, haga clic en la pestaña CSharp Client (Cliente de CSharp):

//----------------------
// <auto-generated>
//     Generated using the NSwag toolchain v12.0.9.0 (NJsonSchema v9.13.10.0 (Newtonsoft.Json v11.0.0.0)) (http://NSwag.org)
// </auto-generated>
//----------------------

namespace MyNamespace
{
    #pragma warning disable

    [System.CodeDom.Compiler.GeneratedCode("NSwag", "12.0.9.0 (NJsonSchema v9.13.10.0 (Newtonsoft.Json v11.0.0.0))")]
    public partial class TodoClient
    {
        private string _baseUrl = "https://localhost:44354";
        private System.Net.Http.HttpClient _httpClient;
        private System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _settings;

        public TodoClient(System.Net.Http.HttpClient httpClient)
        {
            _httpClient = httpClient;
            _settings = new System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(() =>
            {
                var settings = new Newtonsoft.Json.JsonSerializerSettings();
                UpdateJsonSerializerSettings(settings);
                return settings;
            });
        }

        public string BaseUrl
        {
            get { return _baseUrl; }
            set { _baseUrl = value; }
        }

        // code omitted for brevity

Sugerencia

El código de cliente de C# se genera en función de las selecciones en la pestaña Settings (Configuración). Modifique esta configuración para realizar tareas como cambiar el nombre del espacio de nombres predeterminado y generar un método sincrónico.

  • Copie el código de C# generado en un archivo del proyecto de cliente que usará la API.
  • Empiece a consumir la Web API:
 var todoClient = new TodoClient();

// Gets all to-dos from the API
 var allTodos = await todoClient.GetAllAsync();

 // Create a new TodoItem, and save it via the API.
var createdTodo = await todoClient.CreateAsync(new TodoItem());

// Get a single to-do by ID
var foundTodo = await todoClient.GetByIdAsync(1);

Personalización de la documentación de API

Swagger proporciona opciones para documentar el modelo de objetos de cara a facilitar el consumo de Web API.

Información y descripción de la API

En el método Startup.ConfigureServices, la acción de configuración que se pasa al método AddSwaggerDocument agrega información, como el autor, la licencia y la descripción:

services.AddSwaggerDocument(config =>
{
    config.PostProcess = document =>
    {
        document.Info.Version = "v1";
        document.Info.Title = "ToDo API";
        document.Info.Description = "A simple ASP.NET Core web API";
        document.Info.TermsOfService = "None";
        document.Info.Contact = new NSwag.OpenApiContact
        {
            Name = "Shayne Boyer",
            Email = string.Empty,
            Url = "https://twitter.com/spboyer"
        };
        document.Info.License = new NSwag.OpenApiLicense
        {
            Name = "Use under LICX",
            Url = "https://example.com/license"
        };
    };
});

La interfaz de usuario de Swagger muestra información de la versión:

Interfaz de usuario de Swagger con información de la versión

comentarios XML

Para habilitar los comentarios XML, realice los siguientes pasos:

  • Haga clic con el botón derecho en el Explorador de soluciones y seleccione Edit <project_name>.csproj.
  • Agregue manualmente las líneas resaltadas al archivo .csproj:
<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
  <NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>

Anotaciones de datos

Dado que NSwag usa Reflection y el tipo de valor devuelto recomendado para acciones de API web es ActionResult<T>, solo puede inferir el tipo de valor devuelto definido por T. No puede inferir automáticamente ningún otro tipo de valor devuelto.

Considere el ejemplo siguiente:

[HttpPost]
public ActionResult<TodoItem> Create(TodoItem item)
{
    _context.TodoItems.Add(item);
    _context.SaveChanges();

    return CreatedAtRoute("GetTodo", new { id = item.Id }, item);
}

La acción anterior devuelve ActionResult<T>. Dentro de la acción, se devuelve CreatedAtRoute. Como el controlador tiene el atributo [ApiController], también es posible una respuesta BadRequest. Para obtener más información, consulte Respuestas HTTP 400 automáticas. Use las anotaciones de datos para indicar a los clientes qué códigos de estado HTTP se sabe que esta acción devuelve. Marque la acción con los siguientes atributos:

[ProducesResponseType(StatusCodes.Status201Created)]     // Created
[ProducesResponseType(StatusCodes.Status400BadRequest)]  // BadRequest

En ASP.NET Core 2.2 o versiones posteriores, puede usar las convenciones en lugar de decorar explícitamente acciones individuales con [ProducesResponseType]. Para más información, consulte Uso de convenciones de API web.

Ahora, el generador de Swagger puede describir con precisión esta acción y los clientes generados sabrán lo que reciben cuando llamen al punto de conexión. Le recomendamos que marque todas las acciones con estos atributos.

Para obtener instrucciones sobre las respuestas HTTP que deben devolver las acciones de la API, consulte RFC 9110: Semántica HTTP (Sección 9.3: Definiciones de métodos).