Cómo configurar un servicio gRPC

Para crear un servicio gRPC, ya sea que uses Cloud Endpoints o no, especifica la definición de la interfaz en uno o más archivos proto, que son archivos de texto con la extensión .proto. En un archivo proto, defines la superficie de la API, incluidas las estructuras de datos, los métodos, los parámetros de los métodos y los tipos de datos que se muestran. Luego, compilas tu archivo proto mediante el uso del compilador de búfer de protocolo específico del lenguaje, protoc. Si deseas obtener más información, consulta ¿Qué es gRPC? y Conceptos de gRPC.

Para que Endpoints administre tu servicio gRPC, además del archivo proto compilado, debes especificar una configuración del servicio en uno o más archivos YAML. La configuración del servicio es una especificación que te permite definir el comportamiento de un servicio gRPC, incluidas la autenticación, las cuotas y más.

Descripción general de la configuración del servicio

En la parte superior del archivo YAML, especifica la información básica sobre el servicio, como su nombre o título. Configura otros aspectos del servicio en subsecciones del archivo YAML, por ejemplo:

Por ejemplo:

type: google.api.Service
config_version: 3
name: calendar.googleapis.com
title: Google Calendar API
apis:
- name: google.calendar.v3.Calendar
authentication:
  providers:
  - id: google_calendar_auth
    jwks_uri: https://www.googleapis.com/oauth2/v1/certs
    issuer: https://securetoken.google.com
  rules:
  - selector: "*"
    requirements:
      provider_id: google_calendar_auth
backend:
  rules:
    - selector: "*"
      address: grpcs://my-service-98sdf8sd0-uc.a.run.app

Cada subsección corresponde, por lo general, a un mensaje .proto, en el que configuras varios aspectos del servicio. Por ejemplo:

  • authentication: especifica cómo se autentican los emisores.
  • backend: controla el enrutamiento del backend remoto.
  • http: define las reglas para asignar un método RPC a uno o más métodos de la API de REST HTTP.
  • usage te permite habilitar o inhabilitar de manera selectiva la validación de la clave de API.

El esquema oficial para la configuración del servicio se define con el mensaje .proto google.api.Service.

Configuración básica

El ejemplo de Librería, que se usa en los instructivos de gRPC, incluye un archivo de definición de interfaz básica y un archivo de configuración del servicio.

La definición de la interfaz de Libreria, bookstore.proto:

syntax = "proto3";

package endpoints.examples.bookstore;

option java_multiple_files = true;
option java_outer_classname = "BookstoreProto";
option java_package = "com.google.endpoints.examples.bookstore";

import "google/protobuf/empty.proto";

service Bookstore {
  rpc ListShelves(google.protobuf.Empty) returns (ListShelvesResponse) {}
  rpc CreateShelf(CreateShelfRequest) returns (Shelf) {}
  rpc GetShelf(GetShelfRequest) returns (Shelf) {}
  rpc DeleteShelf(DeleteShelfRequest) returns (google.protobuf.Empty) {}
  rpc ListBooks(ListBooksRequest) returns (ListBooksResponse) {}
  rpc CreateBook(CreateBookRequest) returns (Book) {}
  rpc GetBook(GetBookRequest) returns (Book) {}
  rpc DeleteBook(DeleteBookRequest) returns (google.protobuf.Empty) {}
}

message Shelf {
  int64 id = 1;
  string theme = 2;
}

message Book {
  int64 id = 1;
  string author = 2;
  string title = 3;
}

La configuración del servicio de la Librería, api_config.yaml:

type: google.api.Service
config_version: 3

name: bookstore.endpoints.MY_PROJECT_ID.cloud.goog

title: Bookstore gRPC API
apis:
- name: endpoints.examples.bookstore.Bookstore

La muestra de código anterior es la configuración del servicio más simple por los siguientes motivos:

  • Define un servicio llamado bookstore.endpoints.MY_PROJECT_ID.cloud.goog, en el que MY_PROJECT_ID representa el ID de tu proyecto de Google Cloud.
  • Especifica que el servicio expone la API endpoints.examples.bookstore.Bookstore, como se define en el archivo bookstore.proto.
  • Proporciona un título descriptivo que aparece en la página Extremos > Servicios de la consola de Google Cloud después de implementar la configuración. Consulta las versiones completas de cada archivo en GitHub para obtener comentarios más detallados.

Reglas y selectores

En algunos casos, es posible que necesites la capacidad de asociar la configuración con elementos individuales de un servicio, por ejemplo, para aplicar la autenticación en ciertos métodos, pero no en otros. A fin de configurar esto en la configuración de tu servicio, algunas partes de la configuración del servicio, como authentication y http, te permiten especificar las reglas y los selectores. Un selector identifica los elementos del servicio, como el nombre del método al que se aplica la configuración asociada con la regla.

Un selector es una lista separada por comas de nombres calificados definidos en el servicio: método, mensaje, campo, enumeración o valores de enumeración. El último segmento del nombre puede ser el comodín *, que coincide con cualquier sufijo. Los comodines se permiten solo al final de un nombre y solo para un segmento completo del nombre. Por ejemplo: foo.* está bien, pero no foo.b* o foo.*.bar. A fin de configurar un valor predeterminado para todos los elementos aplicables, especifica * por su cuenta.

Ejemplo 1 (afecta a todo el servicio):

usage:
  rules:
  # Allow unregistered calls for all methods.
  - selector: "*"
    allow_unregistered_calls: true

Ejemplo 2 (afecta solo a un método):

usage:
  rules: # IMPORTANT: ONLY LAST MATCHING RULE IS APPLIED
  # Disable API key validation on just the ListShelves method
  # while requiring an API key for the rest of the API.
  - selector: "*"
    allow_unregistered_calls: false
  - selector: "endpoints.examples.bookstore.BookStore.ListShelves"
    allow_unregistered_calls: true

En el ejemplo anterior, se muestra cómo requerir la validación de la clave de API para todos los métodos, excepto para el ListShelves.

Las reglas se evalúan de forma secuencial; se aplica la última que coincide con una del orden de declaración.

Cómo usar varios archivos YAML

Puede resultarte útil usar más de un archivo YAML con el fin de configurar diferentes características para el mismo servicio. El uso de varios archivos YAML facilita la reutilización de archivos y su modificación para diferentes entornos. Por ejemplo, en la Librería de muestra, la configuración básica se especifica en el archivo api_config.yaml, y sus reglas HTTP, en el archivo api_config_http.yaml. Esto te permite implementar las reglas HTTP solo si deseas activar la transcodificación de JSON/HTTP a gRPC para la Librería.

Si usas varios archivos YAML para la configuración de tu servicio, cuando se implementa la configuración, cada archivo se convierte en mensajes proto google.api.Service y, luego, todos los mensajes se combinan mediante la semántica de combinación de proto. Es decir, todos los campos escalares singulares en la última instancia reemplazan a los de la anterior. Entonces, si proporcionas valores singulares diferentes para la misma regla en dos archivos, se usa el valor en el segundo archivo que especificaste cuando implementaste la configuración. Los mensajes incorporados singulares se combinan y los campos repetidos se concatenan.

Al igual que las reglas, la combinación es sensible al orden. Si hay dos configuraciones de servicio, la segunda anula la primera.

Anotaciones (solo reglas HTTP)

Como alternativa al uso de un archivo YAML para configurar las opciones de HTTP, puedes configurarlas directamente en tu archivo proto, mediante el uso de los mecanismos de opciones. Las anotaciones de la API se definen en annotations.proto.

Usa las anotaciones si la opción de configuración está destinada a ser invariante en todos los usos de la definición de la interfaz del búfer de protocolo. Por ejemplo, si una API tiene una sola implementación o es necesario que todas las implementaciones tengan la misma interfaz HTTP, puedes anotar la configuración HTTP en el archivo proto.

Si se proporciona una opción de configuración, tanto en el archivo proto como en el archivo YAML de configuración del servicio, la configuración del servicio anula la anotación.

Ejemplo de anotación en un archivo proto:

rpc ListShelves(google.protobuf.Empty) returns (ListShelvesResponse) {
    option (google.api.http) = { get: "/v1/shelves" };
}

# The preceding annotation is equivalent to the following service configuration:

http:
  rules:
  - selector: endpoints.examples.bookstore.BookStore.ListShelves
    get: '/v1/shelves'

Para obtener más información, consulta Transcodificar HTTP/JSON a gRPC.

Validación de la configuración

Para implementar tu configuración del servicio y los archivos proto compilados, usa el gcloud endpoints services deploy a fin de crear la configuración del entorno de ejecución del servicio. El comando gcloud endpoints services deploy valida la configuración del servicio y marca cualquier error y advertencia.

Las advertencias se dividen en regulares y de linter. Las advertencias de linter usan un identificador con la forma <group>-<rule>, en el que <group> indica el grupo de configuración y <rule>, la regla de linter particular. Por ejemplo, a continuación, el grupo es versioning y la regla es http-version-prefix:

WARNING: bookstore.proto:51:3: (lint) versioning-http-version-prefix: method
'endpoints.examples.bookstore.BookStore.ListShelves' has a different version
prefix in HTTP path ('v2') than api version 'v1'.

Puedes eliminar las advertencias de linter si agregas una directiva a la documentación de un elemento de la API. Puede agregar la directiva en tu archivo proto o en el archivo YAML de la configuración del servicio. Por ejemplo, lo siguiente elimina la advertencia previa:

service Bookstore {
  // Returns an object.
  // (== suppress_warning versioning-http-version-prefix ==)
  rpc ListShelves(google.protobuf.Empty) returns (ListShelvesResponse) {
      option (google.api.http) = { get: "/v1/shelves" };
  }
}

A fin de eliminar las advertencias para todo un grupo, puedes usar un comodín (*) en lugar de los nombres de las reglas. Por ejemplo, versioning-* suprime todas las advertencias relacionadas con el grupo versioning.

Las directivas de eliminación adjuntas a los elementos superiores también se aplican a todos los elementos secundarios. Por ejemplo, en el siguiente ejemplo, se eliminan todas las advertencias del grupo versioning en todos los métodos del servicio:

// (== suppress_warning versioning-* ==)
service Bookstore {
  // Returns an object.
  rpc ListShelves(google.protobuf.Empty) returns (ListShelvesResponse) {
      option (google.api.http) = { get: "/v1/shelves" };
  }
}

Para eliminar globalmente una advertencia, tienes que adjuntarla a la documentación general de la configuración del servicio:

type: google.api.Service
name: your_api.endpoints.<producer-project-id>.cloud.goog
title: Bookstore gRPC API
apis:
- name: endpoints.examples.bookstore.BookStore
documentation:
    overview: |
      A simple Bookstore gRPC API.
      (== suppress_warning documentation-presence ==)

Ten en cuenta que las directivas en la documentación, como suppress_warning, deben aparecer en su propia línea; de lo contrario, no serán reconocidas. Los marcadores literales de bloqueo de YAML, como >, quitan todas las líneas nuevas, así que si usas overview: > en el ejemplo anterior, la eliminación no funciona. Para obtener más información sobre literales de bloque en YAML, consulta Delimitación de sangría.

¿Qué sigue?