From 9e8d12fcc318fa2dca1d11bff30605e85cce5acd Mon Sep 17 00:00:00 2001 From: Yusuke Tsutsumi Date: Sat, 25 Oct 2025 11:29:29 -0700 Subject: [PATCH 1/3] feat(164): specify create overwrites soft deleted 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. 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). --- aep/general/0121/aep.md.j2 | 3 +-- aep/general/0164/aep.md.j2 | 34 ++++++++++------------------------ 2 files changed, 11 insertions(+), 26 deletions(-) diff --git a/aep/general/0121/aep.md.j2 b/aep/general/0121/aep.md.j2 index 23a8990f..4f571d61 100644 --- a/aep/general/0121/aep.md.j2 +++ b/aep/general/0121/aep.md.j2 @@ -106,8 +106,7 @@ Examples of strong consistency include: 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][]) + get request for a resource **must** return `NOT_FOUND`. 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), diff --git a/aep/general/0164/aep.md.j2 b/aep/general/0164/aep.md.j2 index 01abdc88..05039bee 100644 --- a/aep/general/0164/aep.md.j2 +++ b/aep/general/0164/aep.md.j2 @@ -60,20 +60,19 @@ A resource that supports soft delete **should** provide an `Undelete` method: {% endtabs %} -### Long-running undelete +### Create -Some resources take longer to undelete a resource than is reasonable for a -regular API request. In this situation, the API **should** follow the -long-running request pattern AEP-151. +If a user attempts a create on a soft-deleted resource, the request **must** +succeed, acting as if the resource did not exist previously. ### List and Get -Soft-deleted resources **should not** be returned in `List` AEP-132 responses -by default (unless `bool show_deleted` is true). +Soft-deleted resources **must not** be returned in `List` AEP-132 responses by +default (unless `bool show_deleted` is true). -A `Get` AEP-131 request for a soft deleted resource **should** error with -`410 Gone` unless `bool show_deleted` is true, in which case soft-deleted -resources **must** return the resource. +A `Get` AEP-131 request for a soft deleted resource **must** return with a +`410 Gone` response unless `bool show_deleted` is true, in which case +soft-deleted resources **must** return the resource. Services that soft delete resources **may** choose a reasonable strategy for purging those resources, including automatic purging after a reasonable time @@ -84,9 +83,6 @@ removed. ### Declarative-friendly resources -A resource that is declarative-friendly AEP-128 **should** support soft delete -and undelete. - **Important:** There is an ambiguity in declarative tooling between "create" and "undelete". When given an alias which was previously deleted and a directive to make it exist, tooling usually does not know if the intent is to @@ -96,18 +92,9 @@ a new resource: the only way to undelete is to explicitly use the undelete RPC (an imperative operation), and declarative tools **may** elect not to map anything to undelete at all. -Declarative-friendly resources **must** use long-running operations for both -soft delete and undelete. The service **may** return an LRO that is already set -to done if the request is effectively immediate. - -Declarative-friendly resources **must** include `validate_only` AEP-163 and -`etag` AEP-154 in their `Undelete` methods. - ### Errors -If the user does not have permission to access the resource, regardless of -whether or not it exists, the service **must** error with `403 Forbidden`. -Permission **must** be checked prior to checking if the resource exists. +Also see [errors](/errors) for additional guidance. If the user does have proper permission, but the requested resource does not exist (either it was never created or already expunged), the service **must** @@ -115,8 +102,7 @@ error with `404 Not Found`. If the user calling a soft `Delete` has proper permission, but the requested resource is already deleted, the service **must** succeed if `allow_missing` is -`true`, and **should** error with `404 Not Found` if `allow_missing` is -`false`. +`true`, and **must** error with `404 Not Found` if `allow_missing` is `false`. If the user calling `Undelete` has proper permission, but the requested resource is not deleted, the service **must** error with `409 Conflict`. From ca8fec1b4c039246db9d073f842e3b0288592ef7 Mon Sep 17 00:00:00 2001 From: Yusuke Tsutsumi Date: Thu, 30 Oct 2025 21:51:25 -0700 Subject: [PATCH 2/3] address review feedback --- aep/general/0164/aep.md.j2 | 14 ++++++++++---- package-lock.json | 26 +++++++++++--------------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/aep/general/0164/aep.md.j2 b/aep/general/0164/aep.md.j2 index 05039bee..8b35b1d2 100644 --- a/aep/general/0164/aep.md.j2 +++ b/aep/general/0164/aep.md.j2 @@ -62,8 +62,14 @@ A resource that supports soft delete **should** provide an `Undelete` method: ### Create -If a user attempts a create on a soft-deleted resource, the request **must** -succeed, acting as if the resource did not exist previously. +Create methods **must** adhere to one of the following: + +- If a user attempts a create on a soft-deleted resource, the create **must** + succeed, acting as if the resource did not exist previously. +- The create must accept a field (query parameter for OAS), + `overwrite_soft_deleted`. If set to `false`, the request **must** fail if a + soft-deleted resource exists. If set to `true`, the request **must** succeed + if the resource exists acting as if the resource did not exist previously. ### List and Get @@ -71,8 +77,8 @@ Soft-deleted resources **must not** be returned in `List` AEP-132 responses by default (unless `bool show_deleted` is true). A `Get` AEP-131 request for a soft deleted resource **must** return with a -`410 Gone` response unless `bool show_deleted` is true, in which case -soft-deleted resources **must** return the resource. +`404 Not Found` response unless `bool show_deleted` is true, in which case +soft-deleted resources **must** return the resource (with the `DELETED` state value if the resource includes a [`state` field](/states)). Services that soft delete resources **may** choose a reasonable strategy for purging those resources, including automatic purging after a reasonable time diff --git a/package-lock.json b/package-lock.json index 3f4f2009..0fa5098e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,12 +13,11 @@ } }, "node_modules/@playwright/test": { - "version": "1.54.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.54.1.tgz", - "integrity": "sha512-FS8hQ12acieG2dYSksmLOF7BNxnVf2afRJdCuM1eMSxj6QTSE6G4InGF7oApGgDb65MX7AwMVlIkpru0yZA4Xw==", - "license": "Apache-2.0", + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.1.tgz", + "integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==", "dependencies": { - "playwright": "1.54.1" + "playwright": "1.56.1" }, "bin": { "playwright": "cli.js" @@ -32,7 +31,6 @@ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "hasInstallScript": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -42,12 +40,11 @@ } }, "node_modules/playwright": { - "version": "1.54.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.54.1.tgz", - "integrity": "sha512-peWpSwIBmSLi6aW2auvrUtf2DqY16YYcCMO8rTVx486jKmDTJg7UAhyrraP98GB8BoPURZP8+nxO7TSd4cPr5g==", - "license": "Apache-2.0", + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz", + "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==", "dependencies": { - "playwright-core": "1.54.1" + "playwright-core": "1.56.1" }, "bin": { "playwright": "cli.js" @@ -60,10 +57,9 @@ } }, "node_modules/playwright-core": { - "version": "1.54.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.54.1.tgz", - "integrity": "sha512-Nbjs2zjj0htNhzgiy5wu+3w09YetDx5pkrpI/kZotDlDUaYk0HVA5xrBVPdow4SAUIlhgKcJeJg4GRKW6xHusA==", - "license": "Apache-2.0", + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz", + "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==", "bin": { "playwright-core": "cli.js" }, From cd90bb42b4a99cf65de76889bc3da338d9fd77cd Mon Sep 17 00:00:00 2001 From: Yusuke Tsutsumi Date: Fri, 31 Oct 2025 11:24:37 -0700 Subject: [PATCH 3/3] address comment --- Makefile | 8 ++++---- aep/general/0164/aep.md.j2 | 5 +++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 7c50eb1c..0d25ce9a 100644 --- a/Makefile +++ b/Makefile @@ -11,10 +11,10 @@ install: lint: npm run lint - python scripts/fix.py --path ./aep/general/ - python scripts/validate_links.py + python3 scripts/fix.py --path ./aep/general/ + python3 scripts/validate_links.py check: npm run check - python scripts/fix.py --check --path ./aep/general/ - python scripts/validate_links.py + python3 scripts/fix.py --check --path ./aep/general/ + python3 scripts/validate_links.py \ No newline at end of file diff --git a/aep/general/0164/aep.md.j2 b/aep/general/0164/aep.md.j2 index 8b35b1d2..a18c9ffe 100644 --- a/aep/general/0164/aep.md.j2 +++ b/aep/general/0164/aep.md.j2 @@ -66,7 +66,7 @@ Create methods **must** adhere to one of the following: - If a user attempts a create on a soft-deleted resource, the create **must** succeed, acting as if the resource did not exist previously. -- The create must accept a field (query parameter for OAS), +- The create **must** accept a field (query parameter for OAS), `overwrite_soft_deleted`. If set to `false`, the request **must** fail if a soft-deleted resource exists. If set to `true`, the request **must** succeed if the resource exists acting as if the resource did not exist previously. @@ -78,7 +78,8 @@ default (unless `bool show_deleted` is true). A `Get` AEP-131 request for a soft deleted resource **must** return with a `404 Not Found` response unless `bool show_deleted` is true, in which case -soft-deleted resources **must** return the resource (with the `DELETED` state value if the resource includes a [`state` field](/states)). +soft-deleted resources **must** return the resource (with the `DELETED` state +value if the resource includes a [`state` field](/states)). Services that soft delete resources **may** choose a reasonable strategy for purging those resources, including automatic purging after a reasonable time