Cloud Endpoints admite la transcodificación de protocolo para que los clientes puedan acceder a tu API de gRPC con HTTP/JSON. El proxy de servicio extensible (ESP) transcodifica HTTP/JSON a gRPC.
Esta guía describe lo siguiente:
- Cómo usar las anotaciones en tu archivo
.proto
para especificar la conversión de datos de HTTP/JSON a gRPC - Cómo implementar tu servicio en Endpoints para usar esta característica
- Dónde encontrar más información de referencia sobre el diseño y la implementación de la transcodificación para los servicios de gRPC
Suponemos que ya completaste nuestros instructivos de gRPC y que estás familiarizado con los conceptos básicos de Endpoints para las API de gRPC .
Diseña una API compatible con la transcodificación
La transcodificación implica la asignación de solicitudes HTTP/JSON y sus parámetros a los métodos de gRPC y sus parámetros y tipos de datos que se muestran. Por esto, si bien es posible asignar una solicitud HTTP/JSON a cualquier método de la API arbitrario, es más fácil hacerlo si la API de gRPC se estructura de una manera orientada a los recursos, como una API de REST HTTP tradicional. En otras palabras, el servicio de API debe diseñarse para que use una cantidad pequeña de métodos estándar, en relación con verbos HTTP, como GET
y PUT
, que operan en los recursos del servicio y en las colecciones de recursos, que son de un tipo de recurso. Estos métodos estándar son List
, Get
, Create
, Update
y Delete
.
Si es necesario, la API también puede tener algunos métodos personalizados no estándar, aunque no son tan sencillos de asignar.
Puedes obtener mucha más información sobre el diseño orientado a los recursos y asignaciones de transcodificación estándar en nuestra Guía de diseño de API. Este guía de diseño es el estándar que sigue Google cuando diseña API públicas, como las API de Cloud. Si bien no es necesario que sigas esta guía para usar la transcodificación de gRPC, te recomendamos que lo hagas. En particular, las páginas siguientes te servirán de ayuda a fin de comprender estos principios de diseño y agregar asignaciones de transcodificación útiles a tus métodos:
- Diseño orientado a recursos
- Métodos estándar
- Métodos personalizados
- Verbos HTTP: en esta página, se proporcionan lineamientos adicionales para las implementaciones de tu método, en caso de que vayas a acceder a ellos a través de HTTP.
La página de referencia que aparece a continuación también puede ser de utilidad:
- Referencia de regla HTTP: una referencia completa para las reglas de asignación HTTP
En el resto del documento, usaremos el ejemplo de Bookstore, que es el mismo de nuestros instructivos, y que ya pone en funcionamiento estos principios.
Bookstore cuenta con colecciones de “biblioteca” de recursos de “libros” que los usuarios pueden List
, Get
, Create
o Delete
.
Dónde configurar la transcodificación
La transcodificación de gRPC está habilitada de forma predeterminada, y puedes usarla sin ninguna configuración. Sigue las instrucciones para implementar un servicio mediante la transcodificación.
Luego, cuando envíes una solicitud POST
HTTP a la ruta GRPC_SERVICE_FULL_NAME/METHOD_NAME>
de la URL con los valores del campo de mensaje de la solicitud del método (si existen) como JSON en el cuerpo de la solicitud HTTP, el ESP enviará el mensaje de solicitud al método de gRPC adecuado. En el ejemplo anterior, GRPC_SERVICE_FULL_NAME
es el nombre completo de tu servicio de gRPC y METHOD_NAME
es el nombre del método.
Por ejemplo, si envías un POST
a la URL ListShelves
Bookstore de la manera siguiente :
curl -XPOST http://mydomain/endpoints.examples.bookstore.Bookstore/ListShelves
Obtendrás una lista actual de las bibliotecas en formato JSON.
Sin embargo, es preferible en cuanto al diseño de interfaz HTTP que configures de forma explícita las asignaciones, como se describe en el resto de este documento.
La configuración de la API de gRPC estándar para la configuración del servicio te permite especificar con exactitud cómo se deben traducir los datos de HTTP/JSON a gRPC. Se admiten dos mecanismos para hacer esto: anotaciones directas en tu archivo .proto
y en YAML como parte de tu archivo de configuración de API de gRPC. Recomendamos usar anotaciones proto
para facilitar la lectura y el mantenimiento.
Si quieres obtener más información sobre la configuración de YAML y cuándo es posible que debas usarla, consulta Cómo configurar la transcodificación en YAML.
Este es un ejemplo que usa el método recomendado de Bookstore:
// Returns a specific bookstore shelf.
rpc GetShelf(GetShelfRequest) returns (Shelf) {
// Client example - returns the first shelf:
// curl http://DOMAIN_NAME/v1/shelves/1
option (google.api.http) = { get: "/v1/shelves/{shelf}" };
}
...
// Request message for GetShelf method.
message GetShelfRequest {
// The ID of the shelf resource to retrieve.
int64 shelf = 1;
}
La anotación indica al ESP que realizar una solicitud HTTP GET
con la URL http://mydomain/v1/shelves/1
generará una llamada al método GetShelf()
del servidor de gRPC con un GetShelfRequest
que contiene el ID de la biblioteca solicitada shelf
(en este caso, 1
).
Agrega asignaciones de transcodificación
En esta sección, se describen algunas anotaciones de asignaciones adicionales de la muestra de Bookstore. Hay dos archivos proto
de muestra en la muestra de Bookstore para que puedas implementarlos con o sin las asignaciones de transcodificación y comparar las diferencias en los archivos proto
:
bookstore.proto
: se usa en los instructivos de Endpoints y no tiene asignaciones de transcodificación.http_bookstore.proto
: se agregaron vinculaciones de transcodificación.
Para consultar una guía más completa a fin de especificar las asignaciones de transcodificación, consulta Métodos estándar, Métodos personalizados y la Referencia de reglas HTTP.
Asigna un método List
El método List
se define en el archivo .proto
con su tipo de respuesta:
// Returns a list of all shelves in the bookstore. rpc ListShelves(google.protobuf.Empty) returns (ListShelvesResponse) { // Define HTTP mapping. // Client example (Assuming your service is hosted at the given 'DOMAIN_NAME'): // curl http://DOMAIN_NAME/v1/shelves option (google.api.http) = { get: "/v1/shelves" }; } ... message ListShelvesResponse { // Shelves in the bookstore. repeated Shelf shelves = 1; }
La anotación en negrita especifica la asignación HTTP para este método.
option (google.api.http)
especifica que este método es una anotación de asignación HTTP de gRPC.get
especifica que este método está asignado a una solicitudGET
HTTP."/v1/shelves"
es la plantilla de la ruta de URL (adjunta al dominio de tu servicio) que la solicitudGET
usa para llamar a este método. La ruta de URL también se conoce como la ruta del recurso, ya que suele especificar la “cosa” o recurso que quieres usar. En este caso, son todos los recursos de nuestra biblioteca de Bookstore.
Por ejemplo, si un cliente llama a este método mediante el envío de GET
a la URL http://mydomain/v1/shelves
, el ESP llama al método de gRPC ListShelves()
. El backend de gRPC luego muestra las bibliotecas, que el ESP convierte al formato JSON y las muestra al cliente.
Asigna un método Get
El método GetShelf
de Bookstore se define en el archivo .proto
con sus tipos de solicitud y respuesta:
// Returns a specific bookstore shelf. rpc GetShelf(GetShelfRequest) returns (Shelf) { // Client example - returns the first shelf: // curl http://DOMAIN_NAME/v1/shelves/1 option (google.api.http) = { get: "/v1/shelves/{shelf}" }; } ... // Request message for GetShelf method. message GetShelfRequest { // The ID of the shelf resource to retrieve. int64 shelf = 1; } ... // A shelf resource. message Shelf { // A unique shelf id. int64 id = 1; // A theme of the shelf (fiction, poetry, etc). string theme = 2; }
La anotación en negrita especifica la asignación HTTP para este método.
option (google.api.http)
especifica que este método es una anotación de asignación HTTP de gRPC.get
especifica que este método está asignado a una solicitudGET
HTTP."/v1/shelves/{shelf}"
es la ruta de URL para la solicitud, como antes, pero especifica/v1/shelves/
y, luego,{shelf}
. Esta notación de llave indica al ESP que lo que haya en{shelf}
es el valor que debe proporcionar parashelf
en el parámetroGetShelfRequest
del método.
Si un cliente llama a este método mediante el envío de un GET
a la URL http://mydomain/v1/shelves/4
, el ESP crea una GetShelfRequest
con un valor shelf
de 4
y, luego, llama el método de gRPC GetShelf()
con ella. Luego, el backend de gRPC muestra el Shelf
solicitado con el ID 4
, que el ESP convierte al formato JSON y se lo muestra al cliente.
Este método solo requiere que el cliente proporcione un único valor de campo de solicitud, shelf
, que especificamos en la plantilla de la ruta de URL con la notación "captura" de llave. Si es necesario, también puedes capturar varias partes de la URL para identificar el recurso solicitado. Por ejemplo, el método GetBook
necesita que el cliente especifique el ID de la biblioteca y el ID del libro en la URL:
// Returns a specific book.
rpc GetBook(GetBookRequest) returns (Book) {
// Client example - get the first book from the second shelf:
// curl http://DOMAIN_NAME/v1/shelves/2/books/1
option (google.api.http) = { get: "/v1/shelves/{shelf}/books/{book}" };
}
...
// Request message for GetBook method.
message GetBookRequest {
// The ID of the shelf from which to retrieve a book.
int64 shelf = 1;
// The ID of the book to retrieve.
int64 book = 2;
}
Además de las llaves de captura y literales para los valores de campo, las plantillas de ruta de URL pueden usar comodines a fin de indicar que se debe capturar cualquier parte de esta URL. La notación {shelf}
que se usó en el ejemplo anterior es, en realidad, un acceso directo para {shelf=*}
. Puedes encontrar más información sobre las reglas para las plantillas de ruta en la Referencia de reglas HTTP.
En el caso de este tipo de método, no existe un cuerpo de solicitud HTTP especificado. Puedes encontrar más lineamientos sobre la asignación de métodos Get
, incluido el uso de parámetros de consulta, en Métodos estándar.
Asigna un método Create
El método CreateShelf
de Bookstore asigna a HTTP POST
.
// Creates a new shelf in the bookstore. rpc CreateShelf(CreateShelfRequest) returns (Shelf) { // Client example: // curl -d '{"theme":"Music"}' http://DOMAIN_NAME/v1/shelves option (google.api.http) = { post: "/v1/shelves" body: "shelf" }; } ... // Request message for CreateShelf method. message CreateShelfRequest { // The shelf resource to create. Shelf shelf = 1; } ... // A shelf resource. message Shelf { // A unique shelf id. int64 id = 1; // A theme of the shelf (fiction, poetry, etc). string theme = 2; }
option (google.api.http)
especifica que este método es una anotación de asignación HTTP de gRPC.post
especifica que este método está asignado a una solicitudPOST
HTTP."/v1/shelves"
es la ruta de URL para la solicitud, como antes.body: "shelf"
se usa en el cuerpo de la solicitud HTTP a fin de especificar el recurso que quieres agregar, en formato JSON.
Por ejemplo, si un cliente llama a este método de la siguiente manera:
curl -d '{"theme":"Music"}' http://DOMAIN_NAME/v1/shelves
El ESP usa el cuerpo JSON a fin de crear un valor Shelf
con el tema "Music"
para el CreateShelfRequest
y, luego, llama al método CreateShelf()
de gRPC. Ten en cuenta que el cliente no proporciona el valor id
para el Shelf
.
El servicio proporciona los ID de bibliotecas de Bookstore cuando crea una librería nueva.
Este es el tipo de información que debes proporcionar a los usuarios de tu servicio en la documentación de la API.
Usa comodones en el cuerpo
El nombre especial *
se puede usar en la asignación del cuerpo para indicar que cada campo que no está vinculado a la plantilla de ruta se debe asignar al cuerpo de la solicitud.
Esto habilita la siguiente definición alternativa del método CreateShelf
.
// Creates a new shelf in the bookstore. rpc CreateShelf(CreateShelfRequest) returns (Shelf) { // Client example: // curl -d '{"shelf_theme":"Music", "shelf_size": 20}' http://DOMAIN_NAME/v1/shelves/123 option (google.api.http) = { post: "/v1/shelves/{shelf_id}" body: "*" }; } ... // Request message for CreateShelf method. message CreateShelfRequest { // A unique shelf id. int64 shelf_id = 1; // A theme of the shelf (fiction, poetry, etc). string shelf_theme = 2; // The size of the shelf int64 shelf_size = 3; }
option (google.api.http)
especifica que este método es una anotación de asignación HTTP de gRPC.post
especifica que este método está asignado a una solicitudPOST
HTTP."/v1/shelves/{shelf_id}"
es la ruta de URL para la solicitud. Lo que aparezca en{shelf_id}
es el valor del camposhelf_id
enCreateShelfRequest
.body: "*"
se usa en el cuerpo de la solicitud HTTP a fin de especificar todos los campos de solicitud restantes, exceptoshelf_id
en este ejemplo, que sonshelf_theme
yshelf_size
. Para los campos en el cuerpo JSON con estos dos nombres, sus valores se usarán en los campos correspondientes deCreateShelfRequest
.
Por ejemplo, si un cliente llama a este método de la siguiente manera:
curl -d '{"shelf_theme":"Music", "shelf_size": 20}' http://DOMAIN_NAME/v1/shelves/123
El ESP usa el cuerpo JSON y la plantilla de la ruta para crear un CreateShelfRequest{shelf_id: 123 shelf_theme: "Music" shelf_size: 20}
y, luego, la usa a fin de llamar al método CreateShelf()
de gRPC. Para obtener detalles, consulta la HttpRule.
Configura la transcodificación en YAML
Otra posibilidad es cuando especificas tus asignaciones HTTP a gRPC en el archivo YAML de la configuración de API de gRPC, en lugar del archivo .proto
. Es posible que debas configurar la transcodificación en un archivo YAML si tienes una sola definición de API proto
que se usa en varios servicios, con asignaciones diferentes para cada servicio.
Las rules
en la sección http
de tu archivo YAML especifica cómo asignar las solicitudes HTTP/JSON a los métodos de gRPC:
http:
rules:
...
#
# 'GetShelf' is available via the GET HTTP verb and '/shelves/{shelf}' URL
# path, where {shelf} is the value of the 'shelf' field of 'GetShelfRequest'
# protobuf message.
#
# Client example - returns the first shelf:
# curl http://DOMAIN_NAME/v1/shelves/1
#
- selector: endpoints.examples.bookstore.Bookstore.GetShelf
get: /v1/shelves/{shelf}
...
Puedes ver un ejemplo más completo sobre el uso de este método para el servicio de Bookstore de ejemplo en api_config_http.yaml
.
Implementa un servicio que usa transcodificación
La implementación de un servicio de gRPC que usa la transcodificación es muy similar a la implementación de cualquier otro servicio de gRPC, con una diferencia importante. En los instructivos, el ejemplo debía aceptar las solicitudes de gRPC del cliente de muestra. Sin embargo, si quieres que Bookstore también acepte las solicitudes HTTP, debes establecer alguna configuración adicional para el ESP. Los clientes usarán el protocolo HTTP1.1
para enviar solicitudes JSON/HTTP al ESP, por lo que el ESP debe configurarse a fin de usar SSL (el puerto SSL es compatible con ambos tipos de solicitudes) o debe tener un puerto especial habilitado para aceptar estas llamadas. De lo contrario, la implementación es casi la misma que la del instructivo para el entorno elegido.
Asegúrate de que las reglas HTTP estén implementadas
Si ya descargaste el ejemplo de Bookstore para los Instructivos , ten en cuenta que debes descargar una versión algo diferente del archivo .proto
con anotaciones, http_bookstore.proto
.
También debes clonar el repositorio googleapis
de GitHub antes de ejecutar protoc
, ya que deberás realizar annotations.proto
en tu ruta de inclusión.
git clone https://github.com/googleapis/googleapis
GOOGLEAPIS_DIR=<your-local-googleapis-folder>
A continuación, crea un descriptor .pb
nuevo desde http_bookstore.proto
cuando implementes tu configuración en Endpoints:
protoc \
--include_imports \
--include_source_info \
--proto_path=${GOOGLEAPIS_DIR} \
--proto_path=. \
--descriptor_set_out=api_descriptor.pb \
http_bookstore.proto
Si usas el método alternativo de configuración de asignaciones HTTP en tu archivo YAML de la Configuración de la API de gRPC, también debes asegurarte de que se implementen las reglas relevantes durante la implementación de tu configuración en Endpoints. Para probarlo con el servicio de Bookstore, sus reglas básicas están en el archivo api_config.yaml
y sus reglas HTTP en el archivo api_config_http.yaml
:
gcloud endpoints services deploy api_descriptor.pb api_config.yaml api_config_http.yaml
Usa SSL
Si SSL está habilitado para la comunicación entre tus clientes y el ESP, los clientes pueden usar el mismo puerto a fin de realizar llamadas gRPC o HTTP1.1
. Puedes obtener información sobre cómo configurar el SSL para un servicio de Endpoints en Cómo habilitar SSL.
Especifica un puerto para que el ESP acepte llamadas SSL con la marca --ssl_port
en el archivo de configuración de Google Kubernetes Engine (GKE) o el comando docker run
(Compute Engine/Docker).
args: [
"--http_port", "8080",
"--ssl_port", "443", # enable SSL port at 443 to serve https requests
"--backend", "grpc://127.0.0.1:8081", # gRPC backend.
"--service", "SERVICE_NAME",
"--rollout_strategy", "managed",
]
Configura un puerto HTTP1.1
Si no usas SSL, debes configurar un puerto por separado para las solicitudes HTTP1.1
, ya que gRPC y HTTP1.1
no pueden compartir el mismo puerto sin SSL. Usa la marca --http_port
en el archivo de configuración GKE o el comando docker run
para especificar un puerto a fin de aceptar llamadas HTTP1.1
. Si también quieres que el ESP acepte llamadas de gRPC, debes usar la marca --http2_port
para especificar un puerto de gRPC.
args: [
"--http_port", "8080", # for HTTP 1.1
"--http2_port", "8090", # for gRPC
"--backend", "grpc://127.0.0.1:8081", # gRPC backend.
"--service", "SERVICE_NAME",
"--rollout_strategy", "managed",
]
Llama a un servicio mediante transcodificación
En esta sección, se describe la configuración del servicio y cómo realizar llamadas HTTP al servicio.
Configuración del servicio
Suponemos que ya completaste los Instructivos básicos del servicio de gRPC del entorno seleccionado y tienes un clúster de GKE o una instancia de Compute Engine para ejecutar el ejemplo.
- Primero, asegúrate de haber implementado la configuración del servicio de Bookstore habilitada para HTTP en Endpoints, como se describe en Asegúrate de que las reglas HTTP estén implementadas.
Implementa el backend y el ESP como se describe en el instructivo para la plataforma seleccionada con la marca
--http_port
a fin de habilitar un puerto destinado a solicitudesHTTP1.1
:- Implementación de GKE: sigue las instrucciones en Implementación de la API de muestra y el ESP en el clúster para asegurarte de que la marca
"--http_port"
se especifique en el archivo de configuración de GKE. - Implementación de Compute Engine: sigue las instrucciones en ejecutar la API y el ESP de muestra en la contenedor de Docker.
Asegúrate de que la marca
--http_port
esté especificada en el comandodocker run
cuando ejecutes el contenedor de Docker del ESP ya empaquetado.
- Implementación de GKE: sigue las instrucciones en Implementación de la API de muestra y el ESP en el clúster para asegurarte de que la marca
Realiza llamadas HTTP al servicio
- Obtén la dirección IP externa del ESP y configúrala en
$ESP_IP
. Realiza la solicitud HTTP siguiente con
curl
curl http://$ESP_IP/v1/shelves
(o usa la misma URL con
https://
, si usas SSL). El servidor debe responder con lo que se describe a continuación:{"shelves":[{"id":"1","theme":"Fiction"},{"id":"2","theme":"Fantasy"}]}
Si el resultado muestra una respuesta binaria, verifica la configuración de tu puerto, ya que podrías estar usando tu puerto HTTP2, en lugar del puerto HTTP.
Prueba el método
Create
.CreateShelf
requiere una clave de API, por lo que debes crear una clave para tu proyecto y configurarla como$KEY
. Ahora, realiza una llamada:curl -d '{"theme":"Music"}' http://$ESP_IP/v1/shelves?key=$KEY
Si vuelves a llamar a
GetShelves
, deberías ver tu biblioteca nueva.