O Cloud Endpoints suporta a transcodificação de protocolos para que os clientes possam aceder à sua API gRPC através de HTTP/JSON. O proxy de serviço extensível (ESP) transcodifica HTTP/JSON para gRPC.
Este guia descreve:
- Como usar anotações no seu ficheiro
.proto
para especificar a conversão de dados de HTTP/JSON para gRPC - Como implementar o seu serviço nos Endpoints para usar esta funcionalidade
- Onde encontrar mais informações de referência sobre a conceção e a implementação da transcodificação para serviços gRPC
Parte do princípio de que já concluiu os nossos tutoriais do gRPC e que conhece os conceitos básicos dos pontos finais das APIs gRPC.
Conceber uma API compatível com a transcodificação
A transcodificação envolve o mapeamento de pedidos HTTP/JSON e os respetivos parâmetros para métodos gRPC e os respetivos parâmetros e tipos de retorno. Por este motivo, embora seja possível mapear um pedido HTTP/JSON para qualquer método de API arbitrário, é útil fazê-lo se a API gRPC estiver estruturada de uma forma orientada para recursos, tal como uma API REST HTTP tradicional. Por outras palavras, concebe o serviço de API de modo que utilize um pequeno número de métodos padrão, correspondentes a verbos HTTP, como GET
e PUT
, que operam nos recursos e nas coleções de recursos do serviço, que são, em si mesmos, um tipo de recurso. Estes métodos padrão são List
,
Get
, Create
, Update
e Delete
.
Se necessário, a API também pode ter alguns métodos personalizados não padrão, embora não seja tão simples mapeá-los.
Pode saber muito mais sobre o design orientado para recursos e os mapeamentos de transcodificação padrão no guia de design de APIs. Este guia de design é a norma de design seguida na Google ao criar APIs públicas, como as APIs Cloud. Embora não precise de seguir este guia para usar a transcodificação gRPC, recomendamos vivamente que o faça. Em particular, as seguintes páginas podem ajudar a compreender estes princípios de design e adicionar mapeamentos de transcodificação úteis aos seus métodos:
- Design orientado para recursos
- Métodos padrão
- Métodos personalizados
- Verbos HTTP: esta página fornece diretrizes adicionais para as implementações de métodos se forem acedidas através de HTTP.
A seguinte página de referência também pode ser útil:
- Referência da regra HTTP: uma referência abrangente para regras de mapeamento HTTP,
No resto deste documento, usa o exemplo da livraria que usou nos nossos tutoriais, que já usa estes princípios.
A livraria tem coleções de "prateleiras" de recursos de "livros", que os utilizadores podem List
, Get
, Create
ou Delete
.
Onde configurar a transcodificação
A transcodificação de gRPC está ativada por predefinição e pode usá-la sem qualquer configuração. Siga as instruções para
implementar um serviço através da transcodificação.
Posteriormente, quando envia um pedido HTTP POST
para o caminho do URL
GRPC_SERVICE_FULL_NAME/METHOD_NAME>
com os valores dos campos da mensagem de pedido do método (se existirem) como JSON no corpo do pedido HTTP,
o ESP envia a mensagem de pedido para o método gRPC adequado. No exemplo anterior, GRPC_SERVICE_FULL_NAME
é o nome completo do seu serviço gRPC e METHOD_NAME
é o nome do método.
Por exemplo, se enviar um POST
para o URL ListShelves
da livraria da seguinte forma:
curl -XPOST http://mydomain/endpoints.examples.bookstore.Bookstore/ListShelves
Recebe uma lista atual de prateleiras no formato JSON.
No entanto, é altamente preferível em termos de design de interface HTTP configurar explicitamente os mapeamentos, conforme descrito no resto deste documento.
A norma de configuração da API gRPC para a configuração de serviços permite-lhe especificar exatamente como os dados devem ser traduzidos de HTTP/JSON para gRPC. São suportados dois mecanismos para o fazer: anotações diretas no ficheiro .proto
e em YAML como parte do ficheiro de configuração da API gRPC. Recomendamos a utilização de anotações proto
para facilitar a leitura e a manutenção.
Para mais informações sobre a configuração YAML e quando pode precisar de a usar, consulte o artigo Configurar a transcodificação em YAML.
Segue-se um exemplo que usa a abordagem recomendada da livraria:
// 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 anotação indica ao ESP que fazer um pedido HTTP GET
com o URL http://mydomain/v1/shelves/1
chama o método GetShelf()
do servidor gRPC, com um GetShelfRequest
que contém o ID da prateleira pedido shelf
(neste caso, 1
).
Adicionar mapeamentos de transcodificação
Esta secção descreve algumas anotações de mapeamento adicionais do exemplo da livraria. Existem dois ficheiros proto
de exemplo no exemplo da livraria para que possa implementá-lo com ou sem os mapeamentos de transcodificação e comparar as diferenças nos ficheiros proto
:
bookstore.proto
: usado nos tutoriais de pontos finais e não tem mapeamentos de transcodificação.http_bookstore.proto
: associações de transcodificação adicionadas.
Para um guia mais abrangente sobre como especificar mapeamentos de transcodificação, consulte os métodos padrão, os métodos personalizados e a referência de regras HTTP.
Mapeie um método List
O método List
é definido no ficheiro .proto
com o respetivo tipo de resposta:
// 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; }
A anotação em negrito especifica o mapeamento HTTP para este método.
option (google.api.http)
especifica que este método é uma anotação de mapeamento HTTP gRPC.get
especifica que este método está mapeado para um pedido HTTPGET
."/v1/shelves"
é o modelo do caminho do URL (anexado ao domínio do seu serviço) que o pedidoGET
usa para chamar este método. O caminho do URL também é conhecido como caminho do recurso porque especifica normalmente a "coisa" ou o recurso que quer usar. Neste caso, todos os recursos da prateleira da nossa livraria.
Por exemplo, se um cliente chamar este método enviando um GET
para o URL
http://mydomain/v1/shelves
, o ESP chama o método gRPC
ListShelves()
. Em seguida, o back-end gRPC devolve as prateleiras, que o ESP converte para o formato JSON e devolve ao cliente.
Mapeie um método Get
O método GetShelf
da livraria está definido no ficheiro .proto
com os respetivos tipos de pedido e resposta:
// 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; }
A anotação em negrito especifica o mapeamento HTTP para este método.
option (google.api.http)
especifica que este método é uma anotação de mapeamento HTTP gRPC.get
especifica que este método está mapeado para um pedido HTTPGET
."/v1/shelves/{shelf}"
é o caminho do URL para o pedido, como antes, mas especifica/v1/shelves/
e, em seguida,{shelf}
. Esta notação com chavetas indica ao ESP que o que estiver em{shelf}
é o valor que deve fornecer parashelf
no parâmetroGetShelfRequest
do método.
Se um cliente chamar este método enviando um GET
para o URL http://mydomain/v1/shelves/4
, o ESP cria um GetShelfRequest
com um valor shelf
de 4
e, em seguida, chama o método gRPC GetShelf()
com o mesmo. Em seguida, o back-end gRPC devolve o Shelf
com o ID 4
, que o ESP converte para o formato JSON e devolve ao cliente.
Este método só requer que o cliente forneça um único valor de campo de pedido, shelf
, que especifica no modelo de caminho do URL com a notação de "captura" entre chavetas. Também pode capturar várias partes do URL, se necessário, para identificar o recurso pedido. Por exemplo, o método GetBook
precisa que o cliente especifique o ID da prateleira e o ID do livro no 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;
}
Além de literais e chaves de captura para valores de campos, os modelos de caminho de URL podem usar carateres universais para indicar que tudo nesta parte do URL deve ser capturado. A notação {shelf}
usada no exemplo anterior é, na verdade, um atalho para {shelf=*}
. Pode saber mais acerca das regras para modelos de caminhos na referência de regras HTTP.
No caso deste tipo de método, não existe um corpo de pedido HTTP especificado. Pode encontrar mais diretrizes para mapear métodos Get
, incluindo a utilização de parâmetros de consulta, em Métodos padrão.
Mapeie um método Create
O método CreateShelf
da livraria é mapeado para 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 é uma anotação de mapeamento HTTP gRPC.post
especifica que este método está mapeado para um pedido HTTPPOST
."/v1/shelves"
é o caminho do URL do pedido, como antes.body: "shelf"
é usado no corpo do pedido HTTP para especificar o recurso que quer adicionar no formato JSON.
Por exemplo, se um cliente chamasse este método da seguinte forma:
curl -d '{"theme":"Music"}' http://DOMAIN_NAME/v1/shelves
O ESP usa o corpo JSON para criar um valor Shelf
com o tema "Music"
para o CreateShelfRequest
e, em seguida, chama o método CreateShelf()
gRPC. Tenha em atenção que o cliente não fornece o valor id
para o Shelf
.
Os IDs das prateleiras da livraria são fornecidos pelo serviço quando cria uma nova prateleira.
Faculta este tipo de informações aos utilizadores do seu serviço na documentação da API.
Use o caráter universal no corpo
O nome especial *
pode ser usado no mapeamento do corpo para indicar que todos os campos não associados ao modelo de caminho devem ser mapeados para o corpo do pedido.
Isto permite a seguinte definição alternativa do 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 é uma anotação de mapeamento HTTP gRPC.post
especifica que este método está mapeado para um pedido HTTPPOST
."/v1/shelves/{shelf_id}"
é o caminho do URL para o pedido. O que estiver em{shelf_id}
é o valor do camposhelf_id
emCreateShelfRequest
.body: "*"
é usado no corpo do pedido HTTP para especificar todos os campos de pedido restantes, excetoshelf_id
neste exemplo, e sãoshelf_theme
eshelf_size
. Para quaisquer campos no corpo JSON com estes dois nomes, os respetivos valores são usados nos campos correspondentes deCreateShelfRequest
.
Por exemplo, se um cliente chamou este método da seguinte forma:
curl -d '{"shelf_theme":"Music", "shelf_size": 20}' http://DOMAIN_NAME/v1/shelves/123
O ESP usa o corpo JSON e o modelo de caminho para criar um CreateShelfRequest{shelf_id: 123 shelf_theme: "Music" shelf_size: 20}
e, em seguida, usa-o para chamar o método CreateShelf()
gRPC. Para obter detalhes, consulte a secção HttpRule.
Configurar a transcodificação em YAML
Uma abordagem alternativa é especificar os mapeamentos HTTP para gRPC no ficheiro YAML de configuração da API gRPC, em vez de no ficheiro .proto
. Pode ter de configurar a transcodificação num ficheiro YAML se tiver uma única definição da API proto
usada em vários serviços, com mapeamentos diferentes especificados para cada serviço.
O elemento rules
na secção http
do seu ficheiro YAML especifica como mapear pedidos HTTP/JSON para métodos 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}
...
Pode encontrar um exemplo mais completo da utilização desta abordagem para o serviço de livraria de exemplo em api_config_http.yaml
.
Implementar um serviço que usa a transcodificação
A implementação de um serviço gRPC que usa a transcodificação é muito semelhante à implementação de qualquer outro serviço gRPC, com uma grande diferença. Nos
tutoriais, o exemplo necessário para aceitar pedidos gRPC
do cliente de exemplo. No entanto, se quiser que a livraria também aceite pedidos HTTP, tem de fazer alguma configuração adicional para o ESP. Os clientes usam o protocolo HTTP1.1
para enviar pedidos JSON/HTTP para o ESP, pelo que o ESP tem de ser configurado para usar SSL (a porta SSL pode suportar ambos os tipos de pedidos) ou ter uma porta especial ativada para aceitar estas chamadas. A implementação é, de resto, muito semelhante à do tutorial para o ambiente escolhido.
Certifique-se de que as regras HTTP estão implementadas
Se já transferiu o exemplo da livraria para os
Tutoriais, tenha em atenção que tem de transferir uma
versão ligeiramente diferente do ficheiro .proto
com anotações,
http_bookstore.proto
.
Também tem de clonar o repositório
googleapis
do GitHub
antes de executar protoc
, uma vez que precisa de
annotations.proto
no caminho de inclusão.
git clone https://github.com/googleapis/googleapis
GOOGLEAPIS_DIR=<your-local-googleapis-folder>
Em seguida, crie um novo descritor .pb
a partir de http_bookstore.proto
quando
implementar
a sua configuração nos Endpoints:
protoc \
--include_imports \
--include_source_info \
--proto_path=${GOOGLEAPIS_DIR} \
--proto_path=. \
--descriptor_set_out=api_descriptor.pb \
http_bookstore.proto
Se estiver a usar o método alternativo de configuração de mapeamentos HTTP no ficheiro YAML de configuração da API gRPC, também tem de garantir que as regras relevantes são implementadas quando implementa a configuração nos Endpoints. Para experimentar isto com o serviço Bookstore, as respetivas regras básicas encontram-se no ficheiro api_config.yaml
e as respetivas regras HTTP encontram-se no ficheiro api_config_http.yaml
:
gcloud endpoints services deploy api_descriptor.pb api_config.yaml api_config_http.yaml
Usar SSL
Se o SSL estiver ativado para a comunicação entre os seus clientes e o ESP,
os clientes podem usar a mesma porta para fazer chamadas gRPC ou HTTP1.1
. Pode saber como configurar o SSL para um serviço de Endpoints em Ativar SSL.
Especifique uma porta para o ESP aceitar chamadas SSL através da flag --ssl_port
no ficheiro de configuração do Google Kubernetes Engine (GKE) ou do 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",
]
Configurar uma porta HTTP1.1
Se não estiver a usar SSL, tem de configurar uma porta separada para pedidos HTTP1.1
, porque o gRPC e o HTTP1.1
não podem partilhar a mesma porta sem SSL. Use a flag --http_port
no ficheiro de configuração do GKE ou o comando docker run
para especificar uma porta para aceitar chamadas HTTP1.1
. Se também quiser que o ESP aceite chamadas gRPC, tem de usar a flag --http2_port
para especificar uma porta 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",
]
Chamar um serviço através da transcodificação
Esta secção descreve a configuração do serviço e como fazer chamadas HTTP para o serviço.
Configuração do serviço
Isto pressupõe que já concluiu os tutoriais básicos do serviço gRPC para o ambiente escolhido e que tem um cluster do GKE ou uma instância do Compute Engine para executar o exemplo.
- Primeiro, certifique-se de que implementou a configuração do serviço Bookstore ativado para HTTP nos Endpoints, conforme descrito em Certifique-se de que as regras HTTP estão implementadas.
Implemente o back-end e o ESP conforme descrito no tutorial para a plataforma escolhida, usando a flag
--http_port
para ativar uma porta para pedidosHTTP1.1
:- Implementação do GKE: siga as instruções em
Implementar a API de exemplo e o ESP no cluster,
certificando-se de que a flag
"--http_port"
está especificada no ficheiro de configuração do GKE. - Implementação do Compute Engine: siga as instruções em Executar a API de exemplo e o ESP num contentor Docker.
Certifique-se de que a flag
--http_port
é especificada no comandodocker run
quando executar o contentor do Docker do ESP pré-embalado.
- Implementação do GKE: siga as instruções em
Implementar a API de exemplo e o ESP no cluster,
certificando-se de que a flag
Fazer chamadas HTTP para o serviço
- Obtenha o endereço IP externo do ESP e defina-o como
$ESP_IP
. Faça o seguinte pedido HTTP com
curl
curl http://$ESP_IP/v1/shelves
(ou use o mesmo URL com
https://
se estiver a usar SSL). O servidor responde com:{"shelves":[{"id":"1","theme":"Fiction"},{"id":"2","theme":"Fantasy"}]}
Se a saída apresentar uma resposta binária, verifique a configuração da porta, porque pode estar a aceder à porta HTTP2 em vez da porta HTTP.
Experimente um método
Create
.CreateShelf
requer uma chave da API, pelo que tem de criar uma chave para o seu projeto e defini-la como$KEY
. Ligue agora para:curl -d '{"theme":"Music"}' http://$ESP_IP/v1/shelves?key=$KEY
Se ligar novamente para
GetShelves
, deve ver a nova prateleira.