-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(121): porting AEP-121 from AIP-121
- slight rewording on a few sections. - removal of the wording "stateless protocol", which was generally confusing and debated at Google.
- Loading branch information
1 parent
2eb0c24
commit 60c2d56
Showing
2 changed files
with
155 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,155 @@ | ||
# Resource-oriented design | ||
|
||
**Note:** This AEP has not yet been adopted. See | ||
[this GitHub issue](https://github.com/aep-dev/aep.dev/issues/54) for more | ||
information. | ||
Resource-oriented design is a pattern for specifying [RPC][] APIs, based on the | ||
following high-level design principles: | ||
|
||
- The fundamental building blocks of an API are individually-named _resources_ | ||
(nouns) and the relationships and hierarchy that exist between them. | ||
- A small number of standard _methods_ (verbs) provide the semantics for most | ||
common operations. However, custom methods are available in situations where | ||
the standard methods do not fit. | ||
|
||
Readers might notice similarities between these principles and some principles | ||
of [REST][]; resource-oriented design borrows many principles from REST, while | ||
also defining its own patterns where appropriate. | ||
|
||
## Guidance | ||
|
||
When designing an API, consider the following: | ||
|
||
- The resources (nouns) the API will provide. | ||
- The relationships and hierarchies between those resources. | ||
- The schema of each resource. | ||
- The methods (verbs) each resource provides, relying as much as possible on | ||
the standard verbs. | ||
|
||
### Resources | ||
|
||
A resource-oriented API **must** be modeled as a resource hierarchy, where each | ||
node is either a simple resource or a collection of resources. | ||
|
||
A _collection_ contains resources of _the same type_. For example, a publisher | ||
has the collection of books that it publishes. A resource usually has fields, | ||
and resources may have any number of sub-resources (usually collections). | ||
|
||
**Note:** While there is some conceptual alignment between storage systems and | ||
APIs, a service with a resource-oriented API is not necessarily a database, and | ||
has enormous flexibility in how it interprets resources and methods. API | ||
designers **should not** expect that their API will be reflective of their | ||
database schema. In fact, having an API that is identical to the underlying | ||
database schema is actually an anti-pattern, as it tightly couples the surface | ||
to the underlying system. | ||
|
||
### Methods | ||
|
||
Resource-oriented APIs emphasize resources (data model) over the methods | ||
performed on those resources (functionality). A typical resource-oriented API | ||
exposes a large number of resources with a small number of methods on each | ||
resource. The methods can be either the standard methods ([Get][], [List][], | ||
[Create][], [Update][], [Delete][]), or [custom methods][]. | ||
|
||
If the request to or the response from a standard method (or a custom method in | ||
the same _service_) **is** the resource or **contains** the resource, the | ||
resource schema for that resource across all methods **must** be the same. | ||
|
||
| Standard method | Request | Response | | ||
| --------------- | --------------------- | --------------- | | ||
| Create | Contains the resource | Is the resource | | ||
| Get | None | Is the resource | | ||
| Update | Contains the resource | Is the resource | | ||
| Delete | None | None | | ||
| List | None | Is the resource | | ||
|
||
_The table above describes each standard method's relationship to the resource, | ||
where "None" indicates that the resource neither **is** nor **is contained** in | ||
the request or the response_ | ||
|
||
A resource **must** support at minimum [Get][]: clients must be able to | ||
validate the state of resources after performing a mutation such as [Create][], | ||
[Update][], or [Delete][]. | ||
|
||
A resource **must** also support [List][], except for [singleton resources][] | ||
where more than one resource is not possible. | ||
|
||
**Note:** A custom method in resource-oriented design does _not_ entail | ||
defining a new or custom HTTP verb. Custom methods use traditional HTTP verbs | ||
(usually `POST`) and define the custom verb in the URI. | ||
|
||
APIs **should** prefer standard methods over custom methods; the purpose of | ||
custom methods is to define functionality that does not cleanly map to any of | ||
the standard methods. Custom methods offer the same design freedom as | ||
traditional RPC APIs, which can be used to implement common programming | ||
patterns, such as database transactions, import and export, or data analysis. | ||
|
||
### Strong Consistency | ||
|
||
For methods that operate on the [management plane][], the completion of those | ||
operations (either successful or with an error, LRO or synchronous) **must** | ||
mean that the state of the resource's existence and all user-settable values | ||
have reached a steady-state. | ||
|
||
[output only][] values unrelated to the resource [state][] **should** also have | ||
reached a steady-state. for values that are related to the resource [state][]. | ||
|
||
Examples include: | ||
|
||
- Following a successful create that is is latest mutation on a resource, a get | ||
request for a resource **must** return the resource. | ||
- Following a successful update that is the latest mutation on a resource, a | ||
get request for a resource **must** return the final values from the update | ||
request. | ||
- Following a successful delete that is the latest mutation on a resource, a | ||
get request for a resource **must** return `NOT_FOUND` (or the resource with | ||
the `DELETED` state value in the case of [soft delete][]) | ||
|
||
Clients of resource-oriented APIs often need to orchestrate multiple operations | ||
in sequence (e.g. create resource A, create resource B which depends on A), and | ||
ensuring that resources immediately reflect steady user state after an | ||
operation is complete ensures clients can rely on method completion as a signal | ||
to begin the next operation. | ||
|
||
[output only][] fields ideally would follow the same guidelines, but as these | ||
fields can often represent a resources live state, it's sometimes necessary for | ||
these values to change after a successful mutation operation to reflect a state | ||
change. | ||
|
||
### Cyclic References | ||
|
||
The relationship between resources, such as parent-child or [resource | ||
references][], **must** be representable via a [directed acyclic graph][]. | ||
|
||
A cyclic relationship between resources increases the complexity of managing | ||
resources. Consider resources A and B that refer to each other. The process to | ||
create said resources are: | ||
|
||
1. create resource A without a reference to B. Retrieve id for resource A. | ||
2. create resource B with a reference to A. Retrieve id for resource B. | ||
3. update resource A with the reference to B. | ||
|
||
The delete operation may also become more complex, due to reasoning about which | ||
resource must be dereferenced first for a successful deletion. | ||
|
||
This requirement does not apply to relationships that are expressed via [output | ||
only][] fields, as they do not require the user to specify the values and in | ||
turn do not increase resource management complexity. | ||
|
||
[create]: ./0133.md | ||
[custom methods]: ./0136.md | ||
[delete]: ./0135.md | ||
[directed acyclic graph]: https://en.wikipedia.org/wiki/Directed_acyclic_graph | ||
[get]: ./0131.md | ||
[list]: ./0132.md | ||
[management plane]: ./0111.md#management-plane | ||
[output only]: ./0203.md#output-only | ||
[rest]: https://en.wikipedia.org/wiki/Representational_state_transfer | ||
[resource references]: ./0122.md#fields-representing-another-resource | ||
[rpc]: https://en.wikipedia.org/wiki/Remote_procedure_call | ||
[singleton resources]: ./0156.md | ||
[soft delete]: ./0164.md | ||
[state]: ./0216.md | ||
[stateless protocol]: https://en.wikipedia.org/wiki/Stateless_protocol | ||
[update]: ./0134.md | ||
|
||
## Changelog | ||
|
||
- **2024-01-27**: From from https://google.aip.dev/121 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
--- | ||
id: 121 | ||
state: reviewing | ||
state: approved | ||
slug: resources | ||
created: 2023-01-22 | ||
created: 2024-01-27 | ||
placement: | ||
category: resources |