リソース指向の API では、「リソース」は名前付きエンティティであり、「リソース名」はその識別子です。各リソースには、独自の一意のリソース名が必要です。 リソース名は、リソース自体の ID、すべての親リソースの ID、その API サービス名で構成されます。 次に、リソース ID と、リソース名の構成方法について説明します。
gRPC API では、リソース名にスキームのない URI を使用します。一般的に、これらは REST URL の規則に従い、その動作はネットワーク ファイルパスとよく似ています。これらは簡単に REST URL にマッピングすることができます。詳細については、標準メソッドをご覧ください。
コレクションは、同じタイプのサブリソースのリストを含む特別な種類のリソースです。たとえば、ディレクトリはファイル リソースのコレクションです。コレクションのリソース ID はコレクション ID と呼ばれます。
リソース名は、スラッシュで区切られたコレクション ID とリソース ID を使用して階層的に編成されます。リソースにサブリソースが含まれている場合、サブリソースの名前は、親リソース名の後にサブリソースの ID(スラッシュで区切られたもの)を指定することによって構成されます。
例 1: ストレージ サービスには buckets
のコレクションがあり、各バケットには objects
のコレクションがあります。
API サービス名 | コレクション ID | リソース ID | コレクション ID | リソース ID |
---|---|---|---|---|
//storage.googleapis.com | /buckets | /bucket-id | /objects | /object-id |
例 2: メール サービスには users
のコレクションがあります。各ユーザーには settings
サブリソースがあり、settings
サブリソースには customFrom
などその他多数のサブリソースがあります。
API サービス名 | コレクション ID | リソース ID | リソース ID | リソース ID |
---|---|---|---|---|
//mail.googleapis.com | /users | /name@example.com | /settings | /customFrom |
API プロデューサーは、リソース階層内で一意である限り、リソース ID とコレクション ID に任意の許容可能な値を選択できます。次に、適切なリソース ID とコレクション ID を選択するための詳細なガイドラインを示します。
セグメントにはスラッシュが含まれていないと想定して、name.split("/")[n]
などのリソース名を分割することで、個々のコレクション ID とリソース ID を取得できます。
完全なリソース名
URI API サービス名とリソースパスで構成される、スキームのない URI。リソースパスは、相対的なリソース名とも呼ばれます。 次に例を示します。
"//library.googleapis.com/shelves/shelf1/books/book2"
API サービス名は、クライアントが API サービス エンドポイントを見つけるためのものであり、内部専用サービス用の架空の DNS 名である場合があります。API サービス名がコンテキストから明らかな場合は、通常、相対的なリソース名が使用されます。
相対的なリソース名
先頭の「/」のない URI パス(path-noscheme)。API サービス内のリソースを識別します。次に例を示します。
"shelves/shelf1/books/book2"
リソース ID
リソース ID は通常、親リソース内のリソースを識別する 1 つ以上の空でない URI セグメント(segment-nz-nc)で構成されます。上記の例をご覧ください。リソース名の末尾でないリソース ID には URL セグメントが 1 つだけ必要ですが、リソース名の末尾のリソース ID には複数の URI セグメントが含まれる場合があります。次に例を示します。
コレクション ID | リソース ID |
---|---|
ファイル | source/py/parser.py |
API サービスでは、可能な場合、URL に適したリソース ID を使用することが推奨されます。 リソース ID がクライアントとサーバーのいずれによって割り当てられるかは、明確にドキュメント化される必要があります。たとえば、通常、ファイル名はクライアントによって割り当てられますが、メール メッセージ ID はサーバーによって割り当てられます。
コレクション ID
親リソース内のコレクション リソースを識別する、空でない URI セグメント(segment-nz-nc)。上記の例をご覧ください。
通常、コレクション ID は生成されたクライアント ライブラリに含められるため、次の要件に準拠している必要があります。
- 有効な C/C++ 識別子である必要があります。
- lowerCamel ケースで複数形である必要があります。単語が適切な複数形を持たない場合(evidence や weather など)、単数形を使用することが推奨されます。
- 明確で簡潔な英語の用語を使用する必要があります。
- 非常に一般的な用語は使用しないか、修飾することが推奨されます。たとえば、
rowValues
はvalues
よりも優先されます。次の用語は、修飾して使用することが推奨されます。- elements
- entries
- instances
- items
- objects
- リソース
- タイプ
- values
リソース名と URL
完全なリソース名は通常の URL に似ていますが、同じものではありません。単一のリソースは、異なる API バージョン、API プロトコル、API ネットワーク エンドポイントによって公開することができます。完全なリソース名ではこのような情報を指定しないため、実際に使用するには、リソース名を特定の API バージョンと API プロトコルにマッピングする必要があります。
REST API を介して完全なリソース名を使用するには、サービス名の前に HTTPS スキームを追加し、リソースパスの前に API のメジャー バージョンを追加して、リソースパスを URL エスケープすることによって、リソース名を REST URL に変換する必要があります。次に例を示します。
// This is a calendar event resource name.
"//calendar.googleapis.com/users/john smith/events/123"
// This is the corresponding HTTP URL.
"https://calendar.googleapis.com/v3/users/john%20smith/events/123"
文字列としてのリソース名
Google API では、下位互換性が問題にならない限り、文字列を使用してリソースを表す必要があります。リソース名は通常のファイルパスと同様に処理することが必要です。リソース名が異なるコンポーネント間で渡される場合、対象のリソースはアトミックな値として扱われ、データの損失を回避する必要があります。
リソース定義の場合、最初のフィールドはリソース名の文字列フィールドにする必要があります。また、このフィールドには name
という名前を付ける必要があります。
次に例を示します。
service LibraryService {
rpc GetBook(GetBookRequest) returns (Book) {
option (google.api.http) = {
get: "/v1/{name=shelves/*/books/*}"
};
};
rpc CreateBook(CreateBookRequest) returns (Book) {
option (google.api.http) = {
post: "/v1/{parent=shelves/*}/books"
body: "book"
};
};
}
message Book {
// Resource name of the book. It must have the format of "shelves/*/books/*".
// For example: "shelves/shelf1/books/book2".
string name = 1;
// ... other properties
}
message GetBookRequest {
// Resource name of a book. For example: "shelves/shelf1/books/book2".
string name = 1;
}
message CreateBookRequest {
// Resource name of the parent resource where to create the book.
// For example: "shelves/shelf1".
string parent = 1;
// The Book resource to be created. Client must not set the `Book.name` field.
Book book = 2;
}
注: リソース名の整合性を維持するために、URL テンプレート変数を使用して先頭のスラッシュを取得しないでください。たとえば、URL テンプレートは、"/v1{name=/shelves/*/books/*}"
ではなく、"/v1/{name=shelves/*/books/*}"
を使用する必要があります。
質問
Q: リソースを識別するためにリソース ID を使用しないのはなぜですか?
大規模なシステムの場合、多くの種類のリソースがあります。リソース ID を使用してリソースを識別するには、実際には (bucket, object)
や (user, album, photo)
などのリソース固有のタプルを使用します。これにより、いくつかの重大な問題が発生します。
- デベロッパーは、このような匿名のタプルを理解し、覚えておく必要があります。
- 通常、タプルの受け渡しは文字列の受け渡しよりも困難です。
- ロギングやアクセス制御システムなどの集中管理されたインフラストラクチャでは、特殊なタプルは認識されません。
- 特殊なタプルによって、再利用可能な API インターフェースの提供など、API を柔軟に設計することが制限されます。たとえば、長時間実行オペレーションは、柔軟なリソース名を使用するため、他の多くの API インターフェースと連携することができます。
Q: リソース名のフィールドを id
ではなく name
と呼ぶのはなぜですか?
リソース名フィールドには、リソースの名前のコンセプトに基づいて名前が付けられます。一般に、name
の概念はデベロッパーにとって混乱しやすいものであることがわかっています。たとえば、ファイル名は単に名前を指すか、フルパスを指すか、といったことが考えられます。標準フィールド name
を予約するとことにより、デベロッパーは、display_name
、title
、full_name
など、より適切な用語を選択する必要があります。
Q: リソース名を生成、解析するにはどうすればよいですか?
リソース名はファイルパスの役割を果たします。printf()
を使用して、リソース ID からリソース名を生成できます。さらに、split()
を使用すると、リソース名を解析してリソース ID に変換できます。末尾のリソース ID には、/
で区切られた複数の URI セグメント(ファイルパスなど)を含めることができます。