Mentranskode HTTP/JSON ke gRPC

Cloud Endpoints mendukung transkode protokol sehingga klien dapat mengakses gRPC API Anda menggunakan HTTP/JSON. Extensible Service Proxy (ESP) mentranskode HTTP/JSON ke gRPC.

Panduan ini menjelaskan:

  • Cara menggunakan anotasi dalam file .proto untuk menentukan konversi data dari HTTP/JSON ke gRPC
  • Cara men-deploy layanan Anda di Endpoints untuk menggunakan fitur ini
  • Tempat menemukan informasi referensi lainnya tentang mendesain dan menerapkan transcoding untuk layanan gRPC

Hal ini mengasumsikan bahwa Anda telah menyelesaikan Tutorial gRPC kami dan memahami konsep dasar Endpoints for gRPC APIs.

Mendesain API yang kompatibel untuk transcoding

Transcoding melibatkan pemetaan permintaan HTTP/JSON dan parameternya ke metode gRPC dan parameternya serta jenis nilai yang ditampilkan. Oleh karena itu, meskipun permintaan HTTP/JSON dapat dipetakan ke metode API arbitrer, sebaiknya lakukan pemetaan jika gRPC API disusun dengan cara berorientasi resource, seperti REST API HTTP tradisional. Dengan kata lain, Anda mendesain layanan API sehingga menggunakan sejumlah kecil metode standar, yang sesuai dengan kata kerja HTTP seperti GET dan PUT, yang beroperasi pada resource dan kumpulan resource layanan, yang merupakan jenis resource itu sendiri. Metode standar ini adalah List, Get, Create, Update, dan Delete.

Jika perlu, API juga dapat memiliki beberapa metode kustom non-standar, meskipun pemetaannya tidak sesederhana itu.

Anda dapat mengetahui lebih lanjut tentang desain berorientasi resource dan pemetaan transkode standar dalam panduan desain API. Panduan desain ini adalah standar desain yang diikuti di Google saat mendesain API publik seperti Cloud API. Meskipun Anda tidak perlu mengikuti panduan ini untuk menggunakan transkode gRPC, sebaiknya Anda melakukannya. Secara khusus, halaman berikut dapat membantu Anda memahami prinsip desain ini dan menambahkan pemetaan transkode yang berguna ke metode Anda:

Halaman referensi berikut juga mungkin berguna:

Di bagian lain dokumen ini, Anda akan menggunakan contoh Bookstore yang Anda gunakan dalam Tutorial kami, yang sudah menggunakan prinsip ini. Toko Buku memiliki koleksi "rak" dari resource "buku", yang dapat List, Get, Create, atau Delete oleh pengguna.

Tempat mengonfigurasi transcoding

Transcoding gRPC diaktifkan secara default, dan Anda dapat menggunakannya tanpa konfigurasi apa pun. Ikuti petunjuk untuk men-deploy layanan menggunakan transkode. Setelah itu, saat Anda mengirim permintaan HTTP POST ke jalur URL GRPC_SERVICE_FULL_NAME/METHOD_NAME> dengan nilai kolom pesan permintaan metode (jika ada) sebagai JSON di isi permintaan HTTP, ESP akan mengirim pesan permintaan ke metode gRPC yang sesuai. Dalam contoh sebelumnya, GRPC_SERVICE_FULL_NAME adalah nama lengkap layanan gRPC Anda dan METHOD_NAME adalah nama metode.

Misalnya, jika Anda mengirim POST ke URL ListShelves Toko Buku sebagai berikut:

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

Anda akan mendapatkan daftar rak saat ini dalam bentuk JSON.

Namun, dari segi desain antarmuka HTTP, sangat disarankan untuk mengonfigurasi pemetaan secara eksplisit, seperti yang dijelaskan di bagian lain dokumen ini.

Standar konfigurasi gRPC API untuk konfigurasi layanan memungkinkan Anda menentukan secara persis cara data harus diterjemahkan dari HTTP/JSON ke gRPC. Ada dua mekanisme yang didukung untuk melakukannya: anotasi langsung di file .proto, dan di YAML sebagai bagian dari file konfigurasi gRPC API. Sebaiknya gunakan anotasi proto agar lebih mudah dibaca dan dikelola. Untuk mengetahui informasi selengkapnya tentang konfigurasi YAML dan kapan Anda mungkin perlu menggunakannya, lihat Mengonfigurasi transkode dalam YAML.

Berikut adalah contoh yang menggunakan pendekatan yang direkomendasikan dari 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;
}

Anotasi memberi tahu ESP bahwa membuat permintaan HTTP GET dengan URL http://mydomain/v1/shelves/1 memanggil metode GetShelf() server gRPC, dengan GetShelfRequest yang berisi ID rak yang diminta shelf (dalam hal ini, 1).

Menambahkan pemetaan transcoding

Bagian ini menjelaskan beberapa anotasi pemetaan tambahan dari contoh Bookstore. Ada dua file proto contoh di sampel Bookstore sehingga Anda dapat men-deploy-nya dengan atau tanpa pemetaan transcoding, dan membandingkan perbedaan dalam file proto:

Untuk panduan yang lebih komprehensif tentang cara menentukan pemetaan transkode, lihat Metode standar, Metode kustom, dan Referensi aturan HTTP.

Memetakan metode List

Metode List ditentukan dalam file .proto dengan jenis responsnya:

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

Anotasi dengan huruf tebal menentukan pemetaan HTTP untuk metode ini.

  • option (google.api.http) menentukan bahwa metode ini adalah anotasi pemetaan HTTP gRPC.
  • get menentukan bahwa metode ini dipetakan ke permintaan HTTP GET.
  • "/v1/shelves" adalah template jalur URL (ditambahkan ke domain layanan Anda) yang digunakan permintaan GET untuk memanggil metode ini. Jalur URL juga dikenal sebagai jalur resource karena biasanya menentukan "sesuatu" atau resource yang ingin Anda gunakan. Dalam hal ini, semua resource rak Buku kami.

Misalnya, jika klien memanggil metode ini dengan mengirim GET ke URL http://mydomain/v1/shelves, ESP akan memanggil metode gRPC ListShelves(). Backend gRPC kemudian menampilkan rak, yang dikonversi ESP ke format JSON dan ditampilkan ke klien.

Memetakan metode Get

Metode GetShelf Bookstore ditentukan dalam file .proto dengan jenis permintaan dan responsnya:

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

Anotasi dengan huruf tebal menentukan pemetaan HTTP untuk metode ini.

  • option (google.api.http) menentukan bahwa metode ini adalah anotasi pemetaan HTTP gRPC.
  • get menentukan bahwa metode ini dipetakan ke permintaan HTTP GET.
  • "/v1/shelves/{shelf}" adalah jalur URL untuk permintaan, seperti sebelumnya, tetapi menentukan /v1/shelves/ lalu {shelf}. Notasi kurung kurawal ini memberi tahu ESP bahwa apa pun yang ada di {shelf} adalah nilai yang harus diberikan untuk shelf dalam parameter GetShelfRequest metode.

Jika klien memanggil metode ini dengan mengirim GET ke URL http://mydomain/v1/shelves/4, ESP akan membuat GetShelfRequest dengan nilai shelf 4, lalu memanggil metode gRPC GetShelf() dengannya. Backend gRPC kemudian menampilkan Shelf yang diminta dengan ID 4, yang dikonversi ESP ke format JSON dan ditampilkan ke klien.

Metode ini hanya memerlukan satu nilai kolom permintaan yang diberikan oleh klien, shelf, yang Anda tentukan dalam template jalur URL dengan notasi "pengambilan" kurung kurawal. Anda juga dapat mengambil beberapa bagian URL jika perlu untuk mengidentifikasi resource yang diminta. Misalnya, metode GetBook memerlukan klien untuk menentukan ID rak dan ID buku dalam 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;
}

Selain literal dan tanda kurung pengambilan untuk nilai kolom, template jalur URL dapat menggunakan karakter pengganti untuk menunjukkan bahwa apa pun di bagian URL ini harus diambil. Notasi {shelf} yang digunakan dalam contoh sebelumnya sebenarnya merupakan pintasan untuk {shelf=*}. Anda dapat mengetahui lebih lanjut aturan untuk template jalur di referensi aturan HTTP.

Dalam kasus jenis metode ini, tidak ada isi permintaan HTTP yang ditentukan. Anda dapat menemukan panduan lainnya untuk memetakan metode Get, termasuk menggunakan parameter kueri, di Metode standar.

Memetakan metode Create

Metode CreateShelf Bookstore dipetakan ke POST HTTP.

  // 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) menentukan bahwa metode ini adalah anotasi pemetaan HTTP gRPC.
  • post menentukan bahwa metode ini dipetakan ke permintaan HTTP POST.
  • "/v1/shelves" adalah jalur URL untuk permintaan, seperti sebelumnya.
  • body: "shelf" digunakan dalam isi permintaan HTTP untuk menentukan resource yang ingin Anda tambahkan, dalam format JSON.

Jadi, misalnya, jika klien memanggil metode ini seperti ini:

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

ESP menggunakan isi JSON untuk membuat nilai Shelf dengan tema "Music" untuk CreateShelfRequest, lalu memanggil metode CreateShelf() gRPC. Perhatikan bahwa klien tidak memberikan nilai id untuk Shelf. ID rak Toko Buku disediakan oleh layanan saat membuat rak baru. Anda memberikan jenis informasi ini kepada pengguna layanan Anda dalam dokumentasi API.

Menggunakan karakter pengganti di isi pesan

Nama khusus * dapat digunakan dalam pemetaan isi untuk menunjukkan bahwa setiap kolom yang tidak terikat oleh template jalur harus dipetakan ke isi permintaan. Tindakan ini memungkinkan definisi alternatif berikut untuk metode 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) menentukan bahwa metode ini adalah anotasi pemetaan HTTP gRPC.
  • post menentukan bahwa metode ini dipetakan ke permintaan HTTP POST.
  • "/v1/shelves/{shelf_id}" adalah jalur URL untuk permintaan. Apa pun yang ada di {shelf_id} adalah nilai kolom shelf_id di CreateShelfRequest.
  • body: "*" digunakan di isi permintaan HTTP untuk menentukan semua kolom permintaan yang tersisa kecuali shelf_id dalam contoh ini, yaitu shelf_theme dan shelf_size. Untuk kolom apa pun di isi JSON dengan dua nama ini, nilainya akan digunakan di kolom CreateShelfRequest yang sesuai.

Misalnya, jika klien memanggil metode ini seperti ini:

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

ESP menggunakan isi JSON dan template jalur untuk membuat CreateShelfRequest{shelf_id: 123 shelf_theme: "Music" shelf_size: 20}, lalu menggunakannya untuk memanggil metode gRPC CreateShelf(). Untuk mengetahui detailnya, lihat HttpRule.

Mengonfigurasi transcoding di YAML

Pendekatan alternatif adalah dengan menentukan pemetaan HTTP ke gRPC di file YAML konfigurasi gRPC API, bukan di file .proto. Anda mungkin perlu mengonfigurasi transkode dalam file YAML jika memiliki satu definisi API proto yang digunakan di beberapa layanan, dengan pemetaan yang berbeda yang ditentukan untuk setiap layanan.

rules di bagian http file YAML Anda menentukan cara memetakan permintaan HTTP/JSON ke metode 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}
  ...

Contoh yang lebih lengkap tentang penggunaan pendekatan ini untuk layanan Bookstore contoh ada di api_config_http.yaml.

Men-deploy layanan yang menggunakan transcoding

Men-deploy layanan gRPC yang menggunakan transcoding hampir sama dengan men-deploy layanan gRPC lainnya, dengan satu perbedaan utama. Dalam Tutorial, contoh yang diperlukan untuk menerima permintaan gRPC dari klien contoh. Namun, jika Anda ingin Bookstore menerima permintaan HTTP juga, Anda harus melakukan beberapa konfigurasi tambahan untuk ESP. Klien menggunakan protokol HTTP1.1 untuk mengirim permintaan JSON/HTTP ke ESP, sehingga ESP harus dikonfigurasi untuk menggunakan SSL (port SSL dapat mendukung kedua jenis permintaan) atau harus mengaktifkan port khusus untuk menerima panggilan ini. Deployment sebagian besar sama seperti dalam tutorial untuk lingkungan yang Anda pilih.

Pastikan aturan HTTP di-deploy

Jika Anda telah mendownload contoh Bookstore untuk Tutorial, perhatikan bahwa Anda perlu mendownload versi file .proto yang sedikit berbeda dengan anotasi, http_bookstore.proto. Anda juga perlu meng-clone repositori googleapis dari GitHub sebelum menjalankan protoc, karena Anda memerlukan annotations.proto di jalur include Anda.

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

    GOOGLEAPIS_DIR=<your-local-googleapis-folder>

Kemudian, Anda membuat deskriptor .pb baru dari http_bookstore.proto saat men-deploy konfigurasi ke Endpoints:

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

Jika Anda menggunakan metode alternatif untuk mengonfigurasi pemetaan HTTP dalam file YAML konfigurasi gRPC API, Anda juga harus memastikan bahwa aturan yang relevan di-deploy saat men-deploy konfigurasi ke Endpoints. Untuk mencobanya dengan layanan Bookstore, aturan dasarnya ada di file api_config.yaml dan aturan HTTP-nya ada di file api_config_http.yaml:

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

Menggunakan SSL

Jika SSL diaktifkan untuk komunikasi antara klien dan ESP, klien dapat menggunakan port yang sama untuk melakukan panggilan gRPC atau HTTP1.1. Anda dapat mengetahui cara menyiapkan SSL untuk layanan Endpoints di bagian Mengaktifkan SSL.

Tentukan port agar ESP menerima panggilan SSL menggunakan tanda --ssl_port dalam file konfigurasi Google Kubernetes Engine (GKE) atau perintah 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",
    ]

Menyiapkan port HTTP1.1

Jika tidak menggunakan SSL, Anda perlu menyiapkan port terpisah untuk permintaan HTTP1.1 karena gRPC dan HTTP1.1 tidak dapat berbagi port yang sama tanpa SSL. Gunakan flag --http_port dalam file konfigurasi GKE atau perintah docker run untuk menentukan port yang akan menerima panggilan HTTP1.1. Jika Anda juga ingin ESP menerima panggilan gRPC, Anda juga harus menggunakan flag --http2_port untuk menentukan port 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",
    ]

Memanggil layanan menggunakan transcoding

Bagian ini menjelaskan penyiapan layanan dan cara melakukan panggilan HTTP ke layanan.

Penyiapan layanan

Hal ini mengasumsikan bahwa Anda telah menyelesaikan Tutorial layanan gRPC dasar untuk lingkungan yang Anda pilih dan memiliki cluster GKE atau instance Compute Engine untuk menjalankan contoh.

  1. Pertama, pastikan Anda telah men-deploy konfigurasi layanan Bookstore yang mendukung HTTP ke Endpoints, seperti yang dijelaskan dalam Memastikan aturan HTTP di-deploy.
  2. Deploy backend dan ESP seperti yang dijelaskan dalam tutorial untuk platform pilihan Anda, menggunakan tanda --http_port untuk mengaktifkan port bagi permintaan HTTP1.1:

Melakukan panggilan HTTP ke layanan

  1. Dapatkan alamat IP eksternal ESP dan tetapkan ke $ESP_IP.
  2. Buat permintaan HTTP berikut dengan curl

    curl http://$ESP_IP/v1/shelves
    

    (atau gunakan URL yang sama dengan https:// jika Anda menggunakan SSL). Server merespons dengan:

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

    Jika output menampilkan respons biner, periksa konfigurasi port Anda karena Anda mungkin mengakses port HTTP2, bukan port HTTP.

  3. Coba metode Create. CreateShelf memerlukan kunci API, jadi Anda perlu membuat kunci untuk project Anda dan menyetelnya sebagai $KEY. Sekarang panggil:

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

    Jika Anda memanggil GetShelves lagi, Anda akan melihat rak baru.