Skip to content

Commit 5748816

Browse files
feat: AIP-132 – GET for collections (#20)
1 parent aa26319 commit 5748816

4 files changed

Lines changed: 376 additions & 0 deletions

File tree

aip/general/0132/aip.md.j2

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
# GET for collections
2+
3+
In REST APIs, it is customary to make a `GET` request to a resource
4+
collection's URI (for example, `/v1/publishers/{publisher}/books`) in order to
5+
retrieve a list of the resources within that collection. These are sometimes
6+
colloquially called "list" operations.
7+
8+
## Guidance
9+
10+
APIs **should** generally provide a `GET` method for resource collections
11+
unless it is not valuable for users to do so. When the `GET` method is used on
12+
a URI ending in a resource collection, the result should be a list of
13+
resources. For more information about using the `GET` method on a URI ending
14+
with a discrete resource ID, see AIP-131.
15+
16+
### Requests
17+
18+
Collection `GET` operations **must** be made by sending a `GET` request to the
19+
resource collection's URI:
20+
21+
```http
22+
GET /v1/publishers/{publisher}/books HTTP/2
23+
Host: library.googleapis.com
24+
Accept: application/json
25+
```
26+
27+
- The HTTP method **must** be `GET`.
28+
- The request **must** be safe and **must not** have side effects.
29+
- There **must not** be a request body.
30+
- If a `GET` request contains a body, the body **must** be ignored, and
31+
**must not** cause an error.
32+
- The request **must not** require any fields in the query string.
33+
- The query string **may** include fields for common design patterns
34+
relevant to list methods, such as `string filter` and `string orderBy`.
35+
- The query string **may** include custom fields if necessary for a specific
36+
resource, but not in place of any of the common fields for list methods.
37+
38+
### Responses
39+
40+
Collection `GET` operations **must** return a page of results, with each
41+
individual result being a resource:
42+
43+
```json
44+
{
45+
"results": [
46+
{
47+
"name": "publishers/lacroix/books/les-mis",
48+
"isbn": "978-037-540317-0",
49+
"title": "Les Misérables",
50+
"authors": ["Victor Hugo"],
51+
"rating": 9.6
52+
},
53+
{
54+
"name": "publishers/lacroix/books/hunchback-of-notre-dame",
55+
"isbn": "978-140-274575-1",
56+
"title": "The Hunchback of Notre Dame",
57+
"authors": ["Victor Hugo"],
58+
"rating": 9.3
59+
}
60+
],
61+
"nextPageToken": "xyz"
62+
}
63+
```
64+
65+
- The array of resources **must** be named `results` and contain resources with
66+
no additional wrapping.
67+
- The `string nextPageToken` field **must** be included in the list response
68+
schema. It **must** be set if there are subsequent pages, and **must not** be
69+
set if the response represents the final page. For more information, see
70+
AIP-158.
71+
- The response struct **may** include a `int32 totalSize` (or
72+
`int64 totalSize`) field with the number of items in the collection.
73+
- The value **may** be an estimate (the field **should** clearly document
74+
this if so).
75+
- If filtering is used, the `totalSize` field **should** reflect the size of
76+
the collection _after_ the filter is applied.
77+
78+
**Note:** List methods **may** return the complete collection to any user with
79+
permission to make a successful List request on the collection, _or_ **may**
80+
return a collection only containing resources for which the user has read permission.
81+
This behavior **should** be clearly documented either for each List method or as
82+
a standard convention in service-level documentation. Permission checks on individual
83+
resources may have a negative performance impact so should be used only where
84+
absolutely necessary.
85+
86+
### Errors
87+
88+
If the user does not have sufficient permission to know that the collection
89+
exists, the service **should** reply with an HTTP 404 error, regardless of
90+
whether or not the collection exists. Permission **must** be checked prior to
91+
checking whether the collection exists.
92+
93+
If the user does have proper permission, but the requested collection does not
94+
exist (generally because the parent does not exist), the service **must** reply
95+
with an HTTP 404 error.
96+
97+
**Note:** An empty collection which the user has permission to access **must**
98+
return `200 OK` with an empty results array, and not `404 Not Found`.
99+
100+
### Ordering
101+
102+
`List` methods **may** allow clients to specify sorting order; if they do, the
103+
request message **should** contain a `string orderBy` field.
104+
105+
- Values **should** be a comma separated list of fields. For example:
106+
`"foo,bar"`.
107+
- The default sorting order is ascending. To specify descending order for a
108+
field, users append a `-` prefix; for example: `"foo,-bar"`, `"-foo,bar"`.
109+
- Redundant space characters in the syntax are insignificant. `"foo, -bar"`,
110+
`" foo , -bar "`, and `"foo,-bar"` are all equivalent.
111+
- Subfields are specified with a `.` character, such as `foo.bar` or
112+
`address.street`.
113+
114+
**Note:** Only include ordering if there is an established need to do so. It is
115+
always possible to add ordering later, but removing it is a breaking change.
116+
117+
### Filtering
118+
119+
List methods **may** allow clients to specify filters; if they do, the request
120+
message **should** contain a `string filter` field. Filtering is described in
121+
more detail in AIP-160.
122+
123+
**Note:** Only include filtering if there is an established need to do so. It
124+
is always possible to add filtering later, but removing it is a breaking
125+
change.
126+
127+
### Soft-deleted resources
128+
129+
Some APIs need to "[soft delete][aip-135]" resources, marking them as deleted
130+
or pending deletion (and optionally purging them later).
131+
132+
APIs that do this **should not** include deleted resources by default in list
133+
requests. APIs with soft deletion of a resource **should** include a
134+
`bool showDeleted` field in the list request that, if set, will cause
135+
soft-deleted resources to be included.
136+
137+
## Interface Definitions
138+
139+
{% tab proto -%}
140+
141+
List operations are specified using the following pattern:
142+
143+
{% sample 'list.proto', 'rpc ListBooks' %}
144+
145+
- The RPC's name **must** begin with the word `List`. The remainder of the RPC
146+
name **should** be the plural form of the resource's message name.
147+
- The request message **must** match the RPC name, with a `-Request` suffix.
148+
- The response message **must** match the RPC name, with a `-Response` suffix.
149+
- The response **should** usually include fully-populated resources unless
150+
there is a reason to return a partial response (see AIP-157).
151+
- The HTTP verb **must** be `GET`.
152+
- The URI **should** contain a single variable field corresponding to the
153+
collection parent's name.
154+
- This field **should** be called `parent`.
155+
- The URI **should** have a variable corresponding to this field.
156+
- The `parent` field **should** be the only variable in the URI path. All
157+
remaining parameters **should** map to URI query parameters.
158+
- There **must not** be a `body` key in the `google.api.http` annotation.
159+
- There **should** be exactly one `google.api.method_signature` annotation,
160+
with a value of `"parent"`.
161+
162+
List operations also implement a common request message pattern:
163+
164+
{% sample 'list.proto', 'message ListBooksRequest' %}
165+
166+
- A `parent` field **must** be included unless the resource being listed is a
167+
top-level resource. It **should** be called `parent`.
168+
- The field **should** be [annotated as required][aip-203].
169+
- The field **should** identify the [resource type][aip-123] of the resource
170+
being listed.
171+
- The `max_page_size` and `page_token` fields, which support pagination,
172+
**must** be specified on all list request messages. For more information, see
173+
AIP-158.
174+
175+
**Note:** The `parent` field in the request object corresponds to the `parent`
176+
variable in the `google.api.http` annotation on the RPC. This causes the
177+
`parent` field in the request to be populated based on the value in the URL
178+
when the REST/JSON interface is used.
179+
180+
{% sample 'list.proto', 'message ListBooksResponse' %}
181+
182+
- The response message **must** include a field corresponding to the resources
183+
being returned, named for the English plural term for the resource, and
184+
**should not** include any other repeated fields.
185+
- Fields providing metadata about the list request (such as
186+
`string next_page_token` or `int32 total_size`) **must** be included on the
187+
response message (not as part of the resource itself).
188+
189+
{% tab oas %}
190+
191+
Collection `GET` operations **must** be specified with consistent OpenAPI
192+
metadata:
193+
194+
{% sample 'list.oas.yaml', 'paths' %}
195+
196+
- The `operationId` **must** begin with the word `list`. The remainder of the
197+
`operationId` **should** be the plural form of the resource type's name.
198+
- The response content **must** be the resource itself. For example:
199+
`#/components/schemas/Book`
200+
- The response **should** usually include the fully-populated resource unless
201+
there is a reason to return a partial response (see AIP-157).
202+
- The URI **should** contain a variable for each individual ID in the resource
203+
hierarchy.
204+
- The path parameter for all resource IDs **must** be in the form
205+
`{resourceName}Id` (such as `bookId`), and path parameters representing the
206+
ID of parent resources **must** end with `Id`.
207+
208+
{% endtabs %}

aip/general/0132/aip.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
id: 132
3+
state: approved
4+
created: 2019-01-22
5+
placement:
6+
category: operations
7+
order: 20

aip/general/0132/list.oas.yaml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
---
2+
openapi: 3.0.3
3+
info:
4+
title: Library
5+
version: 1.0.0
6+
paths:
7+
/publishers/{publisherId}/books:
8+
parameters:
9+
- name: publisherId
10+
in: path
11+
description: The publisher to list books for.
12+
required: true
13+
schema:
14+
type: string
15+
get:
16+
operationId: listBooks
17+
description: Get a collection of books.
18+
parameters:
19+
- name: pageToken
20+
in: query
21+
description: |
22+
The page token.
23+
If a `next_page_token` value was received on a previous
24+
ListBooks call, providing it here will return the next page.
25+
schema:
26+
type: string
27+
- name: maxPageSize
28+
in: query
29+
description: |
30+
The maximum number of books to return.
31+
schema:
32+
type: integer
33+
responses:
34+
'200':
35+
description: OK
36+
content:
37+
application/json:
38+
schema:
39+
$ref: '#/components/schemas/ListBooksResponse'
40+
components:
41+
schemas:
42+
ListBooksResponse:
43+
type: object
44+
description: A representation of a collection of books.
45+
properties:
46+
results:
47+
type: array
48+
items:
49+
'$ref': '#/components/schemas/Book'
50+
nextPageToken:
51+
type: string
52+
description: |
53+
The token to retrieve the next page. This is populated if and only
54+
if there are more pages.
55+
Book:
56+
description: A representation of a single book.
57+
type: object
58+
properties:
59+
name:
60+
type: string
61+
description: |
62+
The name of the book.
63+
Format: publishers/{publisher}/books/{book}
64+
isbn:
65+
type: string
66+
description: |
67+
The ISBN (International Standard Book Number) for this book.
68+
title:
69+
type: string
70+
description: The title of the book.
71+
authors:
72+
type: array
73+
items:
74+
type: string
75+
description: The author or authors of the book.
76+
rating:
77+
type: number
78+
description: The rating assigned to the book.

aip/general/0132/list.proto

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// Copyright 2020 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
syntax = "proto3";
16+
17+
import "google/api/annotations.proto";
18+
import "google/api/client.proto";
19+
import "google/api/field_behavior.proto";
20+
import "google/api/resource.proto";
21+
22+
service Library {
23+
// Get a single book.
24+
rpc ListBooks(ListBooksRequest) returns (ListBooksResponse) {
25+
option (google.api.http) = {
26+
get: "/v1/{parent=publishers/*}/books"
27+
};
28+
option (google.api.method_signature) = "parent";
29+
}
30+
}
31+
32+
// Request message to list a collection of books.
33+
message ListBooksRequest {
34+
// The publisher to list books for.
35+
string parent = 1 [
36+
(google.api.field_behavior) = REQUIRED,
37+
(google.api.resource_reference) = {
38+
child_type: "library.googleapis.com/Book"
39+
}];
40+
41+
// The maximum number of books to return.
42+
// The service may send fewer.
43+
int32 max_page_size = 2;
44+
45+
// The page token.
46+
// If a `next_page_token` value was received on a previous
47+
// ListBooks call, providing it here will return the next page.
48+
string page_token = 3;
49+
}
50+
51+
// Response message for listing a collection of books.
52+
message ListBooksResponse {
53+
// The books under the umbrella of the given publisher.
54+
repeated Book results = 1;
55+
56+
// The token to retrieve the next page. This is populated if and only if
57+
// there are more pages.
58+
string next_page_token = 2;
59+
}
60+
61+
// A representation of a single book.
62+
message Book {
63+
option (google.api.resource) = {
64+
type: "library.googleapis.com/Book"
65+
pattern: "publishers/{publisher}/books/{book}"
66+
};
67+
68+
// The name of the book.
69+
// Format: publishers/{publisher}/books/{book}
70+
string name = 1;
71+
72+
// The ISBN (International Standard Book Number) for this book.
73+
string isbn = 2;
74+
75+
// The title of the book.
76+
string title = 3;
77+
78+
// The author or authors of the book.
79+
repeated string authors = 4;
80+
81+
// The rating assigned to the book.
82+
float rating = 5;
83+
}

0 commit comments

Comments
 (0)