O Cloud Endpoints é compatível com transcodificação de protocolo para que os clientes possam acessar sua API gRPC usando HTTP/JSON. O Extensible Service Proxy (ESP) transcodifica HTTP/JSON para gRPC.
Este guia descreve:
- como usar anotações no arquivo
.proto
para especificar a conversão de dados de HTTP/JSON para gRPC; - como implantar seu serviço no Endpoints para usar esse recurso;
- onde encontrar mais informações de referência sobre como projetar e implementar a transcodificação para serviços gRPC.
Partimos do princípio que você já concluiu nossos tutoriais sobre gRPC e que conheça os conceitos básicos do Endpoints para APIs gRPC.
Como projetar uma API pronta para transcodificação
A transcodificação envolve o mapeamento de solicitações HTTP/JSON e os respectivos parâmetros para os métodos gRPC, além dos parâmetros e tipos de retorno delas. Por isso, embora seja possível mapear uma solicitação HTTP/JSON em qualquer método de API arbitrário, será melhor se a API gRPC for estruturada com foco nos recursos, como uma API REST HTTP (em inglês) comum. Em outras palavras, o serviço da API é criado para usar um número pequeno de métodos padrão, correspondentes a verbos HTTP, como GET
e PUT
. Esses métodos operam nos recursos e nos conjuntos dos recursos (que também são um tipo de recurso) do serviço. Esses métodos padrão são List
, Get
, Create
, Update
e Delete
.
Se necessário, a API pode também ter alguns métodos personalizados não padrão, mas eles não são muito simples de mapear.
É possível descobrir muito mais sobre o projeto voltado para recursos e os mapeamentos de transcodificação padrão no guia de projeto da API. Esse é o guia de projeto padrão seguido no Google ao projetar APIs públicas, como APIs do Cloud. Não é preciso segui-lo para usar a transcodificação do gRPC, mas é altamente recomendável. Você entenderá melhor os princípios de projeto e aprenderá a adicionar mapeamentos de transcodificação úteis aos métodos nestas páginas:
- Projeto voltado para recursos
- Métodos padrão
- Métodos personalizados
- Verbos HTTP: são fornecidas diretrizes adicionais para as implementações de métodos, caso sejam acessadas por HTTP.
Esta página de referência também pode ser útil:
- Referência de regra HTTP: uma referência abrangente de regras de mapeamento HTTP
No restante do documento, você usa o exemplo Bookstore usado em nossos tutoriais, que já usa esses princípios.
Ele tem coleções com "estante" de recursos de "livros" que os usuários podem List
, Get
, Create
ou Delete
.
Onde configurar a transcodificação
A transcodificação de gRPC está ativada por padrão, e você pode usá-la sem qualquer configuração. Siga as instruções para saber como implantar um serviço usando transcodificação.
O ESP enviará a mensagem de solicitação ao método do gRPC apropriado, depois que uma solicitação POST
HTTP for enviada para o caminho GRPC_SERVICE_FULL_NAME/METHOD_NAME>
do URL com os valores do campo de mensagem de solicitação do método (se houver) como JSON no corpo da solicitação HTTP. No exemplo anterior, GRPC_SERVICE_FULL_NAME
é o nome completo do serviço gRPC e METHOD_NAME
é o nome do método.
Por exemplo, ao enviar uma solicitação POST
ao URL ListShelves
do Bookstore da seguinte forma:
curl -XPOST http://mydomain/endpoints.examples.bookstore.Bookstore/ListShelves
você receberá uma lista atual de estantes no formato JSON.
No entanto, em termos de projeto de interface HTTP, é altamente preferível a configuração explícita dos mapeamentos, conforme descrito no restante deste documento.
O padrão da API gRPC para configuração do serviço permite especificar exatamente como os dados serão convertidos de HTTP/JSON para gRPC. Há dois mecanismos que permitem fazer isso: anotações diretas no arquivo .proto
e no YAML como parte do arquivo de configuração da API gRPC. É recomendado o uso de anotações proto
para facilitar a leitura e a manutenção.
Para mais informações sobre a configuração do YAML e quando é preciso usá-lo, consulte Como configurar a transcodificação no YAML.
Veja um exemplo com a abordagem recomendada 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;
}
Com essa anotação, o ESP é informado de que uma solicitação GET
HTTP feita com o URL http://mydomain/v1/shelves/1
chamará o método GetShelf()
do servidor de gRPC, com um GetShelfRequest
contendo shelf
do ID da estante solicitado (neste caso, 1
).
Como adicionar mapeamentos de transcodificação
Nesta seção, são descritas outras anotações de mapeamento do exemplo Bookstore. Nele, há dois arquivos proto
de amostra para você implantá-lo com ou sem os mapeamentos de transcodificação e comparar as diferenças nos arquivos proto
:
bookstore.proto
(em inglês): usado nos tutoriais do Endpoints e não tem mapeamentos de transcodificação.http_bookstore.proto
(em inglês): vinculações de transcodificação adicionadas.
Para um guia mais abrangente sobre como especificar mapeamentos de transcodificação, consulte Métodos padrão, Métodos personalizados e Referência de regra HTTP.
Mapear um método List
O método List
é definido no arquivo .proto
com o respectivo 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 desse método.
option (google.api.http)
especifica que esse método é uma anotação de mapeamento HTTP do gRPC.get
especifica que esse método é mapeado em uma solicitação HTTPGET
."/v1/shelves"
é o modelo de caminho de URL (anexado ao domínio do serviço) que a solicitaçãoGET
usa para chamar esse método. O caminho do URL também é conhecido como caminho do recurso, já que normalmente especifica o que ou qual recurso será usado. Neste caso, todos os recursos de estante do Bookstore.
Por exemplo, se um cliente chamar esse método enviando um GET
ao URL http://mydomain/v1/shelves
, o ESP chamará o método ListShelves()
do gRPC. Em seguida, o back-end do gRPC retornará as estantes, que o ESP converte no formato JSON e retornará ao cliente.
Mapear um método Get
O método GetShelf
do Bookstore é definido no arquivo .proto
com os respectivos tipos de solicitação 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 desse método.
option (google.api.http)
especifica que esse método é uma anotação de mapeamento HTTP do gRPC.get
especifica que esse método é mapeado em uma solicitação HTTPGET
."/v1/shelves/{shelf}"
é o caminho do URL para a solicitação, mas especifica/v1/shelves/
e, em seguida,{shelf}
. Com essa notação entre chaves, o ESP é informado de que o que está em{shelf}
é o valor a ser fornecido parashelf
no parâmetroGetShelfRequest
do método.
Se um cliente chamar esse método enviando uma solicitação GET
ao URL http://mydomain/v1/shelves/4
, o ESP criará um GetShelfRequest
com um valor shelf
de 4
e chamará o método GetShelf()
do gRPC com ele. Em seguida, o back-end do gRPC retornará o Shelf
solicitado com o ID 4
, que o ESP converterá no formato JSON e retornará ao cliente.
Esse método requer apenas que um único valor do campo de solicitação seja fornecido pelo cliente, shelf
, especificado no modelo de caminho do URL com a notação de "captura" entre chaves. Se necessário, também é possível capturar várias partes do URL para identificar o recurso solicitado. Por exemplo, o método GetBook
precisa que o cliente especifique o ID da estante e 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;
}
Assim como os literais e as chaves de captura para valores de campo, os modelos de caminho do URL podem usar curingas para indicar que qualquer elemento nesta parte do URL precisa ser capturado. A notação {shelf}
usada no exemplo anterior é, na verdade, um atalho para {shelf=*}
. Saiba mais sobre as regras de modelos de caminho em Referência da regra HTTP.
Neste tipo de método, não há nenhum corpo de solicitação HTTP especificado. Encontre mais orientações sobre como mapear métodos Get
, inclusive para usar parâmetros de consulta, em Métodos padrão.
Mapear um método Create
O método CreateShelf
do Bookstore mapeia em 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 esse método é uma anotação de mapeamento HTTP do gRPC.post
especifica que esse método é mapeado em uma solicitação HTTPPOST
."/v1/shelves"
é o caminho do URL da solicitação, conforme descrito anteriormente.body: "shelf"
é usado no corpo da solicitação HTTP para especificar o recurso a ser adicionado, no formato JSON.
Por exemplo, se um cliente chamou esse método assim:
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 CreateShelfRequest
e, em seguida, chama o método CreateShelf()
do gRPC. O cliente não fornece o valor id
para o Shelf
.
Ao criar uma nova estante, os IDs de estante do Bookstore são fornecidos pelo serviço.
Forneça esse tipo de informação aos usuários do seu serviço na documentação da API.
Usar caractere curinga no corpo
O nome especial *
pode ser usado no mapeamento do corpo para indicar que cada campo não vinculado ao modelo de caminho deve ser mapeado para o corpo da solicitação.
Isso 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 esse método é uma anotação de mapeamento HTTP do gRPC.post
especifica que esse método é mapeado em uma solicitação HTTPPOST
."/v1/shelves/{shelf_id}"
é o caminho do URL da solicitação. O valor em{shelf_id}
é o valor do camposhelf_id
emCreateShelfRequest
.body: "*"
é usado no corpo da solicitação HTTP para especificar todos os campos de solicitação restantes, excetoshelf_id
neste exemplo, e sãoshelf_theme
eshelf_size
. Para qualquer campo no corpo JSON com esses dois nomes, os valores serão usados nos campos correspondentes deCreateShelfRequest
.
Por exemplo, se um cliente chamou esse método assim:
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()
do gRPC. Para detalhes, consulte a HttpRule.
Configurar a transcodificação no YAML
Outra abordagem possível é especificar os mapeamentos de HTTP para gRPC no arquivo YAML de configuração da API gRPC, e não no arquivo .proto
. Se você tiver uma única definição de API proto
usada em vários serviços, com diferentes mapeamentos especificados para cada um deles, será preciso configurar a transcodificação em um arquivo YAML.
As rules
na seção http
do arquivo YAML especificam como mapear solicitações HTTP/JSON em 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}
...
Um exemplo mais completo de uso dessa abordagem para o serviço de exemplo Bookstore está em api_config_http.yaml
(em inglês).
Como implantar um serviço que usa transcodificação
A implantação do serviço gRPC que usa transcodificação é semelhante à implantação de qualquer outro serviço gRPC, porém com uma importante diferença. Nos tutoriais, o exemplo precisava aceitar solicitações gRPC do cliente de amostra. No entanto, caso queira que o Bookstore também aceite solicitações HTTP, será necessário fazer outras configurações para o ESP. Os clientes usam o protocolo HTTP1.1
para enviar solicitações JSON/HTTP ao ESP. Portanto, ele precisa ser configurado para usar SSL (a porta SSL é compatível com ambos os tipos de solicitação) ou ter uma porta especial ativada para aceitar essas chamadas. Via de regra, a implantação é igual ao que consta no tutorial para o ambiente escolhido.
Garantir que regras HTTP sejam implantadas
Se você já tiver o download do exemplo do Bookstore para os Tutoriais, é preciso fazer o download de uma versão um pouco diferente do arquivo .proto
com anotações, http_bookstore.proto
(em inglês).
Também é preciso clonar o repositório googleapis
(em inglês) do GitHub antes de executar protoc
, porque é necessário ter o annotations.proto
(em inglês) 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
ao implantar a configuração no Endpoints:
protoc \
--include_imports \
--include_source_info \
--proto_path=${GOOGLEAPIS_DIR} \
--proto_path=. \
--descriptor_set_out=api_descriptor.pb \
http_bookstore.proto
Se estiver usando o método alternativo de configuração dos mapeamentos HTTP no arquivo YAML de configuração da API gRPC, será preciso garantir também que as regras relevantes sejam aplicadas durante a implantação da configuração no Endpoints. Para tentar fazer isso com o serviço Bookstore, as regras básicas estão no arquivo api_config.yaml
(em inglês) e as regras HTTP estão no arquivo api_config_http.yaml
(em inglês):
gcloud endpoints services deploy api_descriptor.pb api_config.yaml api_config_http.yaml
Como usar SSL
Caso o SSL seja ativado para comunicação entre os clientes e o ESP, os clientes poderão usar a mesma porta para fazer chamadas gRPC ou HTTP1.1
. Para mais informações sobre como configurar SSL para um serviço do Endpoints, consulte Como ativar SSL.
Especifique uma porta para o ESP aceitar chamadas SSL usando a sinalização --ssl_port
no arquivo de configuração do Google Kubernetes Engine (GKE) ou no 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",
]
Como configurar uma porta HTTP1.1
Caso não esteja usando SSL, configure uma porta separada para solicitações HTTP1.1
porque gRPC e HTTP1.1
não podem compartilhar a mesma porta sem SSL. Use a sinalização --http_port
no arquivo de configuração do GKE ou o comando docker run
para especificar uma porta para aceitar chamadas HTTP1.1
. Caso também queira que o ESP aceite chamadas gRPC, use a sinalização --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",
]
Como chamar um serviço usando a transcodificação
Nesta seção, descrevemos a configuração do serviço e como fazer chamadas HTTP para o serviço.
Configuração do serviço
Presumimos que você já tenha concluído os tutoriais básicos do serviço gRPC para o ambiente escolhido e que tenha um cluster do GKE ou uma instância do Compute Engine para executar o exemplo.
- Primeiramente, verifique se você já implantou a configuração do serviço Bookstore habilitado para HTTP no Endpoints, conforme descrito em Garantir que regras HTTP sejam implantadas.
Implante o back-end e o ESP, como descrito no tutorial da plataforma escolhida, usando a sinalização
--http_port
para ativar uma porta para solicitaçõesHTTP1.1
:- Implantação do GKE: siga as instruções em Como implantar a API de amostra e o ESP no cluster, garantindo que a sinalização
"--http_port"
esteja especificada no arquivo de configuração do GKE. - Implantação do Compute Engine: siga as instruções em Como executar a API de amostra e o ESP em um contêiner do Docker.
Certifique-se de que a sinalização
--http_port
esteja especificada no comandodocker run
ao executar o contêiner predefinido do Docker ESP.
- Implantação do GKE: siga as instruções em Como implantar a API de amostra e o ESP no cluster, garantindo que a sinalização
Fazer chamadas HTTP ao serviço
- Consiga o endereço IP externo do ESP e defina-o como
$ESP_IP
. Faça a seguinte solicitação HTTP com
curl
curl http://$ESP_IP/v1/shelves
ou utilize o mesmo URL com
https://
, se estiver usando SSL. O servidor responde com:{"shelves":[{"id":"1","theme":"Fiction"},{"id":"2","theme":"Fantasy"}]}
Se a saída exibir uma resposta binária, verifique a configuração da porta, porque é possível que você esteja acessando a porta HTTP2 em vez da HTTP.
Tente um método
Create
.CreateShelf
requer uma Chave de API, então é preciso criar uma chave para o projeto e defini-la como$KEY
. Agora, faça uma chamada para:curl -d '{"theme":"Music"}' http://$ESP_IP/v1/shelves?key=$KEY
Se você chamar
GetShelves
novamente, verá a nova estante.