Skip to content

Commit d5e8f5c

Browse files
author
Luke Sneeringer
authored
feat: AIP-131 – GET for individual resources (#2)
1 parent 0e46e18 commit d5e8f5c

4 files changed

Lines changed: 239 additions & 0 deletions

File tree

aip/general/0131/aip.md.j2

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# GET for individual resources
2+
3+
In REST APIs, it is customary to make a `GET` request to a resource's URI (for
4+
example, `/v1/publishers/{publisher}/books/{book}`) in order to retrieve that
5+
resource.
6+
7+
Our APIs honor this pattern by allowing `GET` requests to be sent to the
8+
resource URI, which returns the resource itself.
9+
10+
## Guidance
11+
12+
APIs **should** generally provide a `GET` method for resources unless it is not
13+
valuable for users to do so. When the `GET` method is used on a URI ending in a
14+
resource ID or resource ID alias, the result should be a single resource. For
15+
more information about using the `GET` method on a URI ending with a resource
16+
collection identifier, see AIP-132.
17+
18+
### Requests
19+
20+
Single-resource `GET` operations **must** be made by sending a `GET` request to
21+
the resource's URI:
22+
23+
```http
24+
GET /v1/publishers/{publisher}/books/{book} HTTP/2
25+
Host: library.googleapis.com
26+
Accept: application/json
27+
```
28+
29+
- The HTTP method **must** be `GET`.
30+
- The request **must** be safe and **must not** have side effects.
31+
- There **must not** be a request body.
32+
- If a `GET` request contains a body, the body **must** be ignored, and
33+
**must not** cause an error.
34+
- The request **must not** require any fields in the query string. The request
35+
**should not** include optional fields in the query string unless described
36+
in another AIP.
37+
38+
### Responses
39+
40+
Single-resource `GET` operations **must** return the resource itself, without
41+
any additional wrapping:
42+
43+
```json
44+
{
45+
"name": "publishers/lacroix/books/les-mis",
46+
"isbn": "978-037-540317-0",
47+
"title": "Les Misérables",
48+
"authors": ["Victor Hugo"],
49+
"rating": 9.6
50+
}
51+
```
52+
53+
### Errors
54+
55+
If the user does not have sufficient permission to know that the resource
56+
exists, the service **should** reply with an HTTP 404 error, regardless of
57+
whether or not the resource exists. Permission **must** be checked prior to
58+
checking if the resource exists.
59+
60+
If the user has sufficient permission to know that the resource exists, but is
61+
unable to access it, the service **should** reply with an HTTP 403 error.
62+
63+
If the user does have proper permission, but the requested resource does not
64+
exist, the service **must** reply with an HTTP 404 error.
65+
66+
## Interface Definitions
67+
68+
{% tab proto -%}
69+
70+
Get operations are specified using the following pattern:
71+
72+
{% sample 'get.proto', 'rpc GetBook' %}
73+
74+
- The RPC's name **must** begin with the word `Get`. The remainder of the RPC
75+
name **should** be the singular form of the resource's message name.
76+
- The request message **must** match the RPC name, with a `-Request` suffix.
77+
- The response message **must** be the resource itself. (There is no
78+
`GetBookResponse`.)
79+
- The response **should** usually include the fully-populated resource unless
80+
there is a reason to return a partial response (see AIP-157).
81+
- The HTTP verb **must** be `GET`.
82+
- The URI **should** contain a single variable field corresponding to the
83+
resource name.
84+
- This field **should** be called `name`.
85+
- The URI **should** have a variable corresponding to this field.
86+
- The `name` field **should** be the only variable in the URI path. All
87+
remaining parameters **should** map to URI query parameters.
88+
- There **must not** be a `body` key in the `google.api.http` annotation.
89+
- There **should** be exactly one `google.api.method_signature` annotation,
90+
with a value of `"name"`.
91+
92+
Get operations also implement a common request message pattern:
93+
94+
{% sample 'get.proto', 'message GetBookRequest' %}
95+
96+
- A resource name field **must** be included. It **should** be called `name`.
97+
- The field **should** be annotated as required.
98+
- The field **should** identify the [resource type][aip-123] that it
99+
references.
100+
- The comment for the `name` field **should** document the resource pattern.
101+
- The request message **must not** contain any other required fields, and
102+
**should not** contain other optional fields except those described in
103+
another AIP.
104+
105+
**Note:** The `name` field in the request object corresponds to the `name`
106+
variable in the `google.api.http` annotation on the RPC. This causes the `name`
107+
field in the request to be populated based on the value in the URL when the
108+
REST/JSON interface is used.
109+
110+
{% tab oas %}
111+
112+
Single-resource `GET` operations **must** be specified with consistent OpenAPI
113+
metadata:
114+
115+
{% sample 'get.oas.yaml', 'paths' %}
116+
117+
- The `operationId` **must** begin with the word `get`. The remainder of the
118+
`operationId` **should** be the singular form of the resource type's name.
119+
- The response content **must** be the resource itself. For example:
120+
`#/components/schemas/Book`
121+
- The response **should** usually include the fully-populated resource unless
122+
there is a reason to return a partial response (see AIP-157).
123+
- The URI **should** contain a variable for each individual ID in the resource
124+
hierarchy.
125+
- The path parameter for all resource IDs **must** be in the form
126+
`{resourceName}Id` (such as `bookId`), and path parameters representing the
127+
ID of parent resources **must** end with `Id`.
128+
129+
{% endtabs %}

aip/general/0131/aip.yaml

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

aip/general/0131/get.oas.yaml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
openapi: 3.0.3
3+
info:
4+
title: Library
5+
version: 1.0.0
6+
paths:
7+
/publishers/{publisherId}/books/{bookId}:
8+
get:
9+
operationId: getBook
10+
description: Get a single book.
11+
responses:
12+
200:
13+
description: OK
14+
content:
15+
application/json:
16+
schema:
17+
$ref: '#/components/schemas/Book'
18+
components:
19+
schema:
20+
Book:
21+
description: A representation of a single book.
22+
properties:
23+
name:
24+
type: string
25+
description: |
26+
The name of the book.
27+
Format: publishers/{publisher}/books/{book}
28+
isbn:
29+
type: string
30+
description: |
31+
The ISBN (International Standard Book Number) for this book.
32+
title:
33+
type: string
34+
description: The title of the book.
35+
authors:
36+
type: array
37+
items:
38+
type: string
39+
description: The author or authors of the book.
40+
rating:
41+
type: float
42+
description: The rating assigned to the book.

aip/general/0131/get.proto

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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/http.proto";
18+
import "google/api/resource.proto";
19+
20+
service Library {
21+
// Get a single book.
22+
rpc GetBook(GetBookRequest) returns (Book) {
23+
option (google.api.http) = {
24+
get: "/v1/{name=publishers/*/books/*}"
25+
};
26+
option (google.api.method_signature) = "name";
27+
}
28+
}
29+
30+
// Request message to get a single book.
31+
message GetBookRequest {
32+
string name = 1 [
33+
(google.api.field_behavior) = REQUIRED,
34+
(google.api.resource_reference) = {
35+
type: "library.googleapis.com/Book"
36+
}];
37+
}
38+
39+
// A representation of a single book.
40+
message Book {
41+
option (google.api.resource) = {
42+
type: "library.googleapis.com/Book"
43+
pattern: "publishers/{publisher}/books/{book}"
44+
};
45+
46+
// The name of the book.
47+
// Format: publishers/{publisher}/books/{book}
48+
string name = 1;
49+
50+
// The ISBN (International Standard Book Number) for this book.
51+
string isbn = 2;
52+
53+
// The title of the book.
54+
string title = 3;
55+
56+
// The author or authors of the book.
57+
repeated string authors = 4;
58+
59+
// The rating assigned to the book.
60+
float rating = 5;
61+
}

0 commit comments

Comments
 (0)