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