Tutorial: Generación de un cliente de API REST
Una aplicación que consume una API REST es un escenario muy común. Normalmente, debe generar código de cliente que la aplicación pueda usar para llamar a la API REST. En este tutorial, aprenderá a generar automáticamente el cliente de la API REST durante el proceso de compilación mediante MSBuild. Usará NSwag, una herramienta que genera código de cliente para una API REST.
El código de ejemplo completo está disponible en Generación de clientes de API de REST en el repositorio de ejemplos de .NET en GitHub.
En el ejemplo se muestra una aplicación de consola que consume la API pública Pet Store, que publica una especificación de OpenAPI .
En el tutorial se asumen conocimientos básicos de los términos de MSBuild, como tareas, destinos, propiedades o entornos de ejecución; para obtener la información general necesaria, consulte el artículo sobre los conceptos de MSBuild .
Cuando quiera ejecutar una herramienta de línea de comandos como parte de una compilación, hay dos enfoques que se deben tener en cuenta. Una consiste en usar la tarea de MSBuildExec, que permite ejecutar una herramienta de línea de comandos y especificar sus parámetros. El otro método consiste en crear una tarea personalizada derivada de ToolTask, lo que proporciona un mayor control.
Prerrequisitos
Debe comprender los conceptos de MSBuild, como tareas, destinos y propiedades. Vea Conceptos de MSBuild.
Los ejemplos requieren MSBuild, que se instala con Visual Studio, pero también se pueden instalar por separado. Vea Descargar MSBuild sin Visual Studio.
Opción 1: Tarea Exec
La tarea Exec simplemente invoca el proceso especificado con los argumentos especificados, espera a que se complete y, a continuación, devuelve true
si el proceso se completa correctamente y false
si se produce un error.
La generación de código NSwag se puede usar desde MSBuild; consulte NSwag.MSBuild.
El código completo está en la carpeta PetReaderExecTaskExample; puede descargar y echar un vistazo. En este tutorial, avanzarás paso a paso y aprenderás los conceptos a lo largo del camino.
Cree una nueva aplicación de consola denominada
PetReaderExecTaskExample
. Utilice .NET 6.0 o posterior.Cree otro proyecto en la misma solución:
PetShopRestClient
(esta solución contendrá el cliente generado como biblioteca). Para este proyecto, use .NET Standard 2.1. El cliente generado no se compila en .NET Standard 2.0.En el proyecto
PetReaderExecTaskExample
, agregue una dependencia al proyectoPetShopRestClient
.En el proyecto de
PetShopRestClient
, incluya los siguientes paquetes NuGet:- Nswag.MSBuild, que permite el acceso al generador de código desde MSBuild.
- Newtonsoft.Json, necesario para compilar el cliente generado
- System.ComponentModel.Annotations, necesario para compilar el cliente generado
En el proyecto de
PetShopRestClient
, agregue una carpeta (denominadaPetShopRestClient
) para la generación de código y elimine la Class1.cs que se generó automáticamente.Cree un archivo de texto denominado petshop-openapi-spec.json en la raíz del proyecto. Copie la especificación de OpenAPI de aquí y guárdela en el archivo. Es mejor copiar una instantánea de la especificación en lugar de leerla en línea durante la compilación. Siempre se desea una compilación reproducible y consistente que dependa solo de la entrada. El consumo de la API directamente podría transformar una compilación que funciona hoy en día en una compilación que produce un error mañana desde el mismo origen. La instantánea guardada en petshop-openapi-spec.json nos permitirá seguir teniendo una versión que se compile incluso si cambia la especificación.
A continuación, modifique PetShopRestClient.csproj y agregue un destino de MSBuild para generar el cliente durante el proceso de compilación.
En primer lugar, agregue algunas propiedades útiles para la generación de clientes:
<PropertyGroup> <PetOpenApiSpecLocation>petshop-openapi-spec.json</PetOpenApiSpecLocation> <PetClientClassName>PetShopRestClient</PetClientClassName> <PetClientNamespace>PetShopRestClient</PetClientNamespace> <PetClientOutputDirectory>PetShopRestClient</PetClientOutputDirectory> </PropertyGroup>
Agregue los siguientes destinos:
<Target Name="generatePetClient" BeforeTargets="CoreCompile" Inputs="$(PetOpenApiSpecLocation)" Outputs="$(PetClientOutputDirectory)\$(PetClientClassName).cs"> <Exec Command="$(NSwagExe) openapi2csclient /input:$(PetOpenApiSpecLocation) /classname:$(PetClientClassName) /namespace:$(PetClientNamespace) /output:$(PetClientOutputDirectory)\$(PetClientClassName).cs" ConsoleToMSBuild="true"> <Output TaskParameter="ConsoleOutput" PropertyName="OutputOfExec" /> </Exec> </Target> <Target Name="forceReGenerationOnRebuild" AfterTargets="CoreClean"> <Delete Files="$(PetClientOutputDirectory)\$(PetClientClassName).cs"></Delete> </Target>
Tenga en cuenta que este destino usa los atributos BeforeTarget y AfterTarget como forma de definir el orden de compilación. El primer destino denominado
generatePetClient
se ejecutará antes del destino de compilación principal, por lo que el origen se creará antes de que se ejecute el compilador. El parámetro de entrada y salida está relacionado con Incremental Build. MSBuild puede comparar las marcas de tiempo de los archivos de entrada con las marcas de tiempo de los archivos de salida y determinar si omitir, compilar o recompilar parcialmente un destino.Después de instalar el paquete NuGet
NSwag.MSBuild
en el proyecto, puede usar la variable$(NSwagExe)
en el archivo.csproj
para ejecutar la herramienta de línea de comandos NSwag en un destino de MSBuild. De este modo, las herramientas se pueden actualizar fácilmente a través de NuGet. Aquí, estás utilizando la tareaExec
MSBuild para ejecutar el programa NSwag con los parámetros necesarios para generar la API REST de cliente. Vea Comandos y parámetros de NSwag.Puede capturar la salida de
<Exec>
agregandoConsoleToMsBuild="true"
a la etiqueta<Exec>
y luego capturar la salida mediante el parámetroConsoleOutput
en una etiqueta<Output>
.ConsoleOutput
devuelve la salida como un elementoItem
. Se recorta el espacio en blanco.ConsoleOutput
está habilitado cuandoConsoleToMSBuild
es verdadero.El segundo destino llamado
forceReGenerationOnRebuild
elimina la clase generada durante la limpieza para forzar la regeneración del código generado durante la ejecución del destino de recompilación. Este destino se ejecuta después del destino predefinido de MSBuildCoreClean
.Ejecute una recompilación de la solución de Visual Studio y vea el cliente generado en la carpeta
PetShopRestClient
.Ahora, use el cliente generado. Vaya al cliente Program.csy copie el código siguiente:
using System; using System.Net.Http; namespace PetReaderExecTaskExample { internal class Program { private const string baseUrl = "https://petstore.swagger.io/v2"; static void Main(string[] args) { HttpClient httpClient = new HttpClient(); httpClient.BaseAddress = new Uri(baseUrl); var petClient = new PetShopRestClient.PetShopRestClient(httpClient); var pet = petClient.GetPetByIdAsync(1).Result; Console.WriteLine($"Id: {pet.Id} Name: {pet.Name} Status: {pet.Status} CategoryName: {pet.Category.Name}"); } } }
Nota
Este código usa
new HttpClient()
porque es sencillo demostrarlo, pero no es el procedimiento recomendado para el código real. El procedimiento recomendado es usarHttpClientFactory
para crear un objetoHttpClient
que solucione los problemas conocidos deHttpClient
solicitud, como agotamiento de recursos o problemas de DNS obsoletos. Vea Uso de IHttpClientFactory para implementar solicitudes HTTP resistentes.
¡Felicidades! Ahora, puede ejecutar el programa para ver cómo funciona.
Opción 2: Tarea personalizada derivada de ToolTask
En muchos casos, el uso de la tarea Exec
es lo suficientemente bueno para ejecutar una herramienta externa para hacer algo como la generación de código de cliente de la API REST, pero ¿qué pasa si solo quieres permitir la generación de código de cliente de la API REST si y solo si no usas una ruta de acceso absoluta de Windows como entrada? ¿O qué ocurre si necesita calcular de alguna manera dónde está el ejecutable? Cuando haya alguna situación en la que necesite ejecutar código para realizar trabajo adicional, la tarea de herramienta de MSBuild es la mejor solución. La clase ToolTask
es una clase abstracta derivada de MSBuild Task
. Puede definir una subclase concreta, que crea una tarea personalizada de MSBuild. Este enfoque le permite ejecutar cualquier código necesario para preparar la ejecución de comandos. Debería leer el tutorial Crear una tarea personalizada para la generación de código primero.
Creará una tarea personalizada derivada de msBuild ToolTask que generará un cliente de API REST, pero se diseñará para emitir un error si intenta hacer referencia a la especificación de OpenAPI mediante una dirección HTTP. NSwag admite una dirección HTTP como entrada de especificación de OpenAPI, pero para los fines de este ejemplo, supongamos que hay un requisito de diseño para no permitirlo.
El código completo está en esta carpeta PetReaderToolTaskExample
; puede descargar y echar un vistazo. En este tutorial, aprenderá paso a paso algunos conceptos que puede aplicar a sus propios escenarios.
Cree un nuevo proyecto de Visual Studio para la tarea personalizada. Asígnele el nombre
RestApiClientGenerator
y use la plantilla de la biblioteca de clases (C#) con .NET Standard 2.0. Asigne el nombre a la soluciónPetReaderToolTaskExample
.Elimine Class1.cs, que se generó automáticamente.
Agregue los paquetes NuGet de
Microsoft.Build.Utilities.Core
:Creación de una clase denominada
RestApiClientGenerator
Herede de MSBuild
ToolTask
e implemente el método abstracto como se muestra en el código siguiente:using Microsoft.Build.Utilities; namespace RestApiClientGenerator { public class RestApiClientGenerator : ToolTask { protected override string ToolName => throw new System.NotImplementedException(); protected override string GenerateFullPathToTool() { throw new System.NotImplementedException(); } } }
Agregue los parámetros siguientes:
- InputOpenApiSpec, donde está la especificación
- ClientClassName, nombre de la clase generada
- ClientNamespaceName, espacio de nombres donde se genera la clase
- FolderClientClass, ruta de acceso a la carpeta donde se ubicará la clase.
- NSwagCommandFullPath, ruta de acceso completa al directorio donde se encuentra NSwag.exe
[Required] public string InputOpenApiSpec { get; set; } [Required] public string ClientClassName { get; set; } [Required] public string ClientNamespaceName { get; set; } [Required] public string FolderClientClass { get; set; } [Required] public string NSwagCommandFullPath { get; set; }
Instale la herramienta de línea de comandos NSwag. Necesitará la ruta de acceso completa al directorio donde se encuentra NSwag.exe.
Implemente los métodos abstractos:
protected override string ToolName => "RestApiClientGenerator"; protected override string GenerateFullPathToTool() { return $"{NSwagCommandFullPath}\\NSwag.exe"; }
Hay muchos métodos que puede reemplazar. Para la implementación actual, defina estas dos:
- Defina el parámetro de comando:
protected override string GenerateCommandLineCommands() { return $"openapi2csclient /input:{InputOpenApiSpec} /classname:{ClientClassName} /namespace:{ClientNamespaceName} /output:{FolderClientClass}\\{ClientClassName}.cs"; }
- Validación de parámetros:
protected override bool ValidateParameters() { //http address is not allowed var valid = true; if (InputOpenApiSpec.StartsWith("http:") || InputOpenApiSpec.StartsWith("https:")) { valid = false; Log.LogError("URL is not allowed"); } return valid; }
Nota
Esta validación simple se puede realizar de otra manera en el archivo de MSBuild, pero se recomienda hacerlo en el código de C# y encapsular el comando y la lógica.
Compile el proyecto.
Creación de una aplicación de consola para usar la nueva tarea de MSBuild
El siguiente paso es crear una aplicación que use la tarea.
Cree un proyecto de aplicación de consola y asígnele el nombre
PetReaderToolTaskConsoleApp
. Elija .NET 6.0. Márquelo como proyecto de inicio.Cree un proyecto de biblioteca de clases para generar el código, denominado
PetRestApiClient
. Use .NET Standard 2.1.En el proyecto de
PetReaderToolTaskConsoleApp
, cree una dependencia de proyecto paraPetRestApiClient
.En el proyecto de
PetRestApiClient
, cree una carpetaPetRestApiClient
. Esta carpeta contendrá el código generado.Elimine Class1.cs, que se generó automáticamente.
En
PetRestApiClient
, agregue los siguientes paquetes NuGet:- Newtonsoft.Json, necesario para compilar el cliente generado
- System.ComponentModel.Annotations, necesario para compilar el cliente generado
En el proyecto de
PetRestApiClient
, cree un archivo de texto denominado petshop-openapi-spec.json (en la carpeta del proyecto). Para agregar la especificación de OpenAPI, copie el contenido de aquí en el archivo. Preferimos una compilación reproducible que dependa solo de la entrada, como se ha comentado anteriormente. En este ejemplo, generará un error de compilación si un usuario elige una dirección URL como entrada de especificación de OpenAPI.Importante
Una reconstrucción general no funcionará. Verá errores que indican que no se puede copiar o eliminar
RestApiClientGenerator
.dll". Esto se debe a que intenta compilar la tarea personalizada de MBuild en el mismo proceso de compilación que lo usa. SeleccionePetReaderToolTaskConsoleApp
y recompile solo ese proyecto. La otra solución es colocar la tarea personalizada en una solución de Visual Studio completamente independiente, como usted hizo en el ejemplo Tutorial: Creación de una tarea personalizada.Copie el código siguiente en Program.cs:
using System; using System.Net.Http; namespace PetReaderToolTaskConsoleApp { internal class Program { private const string baseUrl = "https://petstore.swagger.io/v2"; static void Main(string[] args) { HttpClient httpClient = new HttpClient(); httpClient.BaseAddress = new Uri(baseUrl); var petClient = new PetRestApiClient.PetRestApiClient(httpClient); var pet = petClient.GetPetByIdAsync(1).Result; Console.WriteLine($"Id: {pet.Id} Name: {pet.Name} Status: {pet.Status} CategoryName: {pet.Category.Name}"); } } }
Cambie las instrucciones de MSBuild para llamar a la tarea y generar el código. Edite petRestApiClient.csproj siguiendo estos pasos:
Registre el uso de la tarea personalizada de MSBuild:
<UsingTask TaskName="RestApiClientGenerator.RestApiClientGenerator" AssemblyFile="..\RestApiClientGenerator\bin\Debug\netstandard2.0\RestApiClientGenerator.dll" />
Agregue algunas propiedades necesarias para ejecutar la tarea:
<PropertyGroup> <!--The place where the OpenAPI spec is in--> <PetClientInputOpenApiSpec>petshop-openapi-spec.json</PetClientInputOpenApiSpec> <PetClientClientClassName>PetRestApiClient</PetClientClientClassName> <PetClientClientNamespaceName>PetRestApiClient</PetClientClientNamespaceName> <PetClientFolderClientClass>PetRestApiClient</PetClientFolderClientClass> <!--The directory where NSawg.exe is in--> <NSwagCommandFullPath>C:\Nsawg\Win</NSwagCommandFullPath> </PropertyGroup>
Importante
Seleccione el valor de
NSwagCommandFullPath
adecuado en función de la ubicación de instalación del sistema.Agregue un destino MSBuild para generar el cliente durante el proceso de compilación. Este destino debe ejecutarse antes de que se ejecute
CoreCompile
para generar el código usado en la compilación.<Target Name="generatePetClient" BeforeTargets="CoreCompile" Inputs="$(PetClientInputOpenApiSpec)" Outputs="$(PetClientFolderClientClass)\$(PetClientClientClassName).cs"> <!--Calling our custom task derivated from MSBuild Tool Task--> <RestApiClientGenerator InputOpenApiSpec="$(PetClientInputOpenApiSpec)" ClientClassName="$(PetClientClientClassName)" ClientNamespaceName="$(PetClientClientNamespaceName)" FolderClientClass="$(PetClientFolderClientClass)" NSwagCommandFullPath="$(NSwagCommandFullPath)"></RestApiClientGenerator> </Target> <Target Name="forceReGenerationOnRebuild" AfterTargets="CoreClean"> <Delete Files="$(PetClientFolderClientClass)\$(PetClientClientClassName).cs"></Delete> </Target>
Input
yOutput
están relacionados con la compilación incremental, y el destinoforceReGenerationOnRebuild
elimina el archivo generado después deCoreClean
, lo que obliga al cliente a volver a generarse durante la operación de recompilación.Seleccione
PetReaderToolTaskConsoleApp
y recompile solo ese proyecto. Ahora, se genera el código de cliente y el código se compila. Puede ejecutarlo y ver cómo funciona. Este código genera un código nuevo a partir de un archivo, lo cual está permitido.En este paso, mostrará la validación de parámetros. En PetRestApiClient.csproj, cambie la propiedad
$(PetClientInputOpenApiSpec)
para usar la dirección URL:<PetClientInputOpenApiSpec>https://petstore.swagger.io/v2/swagger.json</PetClientInputOpenApiSpec>
Seleccione
PetReaderToolTaskConsoleApp
y recompile solo ese proyecto. Obtendrá el error "No se permite la dirección URL" de acuerdo con el requisito de diseño.
Descargar el código
Instale la herramienta de línea de comandos NSwag. A continuación, necesitará la ruta de acceso completa al directorio donde se encuentra NSwag.exe. Después, edite PetRestApiClient.csproj y seleccione el valor de $(NSwagCommandFullPath)
adecuado en función de la ruta de instalación del equipo. Ahora, seleccione RestApiClientGenerator
y compile solo ese proyecto y, por último, seleccione y recompile PetReaderToolTaskConsoleApp
. Puede ejecutar PetReaderToolTaskConsoleApp
para comprobar que todo funciona según lo previsto.
Pasos siguientes
Es posible que quiera publicar la tarea personalizada como un paquete NuGet.
Tutorial de : Creación de una tarea personalizada
O bien, aprenda a probar una tarea personalizada.