Transcodifica di HTTP/JSON in gRPC

Cloud Endpoints supporta la transcodifica del protocollo in modo che i client possano accedere API gRPC mediante HTTP/JSON. Extensible Service Proxy (ESP) transcodifica HTTP/JSON in gRPC.

Questa guida descrive:

  • Come utilizzare le annotazioni nel file .proto per specificare la conversione dei dati da Da HTTP/JSON a gRPC
  • Come eseguire il deployment del servizio in Endpoints per utilizzare questa funzionalità
  • Dove trovare ulteriori informazioni di riferimento sulla progettazione e l'implementazione transcodifica per servizi gRPC

Si presume che tu abbia già completato i nostri tutorial su gRPC e che tu abbia familiarità con i concetti di base degli endpoint per le API gRPC.

Progettazione di un'API adatta alla transcodifica

La transcodifica prevede la mappatura delle richieste HTTP/JSON e dei relativi parametri ai metodi gRPC e ai loro parametri e tipi di ritorno. Per questo motivo, anche se è possibile mappare una richiesta HTTP/JSON a qualsiasi metodo API arbitrario, è consigliabile farlo se l'API gRPC è strutturata in modo orientato alle risorse, proprio come un'API HTTP REST tradizionale. In altre parole, progetti il servizio API in modo che utilizzi un numero ridotto dei metodi standard, corrispondenti ai verbi HTTP come GET e PUT, che operano sulle risorse e sulle raccolte di risorse del servizio, che sono a loro volta un tipo di risorsa. Questi metodi standard sono List, Get, Create, Update e Delete.

Se necessario, l'API può anche avere alcuni metodi personalizzati non standard, non sono così semplici da mappare.

Puoi scoprire molto di più sulla progettazione orientata alle risorse mappature di transcodifica nella guida alla progettazione delle API. Questa guida alla progettazione è lo standard di progettazione seguito da Google durante la progettazione di API pubbliche come API Cloud. Sebbene non sia necessario seguire questa guida per utilizzare la transcodifica gRPC, lo consigliamo vivamente. In particolare, le seguenti pagine possono aiutarti a comprendere questi principi di progettazione e ad aggiungere mappature di transcodifica utili ai tuoi metodi:

Potrebbe essere utile anche la seguente pagina di riferimento:

Nel resto di questo documento, utilizzerai l'esempio della libreria che hai utilizzato nei nostri tutorial, che già utilizza questi principi. La libreria ha una "scaffale" raccolte di "libro" che gli utenti possono usare List, Get, Create o Delete.

Dove configurare la transcodifica

La transcodifica gRPC è abilitata per impostazione predefinita e puoi utilizzarla senza configurazione. Segui le istruzioni per implementare un servizio che utilizza la transcodifica. Successivamente, quando invii una richiesta POST HTTP al percorso dell'URL GRPC_SERVICE_FULL_NAME/METHOD_NAME> con (se presenti) del campo del messaggio di richiesta del metodo come JSON nel corpo della richiesta HTTP, ESP invia la richiesta al metodo gRPC appropriato. Nell'esempio precedente, GRPC_SERVICE_FULL_NAME è il nome completo del servizio gRPC e METHOD_NAME è il nome del metodo.

Ad esempio, se invii un POST all'URL ListShelves della libreria come segue:

curl -XPOST http://mydomain/endpoints.examples.bookstore.Bookstore/ListShelves

Riceverai un elenco aggiornato delle sezioni in formato JSON.

Tuttavia, in termini di progettazione dell'interfaccia HTTP, è fortemente preferibile configurare esplicitamente le mappature, come descritto nel resto di questo documento.

Lo standard di configurazione dell'API gRPC per la configurazione del servizio ti consente di specificare esattamente come devono essere tradotti i dati da HTTP/JSON a gRPC. Per farlo sono supportati due meccanismi: annotazioni dirette nel file .proto e in YAML nell'ambito del file di configurazione dell'API gRPC. Ti consigliamo di utilizzare le annotazioni proto per semplificare la lettura e la manutenzione. Per ulteriori informazioni sulla configurazione YAML e quando potresti aver bisogno di utilizzarla, vedi Configurazione della transcodifica in YAML.

Ecco un esempio che utilizza l'approccio consigliato dalla libreria:

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

L'annotazione indica a ESP che effettuare una richiesta GET HTTP con l'URL http://mydomain/v1/shelves/1 chiama GetShelf() del server gRPC con un elemento GetShelfRequest contenente l'ID scaffale richiesto shelf (in questo caso, 1).

Aggiunta di mappature di transcodifica

In questa sezione vengono descritte alcune annotazioni di mappatura aggiuntive della Libreria campione. Nell'esempio di Bookstore sono presenti due file proto di esempio, in modo da poterli implementare sia con che senza le mappature di transcodifica e confrontare le differenze nei file proto:

Per una guida più completa su come specificare le mappature di transcodifica, consulta Metodi standard, Metodi personalizzati e il riferimento alle regole HTTP.

Mappa un metodo List

Il metodo List è definito nel file .proto con il relativo tipo di risposta:

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

L'annotazione in grassetto specifica la mappatura HTTP per questo metodo.

  • option (google.api.http) specifica che questo metodo è un mapping HTTP gRPC annotazione.
  • get specifica che questo metodo è mappato a una richiesta HTTP GET.
  • "/v1/shelves" è il modello di percorso dell'URL (aggiunto al dominio del servizio) utilizzato dalla richiesta GET per chiamare questo metodo. Il percorso dell'URL è noto anche come percorso della risorsa, perché in genere specifica "thing" o risorsa che vuoi utilizzare. In questo caso, tutte le risorse della sezione del nostro Negozio di libri.

Ad esempio, se un client chiama questo metodo inviando un GET all'URL http://mydomain/v1/shelves, ESP chiama il metodo gRPC ListShelves(). Il backend gRPC restituisce quindi gli scaffali, ESP converte in formato JSON e restituisce il client.

Mappa un metodo Get

Il metodo GetShelf della libreria è definito nel file .proto con i relativi tipi di richiesta e risposta:

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

L'annotazione in grassetto specifica il mapping HTTP per questo metodo.

  • option (google.api.http) specifica che questo metodo è un mapping HTTP gRPC annotazione.
  • get specifica che questo metodo è mappato a una richiesta HTTP GET.
  • "/v1/shelves/{shelf}"è il percorso dell'URL per la richiesta, come prima, ma specifica /v1/shelves/ e poi {shelf}. Questa notazione con parentesi graffa ESP che qualsiasi cosa sia in {shelf} è il valore che dovrebbe indica shelf nel parametro GetShelfRequest del metodo.

Se un client chiama questo metodo inviando un GET all'URL http://mydomain/v1/shelves/4, ESP crea un'istanza GetShelfRequest con un valore shelf di 4, quindi chiama il metodo gRPC GetShelf(). Il backend gRPC restituisce quindi l'oggetto Shelf richiesto con l'ID 4, che ESP converte in formato JSON e restituisce di alto profilo.

Questo metodo richiede solo che il client fornisca un singolo valore del campo della richiesta, shelf, che specifichi nel modello di percorso dell'URL con la notazione "di acquisizione" tra parentesi graffe. Puoi anche acquisire più parti dell'URL se necessario per identificare la risorsa richiesta. Ad esempio, GetBook richiede che il client specifichi sia l'ID scaffale sia l'ID libro nell'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;
}

Oltre ai valori letterali e alle parentesi graffe per i valori dei campi, i modelli di percorso dell'URL possono utilizzare caratteri jolly per indicare che qualsiasi elemento in questa parte dell'URL acquisite. La notazione {shelf} utilizzata nell'esempio precedente è in realtà una scorciatoia per {shelf=*}. Puoi scoprire di più sulle regole per il percorso modelli nel Riferimento per le regole HTTP.

In questo tipo di metodo, non è specificato il corpo della richiesta HTTP. Puoi trovare altre linee guida per la mappatura dei metodi Get, incluso l'utilizzo dei parametri di query, in Metodi standard.

Mappa un metodo Create

Il metodo CreateShelf della Libreria viene mappato a 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) specifica che questo metodo è un mapping HTTP gRPC annotazione.
  • post specifica che questo metodo è mappato a una richiesta HTTP POST.
  • "/v1/shelves" è il percorso dell'URL per la richiesta, come prima.
  • body: "shelf"viene utilizzato nel corpo della richiesta HTTP per specificare la risorsa da aggiungere in formato JSON.

Ad esempio, se un client chiama questo metodo come segue:

curl -d '{"theme":"Music"}' http://DOMAIN_NAME/v1/shelves

ESP usa il corpo JSON per creare un valore Shelf con il tema "Music" per CreateShelfRequest, quindi chiama gRPC CreateShelf() . Tieni presente che il client non fornisce il valore id per Shelf. Gli ID scaffale della Libreria vengono forniti dal servizio quando viene creato un nuovo scaffale. Fornisci questo tipo di informazioni agli utenti del tuo servizio nella documentazione dell'API.

Utilizzare un carattere jolly nel corpo

Il nome speciale * può essere utilizzato nella mappatura del corpo per indicare che ogni campo non associato dal modello di percorso deve essere mappato al corpo della richiesta. Viene attivata la seguente definizione alternativa del metodo 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) specifica che questo metodo è un mapping HTTP gRPC annotazione.
  • post specifica che questo metodo è mappato a una richiesta HTTP POST.
  • "/v1/shelves/{shelf_id}" è il percorso dell'URL per la richiesta. Qualsiasi valore in {shelf_id} è il valore del campo shelf_id in CreateShelfRequest.
  • body: "*" viene utilizzato nel corpo della richiesta HTTP per specificare tutti i campi della richiesta rimanenti, ad eccezione di shelf_id in questo esempio, ovvero shelf_theme e shelf_size. Per tutti i campi del corpo JSON con questi due nomi, i relativi valori verranno utilizzati nei campi corrispondenti di CreateShelfRequest.

Ad esempio, se un client chiama questo metodo come segue:

curl -d '{"shelf_theme":"Music", "shelf_size": 20}' http://DOMAIN_NAME/v1/shelves/123

ESP usa il corpo JSON e il modello di percorso per creare CreateShelfRequest{shelf_id: 123 shelf_theme: "Music" shelf_size: 20}, e quindi lo utilizza per chiamare il metodo gRPC CreateShelf(). Per maggiori dettagli, consulta HttpRule.

Configurazione della transcodifica in YAML

Un approccio alternativo consiste nel specificare le mappature da HTTP a gRPC nel File YAML di configurazione dell'API gRPC anziché nel file .proto. Potresti dover configurare la transcodifica in un file YAML se hai una singola definizione dell'API proto utilizzata in più servizi, con mappature diverse specificate per ciascun servizio.

Il rules nella sezione http del tuo file YAML specifica come mappare HTTP/JSON richieste ai metodi 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}
  ...

Un esempio più completo di utilizzo di questo approccio per il servizio di libreria di esempio è in api_config_http.yaml

Deployment di un servizio che utilizza la transcodifica

Il deployment di un servizio gRPC che utilizza la transcodifica è molto simile a quello di qualsiasi altro servizio gRPC, con una differenza sostanziale. Nei tutorial, l'esempio doveva accettare le richieste gRPC dal client di esempio. Tuttavia, se vuoi che la libreria accetti anche le richieste HTTP, devi eseguire un'ulteriore configurazione per ESP. I client utilizzano il protocollo HTTP1.1 per inviare richieste JSON/HTTP all'ESP, pertanto l'ESP deve essere configurato per utilizzare SSL (la porta SSL può supportare entrambi i tipi di richiesta) o deve avere una porta speciale abilitata per accettare queste chiamate. Il deployment è in altro modo in gran parte uguale a quello del tutorial per l'ambiente scelto.

Assicurati che venga eseguito il deployment delle regole HTTP

Se hai già scaricato l'esempio della libreria per i tutorial, tieni presente che devi scaricare una versione leggermente diversa del file .proto con le annotazioni, http_bookstore.proto. Devi inoltre clonare Repository googleapis da GitHub prima di eseguire protoc, in quanto annotations.proto nel percorso di inclusione.

    git clone https://github.com/googleapis/googleapis

    GOOGLEAPIS_DIR=<your-local-googleapis-folder>

Quindi crei un nuovo descrittore .pb da http_bookstore.proto quando deployment la configurazione a Endpoints:

    protoc \
        --include_imports \
        --include_source_info \
        --proto_path=${GOOGLEAPIS_DIR} \
        --proto_path=. \
        --descriptor_set_out=api_descriptor.pb \
        http_bookstore.proto

Se utilizzi il metodo alternativo per configurare le mappature HTTP nel file YAML della configurazione dell'API gRPC, devi anche assicurarti che le regole pertinenti vengano implementate durante il deployment della configurazione in Endpoints. Per provare questa operazione con il servizio Libreria, le relative regole di base si trovano nel file api_config.yaml e le regole HTTP nel file api_config_http.yaml:

    gcloud endpoints services deploy api_descriptor.pb api_config.yaml api_config_http.yaml

Utilizzo di SSL

Se SSL è abilitato per la comunicazione tra i client e l'ESP, i client possono utilizzare la stessa porta per effettuare chiamate gRPC o HTTP1.1. Puoi visualizzare scopri come configurare SSL per un servizio Endpoints Attivazione di SSL.

Specifica una porta per consentire a ESP di accettare le chiamate SSL utilizzando --ssl_port nel file di configurazione di Google Kubernetes Engine (GKE) o 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",
    ]

Configurare una porta HTTP1.1

Se non utilizzi SSL, devi configurare una porta separata per le richieste HTTP1.1 perché gRPC e HTTP1.1 non possono condividere la stessa porta senza SSL. Utilizza le funzionalità di il flag --http_port nel file di configurazione GKE docker run per specificare una porta su accetta chiamate HTTP1.1. Se vuoi anche che ESP accetti gRPC devi utilizzare anche il flag --http2_port per specificare una 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",
    ]

Chiamata a un servizio tramite transcodifica

Questa sezione descrive la configurazione del servizio e come effettuare chiamate HTTP al servizio.

Configurazione del servizio

Si presume che tu abbia già completato i tutorial di base sul servizio gRPC per l'ambiente scelto e che tu abbia un cluster GKE o un'istanza Compute Engine per eseguire l'esempio.

  1. Innanzitutto, assicurati di aver eseguito il deployment della configurazione del servizio Bookstore abilitato per HTTP in Endpoints, come descritto in Verificare il deployment delle regole HTTP.
  2. Esegui il deployment del backend e dell'ESP come descritto nel tutorial per la piattaforma scelta, utilizzando il flag --http_port per attivare una porta per le richieste HTTP1.1:

Effettuare chiamate HTTP al servizio

  1. Ottieni l'indirizzo IP esterno dell'ESP e impostalo su $ESP_IP.
  2. Effettua la seguente richiesta HTTP con curl

    curl http://$ESP_IP/v1/shelves
    

    (oppure utilizza lo stesso URL con https:// se utilizzi SSL). Il server risponde con:

    {"shelves":[{"id":"1","theme":"Fiction"},{"id":"2","theme":"Fantasy"}]}
    

    Se l'output visualizza una risposta binaria, controlla la configurazione della porta. perché potresti aver raggiunto la porta HTTP2 anziché la porta HTTP.

  3. Prova un metodo Create. CreateShelf richiede una chiave API, quindi devi crearla per il tuo progetto e impostarla come $KEY. Chiama ora:

    curl -d '{"theme":"Music"}' http://$ESP_IP/v1/shelves?key=$KEY
    

    Se chiami di nuovo GetShelves dovresti vedere il tuo nuovo scaffale.