Como configurar um serviço gRPC

Para criar um serviço gRPC, mesmo que você não use o Cloud Endpoints, especifique a definição da interface em um ou mais arquivos proto, que são arquivos de texto com a extensão .proto. Em um arquivo proto, você define a superfície da API, incluindo as estruturas de dados, os métodos, os parâmetros do método e os tipos de retorno. Em seguida, compile seu arquivo proto usando o compilador de buffer de protocolo específico da linguagem, protoc. Para mais informações, consulte O que é gRPC? e Conceitos de gRPC (links em inglês).

Para que o serviço gRPC seja gerenciado pelo Endpoints, além do arquivo proto compilado, é preciso especificar uma configuração de serviço em um ou mais arquivos YAML. Uma configuração de serviço é uma especificação que permite definir o comportamento de um serviço gRPC, incluindo autenticação, cotas e muito mais.

Visão geral da configuração de serviço

Na parte superior do arquivo YAML, especifique as informações básicas sobre o serviço, como nome e título. Configure outros aspectos do serviço nas subseções do arquivo YAML. Veja alguns exemplos:

Exemplo:

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

Normalmente, cada subseção corresponde a uma mensagem .proto (em inglês), em que vários aspectos do serviço são configurados. Exemplo:

  • authentication: especifica como os chamadores são autenticados.
  • backend: controla o roteamento remoto de back-end.
  • http: define as regras para mapear um método RPC para um ou mais métodos da API REST HTTP.
  • usage: permite ativar e desativar seletivamente a validação da chave de API.

O esquema oficial da configuração do serviço é definido pela mensagem .proto google.api.Service (em inglês).

Configuração básica

A amostra Bookstore, usada nos tutoriais do gRPC, inclui um arquivo de definição de interface básico e um de configuração de serviço.

A definição da interface Bookstore, bookstore.proto (em inglês):

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

A configuração do serviço Bookstore, api_config.yaml (em inglês):

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

O exemplo de código anterior é a configuração de serviço mais simples, já que:

  • define um serviço chamado bookstore.endpoints.MY_PROJECT_ID.cloud.goog, em que MY_PROJECT_ID representa seu ID de projeto do Google Cloud;
  • especifica que o serviço expõe a API endpoints.examples.bookstore.Bookstore, conforme definido no arquivo bookstore.proto;
  • fornece um título descritivo que aparece na página Endpoints > Serviços no console do Google Cloud depois que você implanta a configuração. Para comentários mais detalhados, analise as versões completas de cada arquivo no GitHub.

Regras e seletores

Em alguns casos, será preciso associar a configuração a elementos individuais de um serviço. Por exemplo, para impor a autenticação em determinados métodos, mas não em outros. Para fazer isso na configuração do serviço, algumas partes dela, como authentication e http, permitem especificar regras e seletores. Um seletor identifica os elementos do serviço, como um nome de método a que a configuração associada à regra se aplica.

Um seletor é uma lista separada por vírgulas de nomes qualificados de serviço, método, mensagem, campo, "enum" ou valores de "enum". O último segmento do nome pode ser o caractere curinga *, que corresponde a qualquer sufixo. Caracteres curinga são permitidos apenas no final de um nome e apenas para um segmento inteiro do nome. Por exemplo: foo.* está correto, mas não foo.b* ou foo.*.bar. Para configurar um padrão para todos os elementos aplicáveis, especifique * por si só.

Exemplo 1 (afeta todo o serviço):

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

Exemplo 2 (afeta um único 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

O exemplo anterior mostra como exigir a validação de chave de API para todos os métodos, exceto o ListShelves.

As regras são avaliadas sequencialmente, o último correspondente na ordem de declaração é aplicado.

Como usar vários arquivos YAML

Pode ser útil usar mais de um arquivo YAML para configurar recursos diferentes para o mesmo serviço. O uso de vários arquivos YAML facilita a reutilização e modificação de arquivos para diferentes ambientes. Por exemplo, no exemplo do Bookstore, a configuração básica é especificada no arquivo api_config.yaml e suas regras HTTP estão no arquivo api_config_http.yaml (links em inglês). Isso só permite implantar as regras de HTTP se você quiser ativar o JSON/HTTP para transcodificação de gRPC para a Bookstore.

Se você usar vários arquivos YAML para a configuração do serviço, quando a configuração for implantada, cada arquivo será convertido em mensagens proto de google.api.Service (em inglês). Todas as mensagens serão mescladas usando proto mesclando semântica. Ou seja, todos os campos escalares singulares da última instância substituirão os da primeira. Portanto, ao fornecer diferentes valores singulares para a mesma regra em dois arquivos, o valor no segundo arquivo especificado ao implantar a configuração será usado. Mensagens incorporadas singulares serão mescladas e campos repetidos serão concatenados.

Assim como as regras, a mesclagem é sensível à ordem. Se houver duas configurações de serviço, a segunda substituirá a primeira.

Anotações (apenas regras HTTP)

Em vez de usar um arquivo YAML para configurar as opções de HTTP, é possível fazer isso diretamente no arquivo proto, usando o mecanismo de opções (em inglês). As anotações da API estão definidas em annotations.proto (em inglês).

Use anotações se a opção de configuração for invariável ao longo de todos os usos da definição de interface do buffer de protocolo. Por exemplo, se uma API tiver uma única implementação ou todas as implementações forem obrigadas a ter a mesma interface HTTP, anote a configuração de HTTP no arquivo proto.

Se uma opção de configuração for fornecida, tanto no arquivo proto quanto no YAML da configuração de serviço, ela substituirá a anotação.

Anotação de exemplo em um arquivo 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 mais informações, consulte Como transcodificar HTTP/JSON para gRPC.

Validação de configuração

É preciso implantar a configuração de serviço e compilar os arquivos proto usando gcloud endpoints services deploy para criar a configuração do ambiente de execução de seu serviço. O comando gcloud endpoints services deploy valida a configuração do serviço e sinaliza quaisquer erros e avisos.

Os avisos são divididos em regulares e linter. Os avisos do Linter usam um identificador da forma <group>-<rule>, em que <group> indica o grupo de configuração e <rule> a regra de linter específica. Por exemplo, abaixo do grupo é versioning e a regra é 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'.

Para suprimir avisos linter, basta adicionar uma diretiva à documentação de um elemento da API. Isso pode ser feito no arquivo proto ou YAML da configuração de serviço. Por exemplo, o aviso acima é suprimido da seguinte maneira:

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 avisos de todo um grupo, use um caractere curinga (*) em vez de nomes de regras. Por exemplo, versioning-* suprime todos os avisos relacionados ao grupo versioning.

As diretivas de supressão anexadas a elementos pai também se aplicam a todos os elementos secundários. Por exemplo, o exemplo a seguir suprime todos os avisos de grupo versioning em todos os métodos no serviço:

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

Para suprimir globalmente um aviso, anexe-o à documentação geral da configuração do serviço:

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 ==)

As diretrizes na documentação, como suppress_warning aparecem em sua própria linha, caso contrário, eles não serão reconhecidos. Os marcadores de literal de bloco YAML, como >, removem todas as novas linhas, por isso, se você usar overview: > no exemplo anterior, a supressão não funcionará. Para mais informações sobre literais em bloco do YAML, consulte Delimitação recuada (em inglês).

A seguir