gRPC サービスを構成する

gRPC サービスを作成するには、Cloud Endpoints を使用しているかどうかにかかわらず、1 つ以上の proto ファイル(拡張子が .proto のテキスト ファイル)でインターフェース定義を指定します。proto ファイルでは、データ構造、メソッド、メソッド パラメータ、戻り値の型など、API のサーフェスを定義します。次に、言語に固有のプロトコル バッファ コンパイラ protoc を使用して proto ファイルをコンパイルします。詳細については、gRPC とはgRPC のコンセプトをご覧ください。

gRPC サービスを Endpoints で管理するには、コンパイルされた proto ファイルに加えて、1 つ以上の YAML ファイルでサービス構成を指定する必要があります。サービス構成とは、認証、割り当てなどの gRPC サービスの動作を定義するための仕様です。

サービス構成の概要

YAML ファイルの先頭には、名前やタイトルなどのサービスの基本情報を指定します。YAML ファイルのサブセクションで、以下のようなサービス構成をします。

次に例を示します。

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

各サブセクションは通常、さまざまなサービス構成を行う .proto メッセージに対応しています。次に例を示します。

  • authentication: 呼び出し元の認証方法を指定します。
  • backend: リモート バックエンド ルーティングを制御します。
  • http: 1 つの RPC メソッドを 1 つ以上の HTTP REST API メソッドにマッピングする際のルールを定義します。
  • usage: API キー検証の有効、無効を選択できます。

サービス構成の公式なスキーマは、.proto メッセージ google.api.Service によって定義されます。

基本的な構成

gRPC のチュートリアルで使用される Bookstore サンプルには、基本的なインターフェース定義ファイルとサービス構成ファイルが含まれています。

Bookstore のインターフェース定義bookstore.proto:

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

Bookstore のサービス構成api_config.yaml:

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

上記のコードサンプルは、次の機能を持つ最も単純なサービス構成です。

  • bookstore.endpoints.MY_PROJECT_ID.cloud.goog という名前のサービスを定義します。ここで、MY_PROJECT_ID は実際の Google Cloud プロジェクト ID です。
  • bookstore.proto ファイルで定義されているように、サービスが API endpoints.examples.bookstore.Bookstore を公開することを指定します。
  • わかりやすいタイトルを指定します。構成をデプロイした後、このタイトルは Google Cloud Console の [エンドポイント] > [サービス] ページに表示されます。詳しい説明については、GitHub で各ファイルの完全版をご覧ください。

ルールとセレクタ

場合によっては、サービスの個々の要素に構成を関連付ける機能が必要になることがあります。たとえば、認証を特定のメソッドのみに適用し、他のメソッドには適用しない場合などです。サービス構成でこの構成をする場合、サービス構成の一部(authenticationhttp)でルールやセレクタを指定できます。セレクタは、ルールに関連付けられた構成が適用されるサービスの要素(メソッド名など)を識別します。

セレクタでは、サービス、メソッド、メッセージ、フィールド、列挙の完全修飾名や列挙値をカンマ区切りで指定します。名前の最後のセグメントをワイルドカード * にすることで、すべてのサフィックスを対象にできます。ワイルドカードは、パターンの末尾、および名前のセグメント全体についてのみ使用できます。たとえば、foo.* は有効ですが、foo.b*foo.*.bar は有効ではありません。該当するすべての要素のデフォルトを構成するには、* を単独で指定します。

例 1(サービス全体に適用)

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

例 2(単一のメソッドに適用)

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

上記の例は、ListShelves メソッドを除くすべてのメソッドで API キー検証を義務付ける方法を示しています。

ルールは順番に評価され、宣言の順序で最後に一致するルールが適用されます。

複数の YAML ファイルの使用

同じサービスの各機能を複数の YAML ファイルで構成しておくと便利な場合があります。複数の YAML ファイルを使用すると、ファイルの再利用や環境に応じてファイル内容の変更をすることが簡単になります。たとえば Bookstore サンプルでは、基本的な構成を api_config.yaml ファイルで、HTTP ルールを api_config_http.yaml ファイルでそれぞれ指定しています。これにより、Bookstore で JSON / HTTP から gRPC へのコード変換を有効にする場合にのみ HTTP ルールをデプロイできます。

サービス構成に複数の YAML ファイルを使用する場合、構成がデプロイされるときに各ファイルが google.api.Service proto メッセージに変換され、さらに proto マージ セマンティクスですべてのメッセージがマージされます。つまり、より後に出現するインスタンスの独特なスカラー フィールドはすべて、それ以前のものを置き換えます。したがって、同じルールについて 2 つのファイルで異なる特異値を指定した場合、構成のデプロイ時には、2 つ目のファイルで指定した値が使用されます。特異な埋め込みメッセージがマージされ、繰り返しフィールドが連結されます。

ルールと同様に、マージは設定の優先順に行われます。2 つのサービス構成がある場合、2 番目のサービス構成が 1 番目の構成をオーバーライドします。

アノテーション(HTTP ルールのみ)

HTTP オプションを構成する方法として、YAML ファイルを使用するほかに、proto ファイルでオプション メカニズムを使って直接構成することもできます。API アノテーションは annotations.proto で定義されています。

アノテーションは、プロトコル バッファ インターフェース定義のすべての使用事例で構成オプションが不変な場合に使われます。たとえば API の実装が 1 つだけの場合や、すべての実装で HTTP インターフェースを同じにする必要がある場合には、proto ファイルで HTTP 構成にアノテーションを付けることができます。

proto ファイルとサービス構成 YAML ファイルの両方で構成オプションが指定されている場合は、サービス構成がアノテーションをオーバーライドします。

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'

詳細については、HTTP / JSON の gRPC へのコード変換をご覧ください。

構成の検証

gcloud endpoints services deploy を使用してサービス構成とコンパイル済みの proto ファイルをデプロイし、サービスのランタイム構成を作成します。gcloud endpoints services deploy コマンドは、サービス構成を検証し、エラーや警告にフラグを付けます。

警告には、通常の警告とリンター警告の 2 種類があります。リンター警告は <group>-<rule> の形式で示されます。<group> は構成のグループで、<rule> は特定のリンターのルールです。たとえば、次の例では、versioning がグループで 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'.

リンター警告は、API 要素のドキュメントにディレクティブを追加することで非表示にできます。proto ファイルやサービス構成 YAML ファイルでディレクティブを追加できます。上記の警告を非表示にする例を次に示します。

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

グループ全体で警告を非表示にするには、ルール名の代わりにワイルドカード(*)を使用します。たとえば、versioning-* と指定すると、versioning グループに関するすべての警告が非表示になります。

警告を非表示にするディレクティブを親要素に適用すると、子要素にもすべて適用されます。たとえば、次の例では、サービス内のすべてのメソッドについて、versioning グループのすべての警告が非表示になります。

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

警告をグローバルに非表示にするには、サービス構成の概要ドキュメントにディレクティブを付加します。

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

suppress_warning などのドキュメント内のディレクティブは独立した行に記述される必要があり、そうでない場合は認識されません。YAML ブロック リテラル マーカー(たとえば >)を使用するとすべての改行が削除されるので、上記の例で overview: > のように指定した場合は、非表示になりません。YAML 内のブロック リテラルの詳細については、インデントされた区切りをご覧ください。

次のステップ