You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polaris.apache.org by dh...@apache.org on 2026/10/27 00:47:32 UTC
(polaris) branch main updated: Add an OpenAPI specification for a Shares API (beta) (#5446)
This is an automated email from the ASF dual-hosted git repository.
dennishuo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/polaris.git
The following commit(s) were added to refs/heads/main by this push:
new 244a582a7f Add an OpenAPI specification for a Shares API (beta) (#5446)
244a582a7f is described below
commit 244a582a7fb4f6e9a83f8242c57ec6f5ffb2db29
Author: Dennis Huo <74...@users.noreply.github.com>
AuthorDate: Mon Oct 26 17:47:24 2026 -0700
Add an OpenAPI specification for a Shares API (beta) (#5446)
* Add the Polaris Shares API OpenAPI specification (beta, draft)
Adds spec/polaris-shares-api.yaml, a beta management API for shares and their members (what is shared), served under /api/shares-management/v1, and its entry in spec/README.md. Specification only. Consumer management and server code follow in separate PRs.
---
spec/README.md | 4 +
spec/polaris-shares-api.yaml | 458 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 462 insertions(+)
diff --git a/spec/README.md b/spec/README.md
index 6346afbdba..b87f4e4eb0 100644
--- a/spec/README.md
+++ b/spec/README.md
@@ -24,6 +24,10 @@ Apache Polaris provides the following OpenAPI specifications:
- [polaris-management-service.yml](polaris-management-service.yml) - Defines the management APIs for creating and managing
principals, principal roles, catalogs and catalog roles.
+- [polaris-shares-api.yaml](polaris-shares-api.yaml) - Defines the management APIs for shares and their
+ members, which define what is shared, served under `/api/shares-management/v1` (beta; served only when
+ the shares feature is enabled).
+
- [polaris-catalog-service.yaml](polaris-catalog-service.yaml) - Defines the specification for the Apache Polaris
Catalog API, which encompasses both the Apache Iceberg REST Catalog API and Apache
Polaris-native APIs:
diff --git a/spec/polaris-shares-api.yaml b/spec/polaris-shares-api.yaml
new file mode 100644
index 0000000000..bef908e803
--- /dev/null
+++ b/spec/polaris-shares-api.yaml
@@ -0,0 +1,458 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+openapi: 3.0.3
+info:
+ title: Polaris Shares API
+ version: 0.0.1
+ description:
+ Defines the management APIs for sharing catalog content as read-only shares, which
+ define what is shared. A share is a named set of objects from one catalog. Consumers
+ read shared tables with any Iceberg REST client. Who may read a share is decided by the
+ service's authorization, and how a consumer authenticates is up to the service, as for
+ the Iceberg REST API. Shares are realm-level objects addressed by name, and each share
+ is bound to one catalog. This API is in beta and may change in a backward-incompatible
+ way, and it is served only when the shares feature flag is enabled (off by default).
+servers:
+ - url: "{scheme}://{host}/api/shares-management/v1"
+ description: Server URL when the port can be inferred from the scheme
+ variables:
+ scheme:
+ description: The scheme of the URI, either http or https.
+ default: https
+ host:
+ description: The host address for the specified server
+ default: localhost
+security:
+ - OAuth2: []
+
+paths:
+ /shares:
+ get:
+ operationId: listShares
+ summary: List shares
+ parameters:
+ - name: pageToken
+ in: query
+ required: false
+ description: The continuation token returned with the previous page. Absent for the first page
+ schema:
+ type: string
+ - name: pageSize
+ in: query
+ required: false
+ description:
+ Maximum number of items to return, at least 1. If absent, or larger than the service's
+ maximum, the service's maximum is used
+ schema:
+ type: integer
+ minimum: 1
+ description:
+ "List all shares in this Polaris service."
+ responses:
+ 200:
+ description: A page of shares
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Shares"
+ 403:
+ description: "The caller does not have permission to list shares"
+ 501:
+ description: "This realm's persistence does not support share records. Shares are unavailable until it is upgraded"
+ post:
+ operationId: createShare
+ summary: Create a share
+ description:
+ "Create a share bound to the catalog named in the request. A new share has no members until
+ members are added, and no one can read it until access to it is granted. Not idempotent: a retry
+ after a lost response returns 409 because the share exists. Fetch it by name."
+ requestBody:
+ description: The share to create
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/CreateShareRequest"
+ responses:
+ 201:
+ description: "Successful response"
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Share"
+ 400:
+ description: "The share name is invalid, or the request is malformed"
+ 403:
+ description: "The caller does not have permission to create a share, or to create a catalog role in the bound catalog"
+ 404:
+ description: "The bound catalog does not exist"
+ 409:
+ description: "A share with the specified name already exists"
+ 501:
+ description: "This realm's persistence does not support share records. Shares are unavailable until it is upgraded"
+
+ /shares/{shareName}:
+ parameters:
+ - name: shareName
+ in: path
+ description: The name of the share
+ required: true
+ schema:
+ type: string
+ get:
+ operationId: getShare
+ summary: Get a share
+ description:
+ "Get a share by name."
+ responses:
+ 200:
+ description: The share
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Share"
+ 403:
+ description: "The caller does not have permission to read this share"
+ 404:
+ description: "The share does not exist"
+ 501:
+ description: "This realm's persistence does not support share records. Shares are unavailable until it is upgraded"
+ put:
+ operationId: updateShare
+ summary: Update a share
+ description:
+ "Update a share's description or properties: an
+ absent field changes nothing, an empty description clears it, properties are
+ merged by key, and removeProperties lists the keys to drop. Share membership is
+ updated through the members resource, not through this operation."
+ requestBody:
+ description: The update to apply
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/UpdateShareRequest"
+ responses:
+ 200:
+ description: The updated share
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Share"
+ 400:
+ description: "A property key is both set and removed, or a reserved key is set or removed"
+ 403:
+ description: "The caller does not have permission to update this share"
+ 404:
+ description: "The share does not exist"
+ 409:
+ description: "The share was concurrently modified. Fetch and retry"
+ 501:
+ description: "This realm's persistence does not support share records. Shares are unavailable until it is upgraded"
+ delete:
+ operationId: deleteShare
+ summary: Delete a share
+ description:
+ "Delete a share. Every consumer's access to it ends immediately."
+ responses:
+ 204:
+ description: "Success, no content"
+ 403:
+ description: "The caller does not have permission to delete this share"
+ 404:
+ description: "The share does not exist"
+ 409:
+ description: "The share was concurrently modified. Fetch and retry"
+ 501:
+ description: "This realm's persistence does not support share records. Shares are unavailable until it is upgraded"
+
+ /shares/{shareName}/members:
+ parameters:
+ - name: shareName
+ in: path
+ description: The name of the share
+ required: true
+ schema:
+ type: string
+ get:
+ operationId: listShareMembers
+ summary: List share members
+ parameters:
+ - name: pageToken
+ in: query
+ required: false
+ description: The continuation token returned with the previous page. Absent for the first page
+ schema:
+ type: string
+ - name: pageSize
+ in: query
+ required: false
+ description:
+ Maximum number of items to return, at least 1. If absent, or larger than the service's
+ maximum, the service's maximum is used
+ schema:
+ type: integer
+ minimum: 1
+ description:
+ "List the members of a share."
+ responses:
+ 200:
+ description: A page of the share's members
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ShareMembers"
+ 403:
+ description: "The caller does not have permission to read this share"
+ 404:
+ description: "The share does not exist"
+ 501:
+ description: "This realm's persistence does not support share records. Shares are unavailable until it is upgraded"
+ post:
+ operationId: updateShareMembers
+ summary: Update share members
+ description:
+ "Atomically apply a list of member additions and removals: either every update is applied or
+ none is. A member may appear at most once in a batch. The batch is applied against one version of the share
+ (currentEntityVersion if given, otherwise the version the service reads). Any
+ concurrent change to the share, including another member update, returns 409. Fetch
+ the share and retry. A stale currentEntityVersion returns 409 before any update is
+ applied. Adding a member that is already present returns 400, and removing one that
+ is absent returns 404. Every member must belong to the share's catalog. A removed
+ member disappears from every consumer's view immediately. Read grants follow the
+ membership record once the update commits. If granting fails partway, the service
+ documents its behavior."
+ requestBody:
+ description: The membership updates to apply
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/UpdateShareMembersRequest"
+ responses:
+ 200:
+ description:
+ The updated share, with its new entityVersion
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Share"
+ 400:
+ description: "An update in the list is invalid, a member appears more than once, or a member is outside the share's bound catalog"
+ 403:
+ description: "The caller does not have permission to update this share's members"
+ 404:
+ description: "The share, or a referenced member object, does not exist"
+ 409:
+ description: "The share was concurrently modified. Fetch and retry"
+ 501:
+ description: "This realm's persistence does not support share records. Shares are unavailable until it is upgraded"
+
+components:
+ securitySchemes:
+ OAuth2:
+ type: oauth2
+ description:
+ OAuth2 client credentials for provider administrators, as in the Polaris Management API.
+ Consumers do not use this scheme. The token URL below is illustrative.
+ flows:
+ clientCredentials:
+ tokenUrl: "https://auth.example.invalid/oauth/tokens"
+ scopes: {}
+
+ schemas:
+ Share:
+ description:
+ A named, realm-level container that lists shared objects. A share is bound to one catalog,
+ and its members are objects in that catalog. Share names are unique across the
+ service.
+ type: object
+ properties:
+ name:
+ type: string
+ pattern: "^[A-Za-z0-9][A-Za-z0-9_-]*$"
+ maxLength: 256
+ description: The share's name, unique across the realm's shares. Letters, digits, underscore and hyphen, starting with a letter or digit, at most 256 characters
+ catalogName:
+ type: string
+ description:
+ The catalog this share is bound to, whose objects it can contain. Required at creation,
+ immutable afterwards. Exactly one catalog is bound
+ description:
+ type: string
+ properties:
+ type: object
+ additionalProperties:
+ type: string
+ description:
+ User-defined properties. Keys with the reserved "share." prefix belong to the service. They
+ are never returned here and are rejected (400) when set
+ createTimestamp:
+ type: string
+ format: date-time
+ description: The creation time, in ISO 8601 (RFC 3339) format. Set by the service
+ readOnly: true
+ lastUpdateTimestamp:
+ type: string
+ format: date-time
+ description: The last update time, in ISO 8601 (RFC 3339) format. Set by the service
+ readOnly: true
+ entityVersion:
+ type: integer
+ description:
+ The share's version, incremented on every change. Send it as currentEntityVersion with an
+ update to detect concurrent modification
+ required:
+ - name
+ - catalogName
+
+ Shares:
+ type: object
+ properties:
+ nextPageToken:
+ type: string
+ description:
+ Present when more results exist. Absent on the last page
+ shares:
+ type: array
+ items:
+ $ref: "#/components/schemas/Share"
+
+ CreateShareRequest:
+ type: object
+ properties:
+ share:
+ $ref: "#/components/schemas/Share"
+ required:
+ - share
+
+ UpdateShareRequest:
+ description:
+ Updates to apply to a share's description or properties. Every field is
+ optional and an absent field changes nothing. The fields present are applied
+ together, under the version check when currentEntityVersion is given
+ type: object
+ properties:
+ currentEntityVersion:
+ type: integer
+ description:
+ The version of the object onto which this update is applied. If the object
+ changed, the update will fail and the caller should retry after fetching the
+ latest version
+ description:
+ type: string
+ description:
+ The new description. An empty string clears the description. An absent
+ field leaves it unchanged
+ properties:
+ type: object
+ additionalProperties:
+ type: string
+ description:
+ Properties to set, merged into the share's properties by key. Other keys are kept. An absent
+ or empty map sets nothing. Keys with the reserved "share." prefix are rejected
+ (400)
+ removeProperties:
+ type: array
+ items:
+ type: string
+ description:
+ Keys to remove from the share's properties. A key that is not set is ignored. A key both set
+ in properties and listed here is rejected (400), as is a key with the reserved
+ "share." prefix
+
+ ShareMember:
+ description:
+ A member of a share. Consumers see the member under its canonical identity in the share's
+ catalog. A member is pinned to the object's stable ID when it is added, so a renamed
+ object stays a member under its new name, and a new object that reuses an old name is
+ not a member. Aliasing (exposing a member under another identity) is not supported in
+ this version.
+ type: object
+ properties:
+ type:
+ type: string
+ description:
+ The member type. TABLE is the only type defined. The set is open, and a service rejects
+ types it does not support
+ canonical:
+ $ref: "#/components/schemas/MemberIdentity"
+ required:
+ - type
+ - canonical
+
+ MemberIdentity:
+ description:
+ The identity of a member object, as a namespace and a name inside the share's
+ bound catalog. The catalog is the share's and is not repeated here. It is the
+ identifier a consumer's Iceberg REST client uses for the member
+ type: object
+ properties:
+ namespace:
+ type: array
+ items:
+ type: string
+ name:
+ type: string
+ required:
+ - namespace
+ - name
+
+ ShareMembers:
+ type: object
+ properties:
+ nextPageToken:
+ type: string
+ description:
+ Present when more results exist. Absent on the last page
+ members:
+ type: array
+ items:
+ $ref: "#/components/schemas/ShareMember"
+
+ UpdateShareMembersRequest:
+ description: A list of membership updates, applied atomically. Each member may appear at most once
+ type: object
+ properties:
+ currentEntityVersion:
+ type: integer
+ description:
+ The share version this batch applies to. If the share has changed, the request returns 409.
+ Fetch the latest version and retry. Optional. Without it, the service applies the
+ batch against the version it reads, and a concurrent change still returns 409
+ updates:
+ type: array
+ items:
+ $ref: "#/components/schemas/ShareMemberUpdate"
+ required:
+ - updates
+
+ ShareMemberUpdate:
+ type: object
+ properties:
+ action:
+ type: string
+ enum:
+ - ADD
+ - REMOVE
+ member:
+ $ref: "#/components/schemas/ShareMember"
+ required:
+ - action
+ - member