Configurar un servicio gRPC

Para crear un servicio gRPC, tanto si usas Cloud Endpoints como si no, debes especificar la definición de interfaz en uno o varios archivos proto, que son archivos de texto con la extensión .proto. En un archivo proto, se define la superficie de la API, incluidas las estructuras de datos, los métodos, los parámetros de los métodos y los tipos de valor devuelto. A continuación, compila el archivo proto con el compilador de búfer de protocolo específico del lenguaje, protoc. Para obtener más información, consulta ¿Qué es gRPC? y Conceptos de gRPC.

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

Información general sobre la configuración del servicio

En la parte superior del archivo YAML, especifica información básica sobre el servicio, como su nombre y título. Puedes configurar otros aspectos del servicio en las subsecciones del archivo YAML, como los siguientes:

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 suele corresponderse con un mensaje .proto en el que se configuran varios aspectos del servicio. Por ejemplo:

  • authentication: especifica cómo se autentican las personas que llaman.
  • backend: controla el enrutamiento del backend remoto.
  • http: define las reglas para asignar un método RPC a uno o varios métodos de la API REST HTTP.
  • usage: te permite habilitar e inhabilitar de forma selectiva la validación de claves de API.

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

Configuración básica

El ejemplo de librería, que se usa en los tutoriales de gRPC, incluye un archivo de definición de interfaz básico y un archivo de configuración de servicio.

Definición de la interfaz de Bookstore 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;
}

Configuración del servicio Bookstore 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

El ejemplo de código anterior es la configuración de servicio más sencilla, ya que:

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

Reglas y selectores

En algunos casos, es posible que necesites asociar una configuración a elementos concretos de un servicio. Por ejemplo, para aplicar la autenticación en determinados métodos, pero no en otros. Para configurar esto en la configuración de tu servicio, algunas partes de la configuración del servicio, como authentication y http, te permiten especificar reglas y selectores. Un selector identifica los elementos del servicio, como un nombre de método al que se aplica la configuración asociada a la regla.

Un selector es una lista separada por comas de nombres cualificados definidos en el servicio: método, mensaje, campo, enum o valores de enum. El último segmento del nombre puede ser el comodín *, que coincide con cualquier sufijo. Los comodines solo se pueden usar al final de un nombre y solo para un segmento completo del nombre. Por ejemplo, foo.* es correcto, pero no foo.b* ni foo.*.bar. Para configurar un valor predeterminado para todos los elementos aplicables, especifica * por sí solo.

Ejemplo 1 (afecta a todo el servicio):

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

Ejemplo 2 (afecta a un solo 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 el método ListShelves.

Las reglas se evalúan de forma secuencial y se aplica la última que coincida en el orden de declaración.

Usar varios archivos YAML

Puede que te resulte útil usar más de un archivo YAML para configurar diferentes funciones del mismo servicio. Si usas varios archivos YAML, te resultará más fácil reutilizar archivos y modificarlos para distintos entornos. Por ejemplo, en el ejemplo de librería, la configuración básica se especifica en el archivo api_config.yaml y sus reglas HTTP se especifican en el archivo api_config_http.yaml. De esta forma, puedes implementar las reglas HTTP solo si quieres activar la transcodificación de JSON/HTTP a gRPC para Bookstore.

Si usas varios archivos YAML para la configuración de tu servicio, cuando se despliega la configuración, cada archivo se convierte en mensajes proto google.api.Service y, a continuación, todos los mensajes se combinan mediante la semántica de combinación de proto. Es decir, todos los campos escalares singulares de la última instancia sustituyen a los de la primera. Por lo tanto, si proporciona valores únicos diferentes para la misma regla en dos archivos, se usará el valor del segundo archivo que especifique al implementar la configuración. Los mensajes insertados singulares se combinan y los campos repetidos se concatenan.

Al igual que con las reglas, el orden es importante en la combinación. Si hay dos configuraciones de servicio, la segunda anula la primera.

Anotaciones (solo reglas HTTP)

Como alternativa a usar un archivo YAML para configurar las opciones HTTP, puedes configurarlas directamente en el archivo proto mediante el mecanismo de opciones. Las anotaciones de la API se definen en annotations.proto.

Usa anotaciones si la opción de configuración debe ser invariable en todos los usos de la definición de interfaz de búfer de protocolo. Por ejemplo, si una API tiene una sola implementación o todas las implementaciones deben tener 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 el artículo Transcodificar HTTP/JSON a gRPC.

Validación de la configuración

Para desplegar la configuración de tu servicio y los archivos proto compilados, usa gcloud endpoints services deploy para crear la configuración del tiempo de ejecución de tu servicio. El comando gcloud endpoints services deploy valida la configuración del servicio y señala los errores y las advertencias.

Las advertencias se dividen en advertencias normales y de linter. Las advertencias de Linter usan un identificador con el formato <group>-<rule>, donde <group> indica el grupo de configuración y <rule> la regla de Linter concreta. Por ejemplo, debajo del grupo está 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 suprimir las advertencias del linter añadiendo una directiva a la documentación de un elemento de la API. Puedes añadir la directiva en el archivo proto o en el archivo YAML de configuración del servicio. Por ejemplo, la siguiente línea suprime la advertencia anterior:

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" };
  }
}

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

Las directivas de supresión asociadas a elementos superiores también se aplican a todos los elementos secundarios. Por ejemplo, en el siguiente ejemplo se suprimen todas las advertencias de versioning group 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 suprimir una advertencia de forma global, adjúntala 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 de la documentación, como suppress_warning, deben aparecer en una línea independiente. De lo contrario, no se reconocerán. Los marcadores literales de bloque de YAML, como >, eliminan todos los saltos de línea, por lo que, si usas overview: > en el ejemplo anterior, la supresión no funcionará. Para obtener más información sobre los literales de bloque en YAML, consulta Delimitación con sangría.

Siguientes pasos