|
| 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 %} |
0 commit comments