Skip to content

Commit

Permalink
Merge branch 'master' into aip-163
Browse files Browse the repository at this point in the history
  • Loading branch information
Luke Sneeringer authored Jan 6, 2021
2 parents ba9c709 + d5e8f5c commit 285abae
Show file tree
Hide file tree
Showing 8 changed files with 477 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .github/renovate.json5
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
extends: ['config:base', 'docker:disable'],
commitMessagePrefix: 'chore: ',
groupName: 'multiple dependencies',
}
221 changes: 221 additions & 0 deletions aip/general/0001/aip.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
# AIP Purpose and Guidelines

Service APIs on the Internet continue to proliferate; having a machine-readable
API is an expectation and prerequisite to adoption for many services. By some
estimates, there are now more than 20,000 public REST APIs available.

As this corpus continues to grow, many companies struggle with API Governance:
even as companies grow and disparate teams work to deliver discrete services,
APIs ought to remain simple, intuitive, and consistent.

Therefore, it is increasingly necessary to have a corpus of documentation for
API producers, reviewers, and other interested parties to reference. The AIP
collection provides a way to provide consistent documentation for API design
guidance.

## What is an AIP?

AIP stands for **API Improvement Proposal**, which is a design document
providing high-level, concise documentation for API development.

Companies that adopt the AIP program use them as a source of truth for
API-related documentation, and the means by which service producers discuss and
come to consensus on API guidance. AIPs are maintained as Markdown files with
metadata in the AIP GitHub repository.

## Adopting AIPs

Companies **may** adopt the AIP system in one of two ways:

- By applying the guidance described at [aip.dev][].
- By "forking" the AIP system and setting up their own subdomain.

Companies with an already-established corpus of services are unlikely to have
exactly followed the guidance at [aip.dev][]. Forking the system is valuable
because the guidance becomes comparable. Forks **must** retain the same
numbering system (AIP-2) to provide that comparability.

### Technical leadership

The AIP system, as well as the guidance on [aip.dev][], is overseen by the AIP
technical steering committee. The committee is the set of people who make
decisions on AIPs. The general goal is that the AIP process is collaborative
and that we largely work on the basis of consensus. However, a limited number
of designated approvers is necessary, and these committee members will be
approvers for each AIP on [aip.dev][].

The technical steering committee membership is currently:

- Antoine Boyer (@tinnou), Netflix
- Ross Hamilton (@rhamiltonsf), Salesforce
- Mike Kistler (@mkistler), IBM
- Luke Sneeringer (@lukesneeringer), Google

The committee is also responsible for the administrative and editorial aspects
of shepherding AIPs and managing the AIP pipeline and workflow. They approve
PRs to AIPs, assign proposal numbers, manage the agenda, set AIP states, and so
forth. They also ensure that AIPs are readable (proper spelling, grammar,
sentence structure, markup, etc.).

Committee membership is by invitation of the current committee. The committee
**must not** include more than two members from the same company.

**Note:** Companies that maintain their own fork of [aip.dev][] select their
own leadership and have full control of their fork's content.

## States

At any given time, AIPs may exist in a variety of states as they work their way
through the process. The following is a summary of each state.

### Reviewing

Initial discussion on most AIPs occurs in the initial pull request to submit
the AIP. Once this PR is merged, the AIP exists in the "Reviewing" state. This
means that the authors and the technical steering committee have reached a
general consensus on the proposal.

At this stage, the committee may request changes or suggest alternatives to the
proposal before moving forward, but there is a general expectation that the
proposal will move forward and it is usually safe to "early adopt" it.

An AIP **must** be in the reviewing state for at least 14 days before being
approved, and the committee **should** send appropriate communication regarding
the pending approval.

**Note:** As a formal matter, one AIP approver (other than the author) **must**
provide formal signoff to advance an AIP to the reviewing state. Additionally,
there **must not** be formal objections ("changes requested" on the GitHub PR)
from other approvers.

### Approved

Once an AIP has been agreed upon, it enters "approved" state and is considered
"best current practice".

AIPs **may** be edited after they are approved, either to correct grammar or
word choices, or to clarify semantic guidance (in response to reader
questions). In rare occasions, new guidance **may** be added.

Clarifications and new guidance **must** be reflected in the changelog.
Correction of typos or minor language alterations **may** be done silently.

**Note:** As a formal matter, two AIP approvers (other than the author)
**must** provide formal signoff to advance an AIP to the approved state.
Additionally, there **must not** be formal objections ("changes requested" on
the GitHub PR) from other approvers.

### Final

If an AIP has been approved for a significant period and the technical steering
committee is certain that no further guidance will be needed, they **may** move
the AIP in to "final" state.

AIPs in the final state **must not** be amended with new guidance. They **may**
be editied to correct spelling, grammar, or clarity provided there are no
semantic changes.

**Note:** As a formal matter, two AIP approvers **must** provide formal signoff
to advance an AIP to the final state. Additionally, there **must not** be
formal objections ("changes requested" on the GItHub PR) from other approvers.

### Replaced

If an AIP has been replaced by another AIP, it enters "replaced" state. The AIP
**must** include a notice explaining the replacement and rationale (the
replacement AIP **should** also clearly explain the rationale).

In general, service producers rely primarily on AIPs in the "approved" state.
Service producers **may** rely on AIPs in the "reviewing" state

### Withdrawn

If an AIP is withdrawn by the author or champion, or is rejected by the
technical steering committee after reaching the "reviewing" state, it enters
"withdrawn" state. Withdrawn AIPs remain accessible, but are removed from the
indexes; they provide documentation and reference to inform future discussions.

## Workflow

The following workflow describes the process for proposing an AIP, and moving
an AIP from proposal to implementation to final acceptance.

### Overview

```graphviz
digraph d_front_back {
rankdir=LR;
node [ style="filled,solid" shape=box fontname="Roboto" ];
github_pr [ shape="oval" label="GitHub PR" fillcolor="orange" ];
reviewing [ label="Reviewing" fillcolor="lightskyblue" ];
approved [ label="Approved" fillcolor="palegreen" ];
final [ label="Final" fillcolor="palegreen" ];
withdrawn [ label="Withdrawn" fillcolor="mistyrose" ];
replaced [ label="Replaced" fillcolor="lightsteelblue" ];
github_pr -> reviewing;
reviewing -> approved;
reviewing -> withdrawn [ style=dashed, color=mistyrose3 ];
approved -> final;
approved -> replaced [ style=dashed, color=lightsteelblue3 ];
final -> replaced [ style=dashed color=lightsteelblue3 ];
}
```

### Proposing an AIP

In order to propose an AIP, first open a pull request with a draft AIP; the AIP
should conform to the guidance in AIP-8. Most AIPs **should** be no more than
two pages if printed out.

If the technical steering committee has suggested an AIP number, use that;
otherwise use 99 (and expect to change it during the course of the review).

**Important:** Ensure that the PR is editable by maintainers.

In most circumstances, the committee will assign the proposal an AIP number and
begin discussion. Once there is consensus, the committee will merge the PR, and
the AIP will enter the "reviewing" state.

The committee **may** reject an AIP outright if they have an obvious reason to
do so (e.g. the proposal was already discussed and rejected in another AIP or
is fundamentally unsound), in which case the PR is not merged.

### Accepting an AIP

The editors will work together to ensure that qualified proposals do not linger
in review.

To gain final approval, an AIP **must** be approved by, at minimum, two members
of the technical steering committee. Additionally, there **should not** be any
committee members requesting significant changes (indicated by the use of the
"changes requested" feature on GitHub).

**Note:** If an AIP editor is the primary author of an AIP, then at least two
_other_ editors must approve it.

### Withdrawing or Rejecting an AIP

The author of an AIP may decide, after further consideration, that an AIP
should not advance. If so, the author may withdraw the AIP by updating the PR
adding a notice of withdrawal with an explanation of the rationale.

Additionally, the author may be unable to get consensus among the group and the
technical steering committee may elect to reject the AIP. In this situation,
the committee shall amend the PR adding a notice of rejection with an
explanation of the rationale. In both cases, the committee **must** update the
state accordingly and submit the PR.

### Replacing an AIP

In rare cases, it may be necessary to replace an AIP with another one. This is
not general practice: minor edits to approved AIPs are acceptable, and AIPs
only enter final state when there is high confidence that further edits will
not be necessary.

However, if new guidance fundamentally alters the old guidance in some way,
then the technical steering committee **should** create a new AIP that, once
approved, will replace the old one. The old one then enters "Replaced" state,
and will link to the new, current AIP.

[aip.dev]: https://aip.dev/
11 changes: 11 additions & 0 deletions aip/general/0001/aip.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
id: 1
state: reviewing
created: 2020-10-05
placement:
category: meta
order: 10
js_scripts:
- /assets/js/graphviz/viz.js
- /assets/js/graphviz/lite.render.js
- /assets/js/aip/aip-graphviz.js
129 changes: 129 additions & 0 deletions aip/general/0131/aip.md.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# GET for individual resources

In REST APIs, it is customary to make a `GET` request to a resource's URI (for
example, `/v1/publishers/{publisher}/books/{book}`) in order to retrieve that
resource.

Our APIs honor this pattern by allowing `GET` requests to be sent to the
resource URI, which returns the resource itself.

## Guidance

APIs **should** generally provide a `GET` method for resources unless it is not
valuable for users to do so. When the `GET` method is used on a URI ending in a
resource ID or resource ID alias, the result should be a single resource. For
more information about using the `GET` method on a URI ending with a resource
collection identifier, see AIP-132.

### Requests

Single-resource `GET` operations **must** be made by sending a `GET` request to
the resource's URI:

```http
GET /v1/publishers/{publisher}/books/{book} HTTP/2
Host: library.googleapis.com
Accept: application/json
```

- The HTTP method **must** be `GET`.
- The request **must** be safe and **must not** have side effects.
- There **must not** be a request body.
- If a `GET` request contains a body, the body **must** be ignored, and
**must not** cause an error.
- The request **must not** require any fields in the query string. The request
**should not** include optional fields in the query string unless described
in another AIP.

### Responses

Single-resource `GET` operations **must** return the resource itself, without
any additional wrapping:

```json
{
"name": "publishers/lacroix/books/les-mis",
"isbn": "978-037-540317-0",
"title": "Les Misérables",
"authors": ["Victor Hugo"],
"rating": 9.6
}
```

### Errors

If the user does not have sufficient permission to know that the resource
exists, the service **should** reply with an HTTP 404 error, regardless of
whether or not the resource exists. Permission **must** be checked prior to
checking if the resource exists.

If the user has sufficient permission to know that the resource exists, but is
unable to access it, the service **should** reply with an HTTP 403 error.

If the user does have proper permission, but the requested resource does not
exist, the service **must** reply with an HTTP 404 error.

## Interface Definitions

{% tab proto -%}

Get operations are specified using the following pattern:

{% sample 'get.proto', 'rpc GetBook' %}

- The RPC's name **must** begin with the word `Get`. The remainder of the RPC
name **should** be the singular form of the resource's message name.
- The request message **must** match the RPC name, with a `-Request` suffix.
- The response message **must** be the resource itself. (There is no
`GetBookResponse`.)
- The response **should** usually include the fully-populated resource unless
there is a reason to return a partial response (see AIP-157).
- The HTTP verb **must** be `GET`.
- The URI **should** contain a single variable field corresponding to the
resource name.
- This field **should** be called `name`.
- The URI **should** have a variable corresponding to this field.
- The `name` field **should** be the only variable in the URI path. All
remaining parameters **should** map to URI query parameters.
- There **must not** be a `body` key in the `google.api.http` annotation.
- There **should** be exactly one `google.api.method_signature` annotation,
with a value of `"name"`.

Get operations also implement a common request message pattern:

{% sample 'get.proto', 'message GetBookRequest' %}

- A resource name field **must** be included. It **should** be called `name`.
- The field **should** be annotated as required.
- The field **should** identify the [resource type][aip-123] that it
references.
- The comment for the `name` field **should** document the resource pattern.
- The request message **must not** contain any other required fields, and
**should not** contain other optional fields except those described in
another AIP.

**Note:** The `name` field in the request object corresponds to the `name`
variable in the `google.api.http` annotation on the RPC. This causes the `name`
field in the request to be populated based on the value in the URL when the
REST/JSON interface is used.

{% tab oas %}

Single-resource `GET` operations **must** be specified with consistent OpenAPI
metadata:

{% sample 'get.oas.yaml', 'paths' %}

- The `operationId` **must** begin with the word `get`. The remainder of the
`operationId` **should** be the singular form of the resource type's name.
- The response content **must** be the resource itself. For example:
`#/components/schemas/Book`
- The response **should** usually include the fully-populated resource unless
there is a reason to return a partial response (see AIP-157).
- The URI **should** contain a variable for each individual ID in the resource
hierarchy.
- The path parameter for all resource IDs **must** be in the form
`{resourceName}Id` (such as `bookId`), and path parameters representing the
ID of parent resources **must** end with `Id`.

{% endtabs %}
7 changes: 7 additions & 0 deletions aip/general/0131/aip.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
id: 131
state: approved
created: 2019-01-22
placement:
category: operations
order: 10
Loading

0 comments on commit 285abae

Please sign in to comment.