gRPC frente a REST: Introducción al mejor protocolo de API
Publicado: 2022-07-22En el panorama tecnológico actual, la mayoría de los proyectos requieren el uso de API. Las API conectan la comunicación entre servicios que pueden representar un sistema único y complejo, pero que también pueden residir en máquinas separadas o usar varias redes o idiomas incompatibles.
Muchas tecnologías estándar abordan las necesidades de comunicación entre servicios de los sistemas distribuidos, como REST, SOAP, GraphQL o gRPC. Si bien REST es un enfoque favorito, gRPC es un competidor digno que ofrece alto rendimiento, contratos tipificados y excelentes herramientas.
Resumen de REST
La transferencia de estado representacional (REST) es un medio para recuperar o manipular los datos de un servicio. Una API REST generalmente se basa en el protocolo HTTP, utilizando un URI para seleccionar un recurso y un verbo HTTP (por ejemplo, GET, PUT, POST) para seleccionar la operación deseada. Los cuerpos de solicitud y respuesta contienen datos que son específicos de la operación, mientras que sus encabezados proporcionan metadatos. Para ilustrar, veamos un ejemplo simplificado de recuperación de un producto a través de una API REST.
Aquí, solicitamos un recurso de producto con una ID de 11
y le indicamos a la API que responda en formato JSON:
GET /products/11 HTTP/1.1 Accept: application/json
Dada esta solicitud, nuestra respuesta (se omiten los encabezados irrelevantes) podría verse así:
HTTP/1.1 200 OK Content-Type: application/json { id: 11, name: "Purple Bowtie", sku: "purbow", price: { amount: 100, currencyCode: "USD" } }
Si bien JSON puede ser legible por humanos, no es óptimo cuando se usa entre servicios. La naturaleza repetitiva de hacer referencia a nombres de propiedades, incluso cuando están comprimidos, puede generar mensajes inflados. Veamos una alternativa para abordar esta preocupación.
Descripción general de gRPC
gRPC Remote Procedure Call (gRPC) es un protocolo de comunicación multiplataforma, de código abierto y basado en contratos que simplifica y administra la comunicación entre servicios al exponer un conjunto de funciones a clientes externos.
Construido sobre HTTP/2, gRPC aprovecha funciones como la transmisión bidireccional y la seguridad de la capa de transporte (TLS) integrada. gRPC permite una comunicación más eficiente a través de cargas útiles binarias serializadas. Utiliza búferes de protocolo de forma predeterminada como su mecanismo para la serialización de datos estructurados, similar al uso de JSON por parte de REST.
Sin embargo, a diferencia de JSON, los búferes de protocolo son más que un formato serializado. Incluyen otras tres partes principales:
- Un lenguaje de definición de contratos que se encuentra en los archivos
.proto
(Seguiremos a proto3, la última especificación de lenguaje de búfer de protocolo). - Código de función de acceso generado
- Bibliotecas de tiempo de ejecución específicas del idioma
Las funciones remotas que están disponibles en un servicio (definidas en un archivo .proto
) se enumeran dentro del nodo de servicio en el archivo de búfer de protocolo. Como desarrolladores, podemos definir estas funciones y sus parámetros utilizando el sistema de tipos enriquecidos de los búferes de protocolo. Este sistema admite varios tipos numéricos y de fecha, listas, diccionarios y anulables para definir nuestros mensajes de entrada y salida.
Estas definiciones de servicio deben estar disponibles tanto para el servidor como para el cliente. Desafortunadamente, no existe un mecanismo predeterminado para compartir estas definiciones aparte de proporcionar acceso directo al propio archivo .proto
.
Este archivo .proto
de ejemplo define una función para devolver una entrada de producto, dado un ID:
La escritura estricta y el orden de los campos de proto3 hacen que la deserialización de mensajes sea considerablemente menos exigente que analizar JSON.
Comparación de REST con gRPC
En resumen, los puntos más significativos al comparar REST con gRPC son:
DESCANSAR | gRPC | |
---|---|---|
multiplataforma | Sí | Sí |
Formato de mensaje | Personalizado pero generalmente JSON o XML | Búferes de protocolo |
Tamaño de la carga útil del mensaje | Mediano grande | Pequeña |
Complejidad de procesamiento | Superior (análisis de texto) | Inferior (estructura binaria bien definida) |
Compatibilidad con navegador | Sí (nativo) | Sí (a través de gRPC-Web) |
Donde se esperan contratos menos estrictos y adiciones frecuentes a la carga útil, JSON y REST encajan perfectamente. Cuando los contratos tienden a permanecer más estáticos y la velocidad es de suma importancia, gRPC generalmente gana. En la mayoría de los proyectos en los que he trabajado, gRPC ha demostrado ser más ligero y de mayor rendimiento que REST.
Implementación del servicio gRPC
Construyamos un proyecto simplificado para explorar lo simple que es adoptar gRPC.
Creando el Proyecto API
Para comenzar, crearemos un proyecto .NET 6 en Visual Studio 2022 Community Edition (VS). Seleccionaremos la plantilla de servicio gRPC de ASP.NET Core y nombraremos tanto el proyecto (usaremos InventoryAPI
) como nuestra primera solución dentro de él ( Inventory
) .
Ahora, elijamos el . Opción NET 6.0 (soporte a largo plazo) para nuestro marco:
Definición de nuestro servicio de productos
Ahora que creamos el proyecto, VS muestra un servicio de definición de prototipo de gRPC de muestra llamado Greeter
. Reutilizaremos los archivos principales de Greeter
para satisfacer nuestras necesidades.
- Para crear nuestro contrato, reemplazaremos el contenido de
greet.proto
con Snippet 1, renombrando el archivoproduct.proto
. - Para crear nuestro servicio, reemplazaremos el contenido del archivo
GreeterService.cs
con Snippet 2, renombrando el archivoProductCatalogService.cs
.
El servicio ahora devuelve un producto codificado. Para que el servicio funcione, solo necesitamos cambiar el registro del servicio en Program.cs
para hacer referencia al nuevo nombre del servicio. En nuestro caso, cambiaremos el nombre app.MapGrpcService<GreeterService>();
a app.MapGrpcService<ProductCatalogService>();
para hacer que nuestra nueva API sea ejecutable.
Advertencia justa: no es su prueba de protocolo estándar
Si bien podemos tener la tentación de probarlo, no podemos probar nuestro servicio gRPC a través de un navegador dirigido a su punto final. Si intentáramos esto, recibiríamos un mensaje de error que indica que la comunicación con los extremos de gRPC debe realizarse a través de un cliente de gRPC.
Crear el cliente
Para probar nuestro servicio, usemos la plantilla de aplicación de consola básica de VS y creemos un cliente gRPC para llamar a la API. Llamé a la mía InventoryApp
.
Por conveniencia, hagamos referencia a una ruta de archivo relativa por la cual compartiremos nuestro contrato. Agregaremos la referencia manualmente al archivo .csproj
. Luego, actualizaremos la ruta y estableceremos el modo Client
. Nota: Le recomiendo que se familiarice y tenga confianza en su estructura de carpetas local antes de usar referencias relativas.
Estas son las referencias .proto
, tal como aparecen en los archivos de proyecto del servicio y del cliente:
Archivo de proyecto de servicio (Código para copiar al archivo del proyecto del cliente) | Archivo de proyecto del cliente (Después de pegar y editar) |
---|---|
|
|
Ahora, para llamar a nuestro servicio, reemplazaremos el contenido de Program.cs
. Nuestro código logrará una serie de objetivos:
- Cree un canal que represente la ubicación del extremo del servicio (el puerto puede variar, así que consulte el archivo
launchsettings.json
para conocer el valor real). - Cree el objeto de cliente.
- Construya una solicitud simple.
- Envía la solicitud.
Preparándose para el lanzamiento
Para probar nuestro código, en VS, haremos clic derecho en la solución y elegiremos Establecer proyectos de inicio . En el cuadro de diálogo Páginas de propiedades de la solución, haremos lo siguiente:
- Seleccione el botón de opción junto a Múltiples proyectos de inicio y, en el menú desplegable Acción, establezca ambos proyectos (
InventoryAPI
eInventoryApp
) en Inicio . - Haga clic en Aceptar .
Ahora podemos iniciar la solución haciendo clic en Iniciar en la barra de herramientas de VS (o presionando la tecla F5 ). Aparecerán dos nuevas ventanas de consola: una para decirnos que el servicio está escuchando y la otra para mostrarnos los detalles del producto recuperado.
Uso compartido de contratos de gRPC
Ahora usemos otro método para conectar el cliente gRPC a la definición de nuestro servicio. La solución para compartir contratos más accesible para el cliente es hacer que nuestras definiciones estén disponibles a través de una URL. Otras opciones son muy frágiles (archivo compartido a través de una ruta) o requieren más esfuerzo (contrato compartido a través de un paquete nativo). Compartir a través de una URL (como lo hacen SOAP y Swagger/OpenAPI) es flexible y requiere menos código.
Para comenzar, haga que el archivo .proto
esté disponible como contenido estático. Actualizaremos nuestro código manualmente porque la interfaz de usuario en la acción de compilación está configurada en "Protobuf Compiler". Este cambio indica al compilador que copie el archivo .proto
para que se pueda servir desde una dirección web. Si esta configuración se cambiara a través de la interfaz de usuario de VS, la compilación se interrumpiría. Entonces, nuestro primer paso es agregar Snippet 4 al archivo InventoryAPI.csproj
:
A continuación, insertamos el código en el Fragmento 5 en la parte superior del archivo ProductCatalogService.cs
para configurar un punto final para devolver nuestro archivo .proto
:
Y ahora, agregamos Snippet 6 justo antes de app.Run()
, también en el archivo ProductCatalogService.cs
:
Con los Snippets 4-6 agregados, el contenido del archivo .proto
debería estar visible en el navegador.
Un nuevo cliente de prueba
Ahora queremos crear un nuevo cliente de consola que conectaremos a nuestro servidor existente con el Asistente de dependencia de VS. El problema es que este asistente no habla HTTP/2. Por lo tanto, necesitamos ajustar nuestro servidor para hablar sobre HTTP/1 e iniciar el servidor. Ahora que nuestro servidor pone a disposición su archivo .proto
, podemos crear un nuevo cliente de prueba que se conecta a nuestro servidor a través del asistente de gRPC.
- Para cambiar nuestro servidor para hablar sobre HTTP/1, editaremos nuestro archivo
appsettings.json
JSON:- Ajuste el campo
Protocol
(que se encuentra en la rutaKestrel.EndpointDefaults.Protocols
) para leerHttps
. - Guarda el archivo.
- Ajuste el campo
- Para que nuestro nuevo cliente lea esta información
proto
, el servidor debe estar ejecutándose. Originalmente, iniciamos tanto el cliente anterior como nuestro servidor desde el cuadro de diálogo Establecer proyectos de inicio de VS. Ajuste la solución del servidor para iniciar solo el proyecto del servidor y luego inicie la solución. (Ahora que hemos modificado la versión HTTP, nuestro antiguo cliente ya no puede comunicarse con el servidor). - A continuación, cree el nuevo cliente de prueba. Inicie otra instancia de VS. Repetiremos los pasos como se detalla en la sección Crear el proyecto API , pero esta vez elegiremos la plantilla de la aplicación de consola . Llamaremos a nuestro proyecto y solución
InventoryAppConnected
. - Con el chasis del cliente creado, nos conectaremos a nuestro servidor gRPC. Expanda el nuevo proyecto en VS Solution Explorer.
- Haga clic con el botón derecho en Dependencias y, en el menú contextual, seleccione Administrar servicios conectados .
- En la pestaña Servicios conectados, haga clic en Agregar una referencia de servicio y elija gRPC .
- En el cuadro de diálogo Agregar referencia de servicio, elija la opción URL e ingrese la versión
http
de la dirección del servicio (recuerde tomar el número de puerto generado aleatoriamente delaunchsettings.json
) . - Haga clic en Finalizar para agregar una referencia de servicio que se pueda mantener fácilmente.
Siéntase libre de comparar su trabajo con el código de muestra para este ejemplo. Dado que, bajo el capó, VS ha generado el mismo cliente que usamos en nuestra primera ronda de pruebas, podemos reutilizar el contenido del archivo Program.cs
del servicio anterior palabra por palabra.
Cuando cambiamos un contrato, debemos modificar la definición de gRPC de nuestro cliente para que coincida con la definición .proto
actualizada. Para hacerlo, solo necesitamos acceder a los servicios conectados de VS y actualizar la entrada del servicio correspondiente. Ahora, nuestro proyecto gRPC está completo y es fácil mantener sincronizados nuestro servicio y nuestro cliente.
Su próximo candidato a proyecto: gRPC
Nuestra implementación de gRPC proporciona una visión de primera mano de los beneficios de usar gRPC. REST y gRPC tienen cada uno sus propios casos de uso ideales según el tipo de contrato. Sin embargo, cuando ambas opciones se ajusten, lo animo a que pruebe gRPC; lo pondrá a la vanguardia en el futuro de las API.