This is an automated email from the ASF dual-hosted git repository.

blue pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg.git


The following commit(s) were added to refs/heads/main by this push:
     new f60b582eb2 REST Spec: Add Idempotency-Key to OpenAPI (#14196)
f60b582eb2 is described below

commit f60b582eb24e74af9e8b583def3cb4c2f55a03b6
Author: Huaxin Gao <[email protected]>
AuthorDate: Wed Nov 19 16:03:40 2025 -0800

    REST Spec: Add Idempotency-Key to OpenAPI (#14196)
---
 open-api/rest-catalog-open-api.py   |  8 ++++-
 open-api/rest-catalog-open-api.yaml | 65 +++++++++++++++++++++++++++++++++++++
 2 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/open-api/rest-catalog-open-api.py 
b/open-api/rest-catalog-open-api.py
index 1709ba260f..c4846fc481 100644
--- a/open-api/rest-catalog-open-api.py
+++ b/open-api/rest-catalog-open-api.py
@@ -17,7 +17,7 @@
 
 from __future__ import annotations
 
-from datetime import date
+from datetime import date, timedelta
 from typing import Any, Dict, List, Literal, Optional, Union
 from uuid import UUID
 
@@ -65,6 +65,12 @@ class CatalogConfig(BaseModel):
             'GET /v1/{prefix}/namespaces/{namespace}/views/{view}',
         ],
     )
+    idempotency_key_lifetime: Optional[timedelta] = Field(
+        None,
+        alias='idempotency-key-lifetime',
+        description='Client reuse window for an Idempotency-Key (ISO-8601 
duration, e.g., PT30M, PT24H). Interpreted as the maximum time from the first 
submission using a key to the last retry during which a client may reuse that 
key. Servers SHOULD accept retries for at least this duration and MAY include a 
grace period to account for delays/clock skew. Clients SHOULD NOT reuse an 
Idempotency-Key after this window elapses; they SHOULD generate a new key for 
any subsequent attempt. Prese [...]
+        example='PT30M',
+    )
 
 
 class UpdateNamespacePropertiesRequest(BaseModel):
diff --git a/open-api/rest-catalog-open-api.yaml 
b/open-api/rest-catalog-open-api.yaml
index 1811fab0bf..dc6ae04db7 100644
--- a/open-api/rest-catalog-open-api.yaml
+++ b/open-api/rest-catalog-open-api.yaml
@@ -147,6 +147,7 @@ paths:
                   "defaults": {
                     "clients": "4"
                   },
+                  "idempotency-key-lifetime": "PT30M",
                   "endpoints": [
                     "GET /v1/{prefix}/namespaces/{namespace}",
                     "GET /v1/{prefix}/namespaces",
@@ -296,6 +297,8 @@ paths:
       tags:
         - Catalog API
       summary: Create a namespace
+      parameters:
+        - $ref: '#/components/parameters/idempotency-key'
       description:
         Create a namespace, with an optional set of properties.
         The server might also add properties, such as `last_modified_time` etc.
@@ -406,6 +409,8 @@ paths:
         - Catalog API
       summary: Drop a namespace from the catalog. Namespace must be empty.
       operationId: dropNamespace
+      parameters:
+        - $ref: '#/components/parameters/idempotency-key'
       responses:
         204:
           description: Success, no content
@@ -450,6 +455,8 @@ paths:
         - Catalog API
       summary: Set or remove properties on a namespace
       operationId: updateProperties
+      parameters:
+        - $ref: '#/components/parameters/idempotency-key'
       description:
         Set and/or remove properties on a namespace.
         The request body specifies a list of properties to remove and a map
@@ -562,6 +569,7 @@ paths:
       operationId: createTable
       parameters:
         - $ref: '#/components/parameters/data-access'
+        - $ref: '#/components/parameters/idempotency-key'
       requestBody:
         required: true
         content:
@@ -866,6 +874,8 @@ paths:
       tags:
         - Catalog API
       summary: Register a table in the given namespace using given metadata 
file location
+      parameters:
+        - $ref: '#/components/parameters/idempotency-key'
       description:
         Register a table using given metadata file location.
 
@@ -995,6 +1005,8 @@ paths:
         - Catalog API
       summary: Commit updates to a table
       operationId: updateTable
+      parameters:
+        - $ref: '#/components/parameters/idempotency-key'
       description:
         Commit updates to a table.
 
@@ -1115,6 +1127,7 @@ paths:
       operationId: dropTable
       description: Remove a table from the catalog
       parameters:
+        - $ref: '#/components/parameters/idempotency-key'
         - name: purgeRequested
           in: query
           required: false
@@ -1234,6 +1247,8 @@ paths:
       tags:
         - Catalog API
       summary: Rename a table from its current name to a new name
+      parameters:
+        - $ref: '#/components/parameters/idempotency-key'
       description:
         Rename a table from one identifier to another. It's valid to move a 
table
         across namespaces, but the server implementation is not required to 
support it.
@@ -1341,6 +1356,8 @@ paths:
         - Catalog API
       summary: Commit updates to multiple tables in an atomic operation
       operationId: commitTransaction
+      parameters:
+        - $ref: '#/components/parameters/idempotency-key'
       requestBody:
         description:
           Commit updates to multiple tables in an atomic operation
@@ -1590,6 +1607,8 @@ paths:
         - Catalog API
       summary: Replace a view
       operationId: replaceView
+      parameters:
+        - $ref: '#/components/parameters/idempotency-key'
       description:
         Commit updates to a view.
       requestBody:
@@ -1691,6 +1710,8 @@ paths:
       summary: Drop a view from the catalog
       operationId: dropView
       description: Remove a view from the catalog
+      parameters:
+        - $ref: '#/components/parameters/idempotency-key'
       responses:
         204:
           description: Success, no content
@@ -1752,6 +1773,8 @@ paths:
         Rename a view from one identifier to another. It's valid to move a view
         across namespaces, but the server implementation is not required to 
support it.
       operationId: renameView
+      parameters:
+        - $ref: '#/components/parameters/idempotency-key'
       requestBody:
         description: Current view identifier to rename and new view identifier 
to rename to
         content:
@@ -1909,6 +1932,36 @@ components:
       schema:
         type: string
 
+    idempotency-key:
+      name: Idempotency-Key
+      in: header
+      required: false
+      schema:
+        type: string
+        format: uuid
+        minLength: 36
+        maxLength: 36
+        example: "017F22E2-79B0-7CC3-98C4-DC0C0C07398F"
+      description: |
+        Optional client-provided idempotency key for safe request retries.
+
+        When present, the server ensures no additional effects for requests 
that carry the same
+        Idempotency-Key. If a prior request with this key has been finalized, 
the server returns
+        an equivalent final response without re-running the operation. The 
response body may
+        reflect a newer state of the catalog than existed at the time of the 
commit.
+
+        Finalization rules:
+        - Finalize & replay: 200, 201, 204, and deterministic terminal 4xx 
(including 409
+          such as AlreadyExists, NamespaceNotEmpty, etc.)
+        - Do not finalize (not stored/replayed): 5xx
+
+        Key Requirements:
+        - Key format: UUIDv7 in string form (RFC 9562).
+        - The idempotency key must be globally unique (no reuse across 
different operations).
+        - Catalogs SHOULD NOT expire keys before the end of the advertised 
token lifetime.
+        - If Idempotency-Key is used, clients MUST reuse the same key when 
retrying the same
+          logical operation and MUST generate a new key for a different 
operation.
+
   ##############################
   # Application Schema Objects #
   ##############################
@@ -1972,6 +2025,18 @@ components:
               "GET /v1/{prefix}/namespaces/{namespace}/tables/{table}",
               "GET /v1/{prefix}/namespaces/{namespace}/views/{view}"
             ]
+        idempotency-key-lifetime:
+          type: string
+          format: duration
+          description:
+            Client reuse window for an Idempotency-Key (ISO-8601 duration, 
e.g., PT30M, PT24H).
+            Interpreted as the maximum time from the first submission using a 
key to the last retry
+            during which a client may reuse that key. Servers SHOULD accept 
retries for at least this
+            duration and MAY include a grace period to account for 
delays/clock skew. Clients SHOULD NOT
+            reuse an Idempotency-Key after this window elapses; they SHOULD 
generate a new key for any
+            subsequent attempt. Presence of this field indicates the server 
supports Idempotency-Key
+            semantics for mutation endpoints. If absent, clients MUST assume 
idempotency is not supported.
+          example: PT30M
 
     CreateNamespaceRequest:
       type: object

Reply via email to