Skip to content

Commit 12dc65a

Browse files
authored
feat(164): specify create overwrites soft deleted (#371)
To help ensure that declarative clients do not have a degraded user experience with resources that implement soft-delete, specify that create overwrites an existing soft-deleted resource, or has a query parameter that allows a client to specify overwrite behavior. This ensures that a declarative tool can still properly apply a resource, overwriting it instead of requiring an out of band force delete or having the user modify the ID of the resource. fixes #111 (which includes some significant debate and context on why this approach was chosen). Inlined description: In #365, there was additional discussion or the viability of the pattern. @odsod brings up valid points that the cost to implement my proposed pattern is quite a bit different (requires two different collections), and perhaps implements a sort of "snapshot" resource collection than a soft-deleted resource, whose main intention is primarily around having a resource that exists until some expiry date rather than a snapshot that should be recovered. In addition, most who have joined AEP live meetings have raised valid examples of soft deleted resources in their APIs (e.g. cryptographic keys in Azure), and therefore the omissions of this pattern might invalidate those resources. As such, combined with the primary motivation here to eliminate the poor UX with declarative clients which may need to overwrite the resource, this change acts as a more surgical fix to ensure that a create behaves like any other resource (specifically allowing the recreation of one), even when using the soft delete pattern.
1 parent c02e392 commit 12dc65a

4 files changed

Lines changed: 33 additions & 45 deletions

File tree

Makefile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ install:
1111

1212
lint:
1313
npm run lint
14-
python scripts/fix.py --path ./aep/general/
15-
python scripts/validate_links.py
14+
python3 scripts/fix.py --path ./aep/general/
15+
python3 scripts/validate_links.py
1616

1717
check:
1818
npm run check
19-
python scripts/fix.py --check --path ./aep/general/
20-
python scripts/validate_links.py
19+
python3 scripts/fix.py --check --path ./aep/general/
20+
python3 scripts/validate_links.py

aep/general/0121/aep.md.j2

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,7 @@ Examples of strong consistency include:
106106
get request for a resource **must** return the final values from the update
107107
request.
108108
- Following a successful delete that is the latest mutation on a resource, a
109-
get request for a resource **must** return `NOT_FOUND` (or the resource with
110-
the `DELETED` state value in the case of [soft delete][])
109+
get request for a resource **must** return `NOT_FOUND`.
111110

112111
Clients of resource-oriented APIs often need to orchestrate multiple operations
113112
in sequence (e.g., create resource A, create resource B which depends on A),

aep/general/0164/aep.md.j2

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -60,20 +60,26 @@ A resource that supports soft delete **should** provide an `Undelete` method:
6060

6161
{% endtabs %}
6262

63-
### Long-running undelete
63+
### Create
6464

65-
Some resources take longer to undelete a resource than is reasonable for a
66-
regular API request. In this situation, the API **should** follow the
67-
long-running request pattern AEP-151.
65+
Create methods **must** adhere to one of the following:
66+
67+
- If a user attempts a create on a soft-deleted resource, the create **must**
68+
succeed, acting as if the resource did not exist previously.
69+
- The create **must** accept a field (query parameter for OAS),
70+
`overwrite_soft_deleted`. If set to `false`, the request **must** fail if a
71+
soft-deleted resource exists. If set to `true`, the request **must** succeed
72+
if the resource exists acting as if the resource did not exist previously.
6873

6974
### List and Get
7075

71-
Soft-deleted resources **should not** be returned in `List` AEP-132 responses
72-
by default (unless `bool show_deleted` is true).
76+
Soft-deleted resources **must not** be returned in `List` AEP-132 responses by
77+
default (unless `bool show_deleted` is true).
7378

74-
A `Get` AEP-131 request for a soft deleted resource **should** error with
75-
`410 Gone` unless `bool show_deleted` is true, in which case soft-deleted
76-
resources **must** return the resource.
79+
A `Get` AEP-131 request for a soft deleted resource **must** return with a
80+
`404 Not Found` response unless `bool show_deleted` is true, in which case
81+
soft-deleted resources **must** return the resource (with the `DELETED` state
82+
value if the resource includes a [`state` field](/states)).
7783

7884
Services that soft delete resources **may** choose a reasonable strategy for
7985
purging those resources, including automatic purging after a reasonable time
@@ -84,9 +90,6 @@ removed.
8490

8591
### Declarative-friendly resources
8692

87-
A resource that is declarative-friendly AEP-128 **should** support soft delete
88-
and undelete.
89-
9093
**Important:** There is an ambiguity in declarative tooling between "create"
9194
and "undelete". When given an alias which was previously deleted and a
9295
directive to make it exist, tooling usually does not know if the intent is to
@@ -96,27 +99,17 @@ a new resource: the only way to undelete is to explicitly use the undelete RPC
9699
(an imperative operation), and declarative tools **may** elect not to map
97100
anything to undelete at all.
98101

99-
Declarative-friendly resources **must** use long-running operations for both
100-
soft delete and undelete. The service **may** return an LRO that is already set
101-
to done if the request is effectively immediate.
102-
103-
Declarative-friendly resources **must** include `validate_only` AEP-163 and
104-
`etag` AEP-154 in their `Undelete` methods.
105-
106102
### Errors
107103

108-
If the user does not have permission to access the resource, regardless of
109-
whether or not it exists, the service **must** error with `403 Forbidden`.
110-
Permission **must** be checked prior to checking if the resource exists.
104+
Also see [errors](/errors) for additional guidance.
111105

112106
If the user does have proper permission, but the requested resource does not
113107
exist (either it was never created or already expunged), the service **must**
114108
error with `404 Not Found`.
115109

116110
If the user calling a soft `Delete` has proper permission, but the requested
117111
resource is already deleted, the service **must** succeed if `allow_missing` is
118-
`true`, and **should** error with `404 Not Found` if `allow_missing` is
119-
`false`.
112+
`true`, and **must** error with `404 Not Found` if `allow_missing` is `false`.
120113

121114
If the user calling `Undelete` has proper permission, but the requested
122115
resource is not deleted, the service **must** error with `409 Conflict`.

package-lock.json

Lines changed: 11 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)