Skip to content

Commit 9425a6e

Browse files
authored
Polaris Catalog Spec: Generic Table APIs (#1150)
1 parent 9b5e518 commit 9425a6e

File tree

8 files changed

+614
-5
lines changed

8 files changed

+614
-5
lines changed

api/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ This directory contains the API modules for Apache Polaris.
3131
Polaris Management API.
3232
- [`polaris-api-iceberg-service`](iceberg-service): contains the service classes for the Polaris
3333
Iceberg REST API.
34+
- [`polaris-api-catalog-service`](polaris-catalog-service): contains the service classes for the Polaris
35+
native Catalog REST API.
3436

3537
The classes in these modules are generated from the OpenAPI specification files in the
3638
[`spec`](../spec) directory.

api/iceberg-service/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ openApiGenerate {
5555
ignoreFileOverride = "$rootDir/.openapi-generator-ignore"
5656
removeOperationIdPrefix = true
5757
templateDir = "$rootDir/server-templates"
58-
globalProperties.put("apis", "")
58+
globalProperties.put("apis", "CatalogApi,ConfigurationApi,OAuth2Api")
5959
globalProperties.put("models", "false")
6060
globalProperties.put("apiDocs", "false")
6161
globalProperties.put("modelTests", "false")
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
plugins {
21+
alias(libs.plugins.openapi.generator)
22+
id("polaris-client")
23+
alias(libs.plugins.jandex)
24+
}
25+
26+
val genericTableModels =
27+
listOf(
28+
"CreateGenericTableRequest",
29+
"LoadGenericTableResponse",
30+
"ListGenericTablesResponse",
31+
"GenericTable",
32+
)
33+
.joinToString(",")
34+
35+
dependencies {
36+
implementation(project(":polaris-core"))
37+
38+
implementation(platform(libs.iceberg.bom))
39+
implementation("org.apache.iceberg:iceberg-api")
40+
implementation("org.apache.iceberg:iceberg-core")
41+
42+
implementation(libs.jakarta.annotation.api)
43+
implementation(libs.jakarta.inject.api)
44+
implementation(libs.jakarta.validation.api)
45+
implementation(libs.swagger.annotations)
46+
47+
implementation(libs.jakarta.servlet.api)
48+
implementation(libs.jakarta.ws.rs.api)
49+
50+
implementation(platform(libs.micrometer.bom))
51+
implementation("io.micrometer:micrometer-core")
52+
53+
implementation(platform(libs.jackson.bom))
54+
implementation("com.fasterxml.jackson.core:jackson-annotations")
55+
implementation("com.fasterxml.jackson.core:jackson-core")
56+
implementation("com.fasterxml.jackson.core:jackson-databind")
57+
}
58+
59+
openApiGenerate {
60+
inputSpec = "$rootDir/spec/polaris-catalog-service.yaml"
61+
generatorName = "jaxrs-resteasy"
62+
outputDir = "$projectDir/build/generated"
63+
apiPackage = "org.apache.polaris.service.catalog.api"
64+
modelPackage = "org.apache.polaris.service.types"
65+
ignoreFileOverride = "$rootDir/.openapi-generator-ignore"
66+
removeOperationIdPrefix = true
67+
templateDir = "$rootDir/server-templates"
68+
globalProperties.put("apis", "GenericTableApi")
69+
globalProperties.put("models", genericTableModels)
70+
globalProperties.put("apiDocs", "false")
71+
globalProperties.put("modelTests", "false")
72+
configOptions.put("resourceName", "catalog")
73+
configOptions.put("useTags", "true")
74+
configOptions.put("useBeanValidation", "false")
75+
configOptions.put("sourceFolder", "src/main/java")
76+
configOptions.put("useJakartaEe", "true")
77+
configOptions.put("generateBuilders", "true")
78+
configOptions.put("generateConstructorWithAllArgs", "true")
79+
configOptions.put("openApiNullable", "false")
80+
openapiNormalizer.put("REFACTOR_ALLOF_WITH_PROPERTIES_ONLY", "true")
81+
additionalProperties.put("apiNamePrefix", "PolarisCatalog")
82+
additionalProperties.put("apiNameSuffix", "")
83+
additionalProperties.put("metricsPrefix", "polaris")
84+
serverVariables.put("basePath", "api/catalog")
85+
importMappings =
86+
mapOf(
87+
"ErrorModel" to "org.apache.iceberg.rest.responses.ErrorResponse",
88+
"IcebergErrorResponse" to "org.apache.iceberg.rest.responses.ErrorResponse",
89+
"TableIdentifier" to "org.apache.iceberg.catalog.TableIdentifier",
90+
)
91+
}
92+
93+
listOf("sourcesJar", "compileJava").forEach { task ->
94+
tasks.named(task) { dependsOn("openApiGenerate") }
95+
}
96+
97+
sourceSets {
98+
main { java { srcDir(project.layout.buildDirectory.dir("generated/src/main/java")) } }
99+
}
100+
101+
tasks.named("javadoc") { dependsOn("jandex") }

gradle/projects.main.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ polaris-core=polaris-core
2222
polaris-api-iceberg-service=api/iceberg-service
2323
polaris-api-management-model=api/management-model
2424
polaris-api-management-service=api/management-service
25+
polaris-api-catalog-service=api/polaris-catalog-service
2526
polaris-service-common=service/common
2627
polaris-quarkus-defaults=quarkus/defaults
2728
polaris-quarkus-service=quarkus/service

spec/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Polaris provides two sets of OpenAPI specifications:
2323
- `polaris-management-service.yml` - Defines the management APIs for using Polaris to create and manage Iceberg catalogs and their principals
2424
- `polaris-catalog-service.yaml` - Defines the specification for the Polaris Catalog API, which encompasses both the Iceberg REST Catalog API
2525
and Polaris-native API.
26-
- `polaris-catalog-apis` - Contains the specifications of Polaris-native API
26+
- `polaris-catalog-apis` - Contains the specification for Polaris-specific Catalog APIs
2727
- `iceberg-rest-catalog-open-api.yaml` - Contains the specification for Iceberg Rest Catalog API
2828

2929
## Generated Specification Files
@@ -45,5 +45,6 @@ npm install @redocly/cli -g
4545
```
4646
redocly bundle spec/polaris-catalog-service.yaml -o spec/generated/bundled-polaris-catalog-service.yaml
4747
```
48+
Note: the license header will be removed after the bundle generation, please manually add it back.
4849

4950

spec/generated/bundled-polaris-catalog-service.yaml

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,6 +1359,147 @@ paths:
13591359
$ref: '#/components/responses/ServiceUnavailableResponse'
13601360
5XX:
13611361
$ref: '#/components/responses/ServerErrorResponse'
1362+
/polaris/v1/{prefix}/namespaces/{namespace}/generic-tables:
1363+
parameters:
1364+
- $ref: '#/components/parameters/prefix'
1365+
- $ref: '#/components/parameters/namespace'
1366+
get:
1367+
tags:
1368+
- Generic Table API
1369+
summary: List all generic tables identifiers underneath a given namespace
1370+
description: Return all generic table identifiers under this namespace
1371+
operationId: listGenericTables
1372+
parameters:
1373+
- $ref: '#/components/parameters/page-token'
1374+
- $ref: '#/components/parameters/page-size'
1375+
responses:
1376+
'200':
1377+
$ref: '#/components/responses/ListGenericTablesResponse'
1378+
'400':
1379+
$ref: '#/components/responses/BadRequestErrorResponse'
1380+
'401':
1381+
$ref: '#/components/responses/UnauthorizedResponse'
1382+
'403':
1383+
$ref: '#/components/responses/ForbiddenResponse'
1384+
'404':
1385+
description: Not Found - The namespace specified does not exist
1386+
content:
1387+
application/json:
1388+
schema:
1389+
$ref: '#/components/schemas/IcebergErrorResponse'
1390+
examples:
1391+
NamespaceNotFound:
1392+
$ref: '#/components/examples/NoSuchNamespaceError'
1393+
'503':
1394+
$ref: '#/components/responses/ServiceUnavailableResponse'
1395+
5XX:
1396+
$ref: '#/components/responses/ServerErrorResponse'
1397+
post:
1398+
tags:
1399+
- Generic Table API
1400+
summary: Create a generic table under the given namespace
1401+
description: Create a generic table under the given namespace, and return the created table information as a response.
1402+
operationId: createGenericTable
1403+
requestBody:
1404+
required: true
1405+
content:
1406+
application/json:
1407+
schema:
1408+
$ref: '#/components/schemas/CreateGenericTableRequest'
1409+
responses:
1410+
'200':
1411+
$ref: '#/components/responses/CreateGenericTableResponse'
1412+
'400':
1413+
$ref: '#/components/responses/BadRequestErrorResponse'
1414+
'401':
1415+
$ref: '#/components/responses/UnauthorizedResponse'
1416+
'403':
1417+
$ref: '#/components/responses/ForbiddenResponse'
1418+
'404':
1419+
description: Not Found - The namespace specified does not exist
1420+
content:
1421+
application/json:
1422+
schema:
1423+
$ref: '#/components/schemas/IcebergErrorResponse'
1424+
examples:
1425+
NamespaceNotFound:
1426+
$ref: '#/components/examples/NoSuchNamespaceError'
1427+
'409':
1428+
description: Conflict - The table already exists under the given namespace
1429+
content:
1430+
application/json:
1431+
schema:
1432+
$ref: '#/components/schemas/IcebergErrorResponse'
1433+
examples:
1434+
TableAlreadyExists:
1435+
$ref: '#/components/examples/TableAlreadyExistsError'
1436+
'503':
1437+
$ref: '#/components/responses/ServiceUnavailableResponse'
1438+
5XX:
1439+
$ref: '#/components/responses/ServerErrorResponse'
1440+
/polaris/v1/{prefix}/namespaces/{namespace}/generic-tables/{generic-table}:
1441+
parameters:
1442+
- $ref: '#/components/parameters/prefix'
1443+
- $ref: '#/components/parameters/namespace'
1444+
- $ref: '#/components/parameters/generic-table'
1445+
get:
1446+
tags:
1447+
- Generic Table API
1448+
summary: Load a generic table under the given namespace from the catalog
1449+
operationId: loadGenericTable
1450+
description: |-
1451+
Load a generic table from the catalog under the given namespace.
1452+
The response contains all table information passed during create.
1453+
responses:
1454+
'200':
1455+
$ref: '#/components/responses/LoadGenericTableResponse'
1456+
'400':
1457+
$ref: '#/components/responses/BadRequestErrorResponse'
1458+
'401':
1459+
$ref: '#/components/responses/UnauthorizedResponse'
1460+
'403':
1461+
$ref: '#/components/responses/ForbiddenResponse'
1462+
'404':
1463+
description: Not Found - NoSuchTableError, generic table to load does not exist
1464+
content:
1465+
application/json:
1466+
schema:
1467+
$ref: '#/components/schemas/IcebergErrorResponse'
1468+
examples:
1469+
TableToLoadDoesNotExist:
1470+
$ref: '#/components/examples/NoSuchTableError'
1471+
'503':
1472+
$ref: '#/components/responses/ServiceUnavailableResponse'
1473+
5XX:
1474+
$ref: '#/components/responses/ServerErrorResponse'
1475+
delete:
1476+
tags:
1477+
- Generic Table API
1478+
summary: Drop a generic table under the given namespace from the catalog
1479+
operationId: dropGenericTable
1480+
description: Remove a table under the given namespace from the catalog
1481+
responses:
1482+
'204':
1483+
description: Success, no content
1484+
'400':
1485+
$ref: '#/components/responses/BadRequestErrorResponse'
1486+
'401':
1487+
$ref: '#/components/responses/UnauthorizedResponse'
1488+
'403':
1489+
$ref: '#/components/responses/ForbiddenResponse'
1490+
'404':
1491+
description: Not Found - NoSuchTableError, Generic table to drop does not exist
1492+
content:
1493+
application/json:
1494+
schema:
1495+
$ref: '#/components/schemas/IcebergErrorResponse'
1496+
examples:
1497+
TableToDeleteDoesNotExist:
1498+
$ref: '#/components/examples/NoSuchTableError'
1499+
'503':
1500+
$ref: '#/components/responses/ServiceUnavailableResponse'
1501+
5XX:
1502+
$ref: '#/components/responses/ServerErrorResponse'
13621503
components:
13631504
securitySchemes:
13641505
OAuth2:
@@ -3257,6 +3398,62 @@ components:
32573398
$ref: '#/components/schemas/NotificationType'
32583399
payload:
32593400
$ref: '#/components/schemas/TableUpdateNotification'
3401+
ListGenericTablesResponse:
3402+
type: object
3403+
properties:
3404+
next-page-token:
3405+
$ref: '#/components/schemas/PageToken'
3406+
identifiers:
3407+
type: array
3408+
uniqueItems: true
3409+
items:
3410+
$ref: '#/components/schemas/TableIdentifier'
3411+
CreateGenericTableRequest:
3412+
type: object
3413+
required:
3414+
- name
3415+
- format
3416+
properties:
3417+
name:
3418+
type: string
3419+
format:
3420+
type: string
3421+
doc:
3422+
type: string
3423+
properties:
3424+
type: object
3425+
additionalProperties:
3426+
type: string
3427+
GenericTable:
3428+
type: object
3429+
description: |
3430+
Generic Table information.
3431+
- `name` name for the generic table
3432+
- `format` format for the generic table, i.e. "delta", "csv"
3433+
- `properties` properties for the generic table passed on creation
3434+
- `doc` comment or description for the generic table
3435+
required:
3436+
- name
3437+
- format
3438+
properties:
3439+
name:
3440+
type: string
3441+
format:
3442+
type: string
3443+
doc:
3444+
type: string
3445+
properties:
3446+
type: object
3447+
additionalProperties:
3448+
type: string
3449+
LoadGenericTableResponse:
3450+
description: Result used when a table is successfully loaded.
3451+
type: object
3452+
required:
3453+
- table
3454+
properties:
3455+
table:
3456+
$ref: '#/components/schemas/GenericTable'
32603457
responses:
32613458
BadRequestErrorResponse:
32623459
description: Indicates a bad request error. It could be caused by an unexpected request body format or other forms of request validation failure, such as invalid json. Usually serves application/json content, although in some cases simple text/plain content might be returned by the server's middleware.
@@ -3436,6 +3633,24 @@ components:
34363633
application/json:
34373634
schema:
34383635
$ref: '#/components/schemas/LoadViewResult'
3636+
ListGenericTablesResponse:
3637+
description: List of generic table identifiers.
3638+
content:
3639+
application/json:
3640+
schema:
3641+
$ref: '#/components/schemas/ListGenericTablesResponse'
3642+
CreateGenericTableResponse:
3643+
description: Table result if successfully created a generic table.
3644+
content:
3645+
application/json:
3646+
schema:
3647+
$ref: '#/components/schemas/LoadGenericTableResponse'
3648+
LoadGenericTableResponse:
3649+
description: Table result if successfully load a generic table.
3650+
content:
3651+
application/json:
3652+
schema:
3653+
$ref: '#/components/schemas/LoadGenericTableResponse'
34393654
parameters:
34403655
prefix:
34413656
name: prefix
@@ -3505,6 +3720,14 @@ components:
35053720
schema:
35063721
type: string
35073722
example: sales
3723+
generic-table:
3724+
name: generic-table
3725+
in: path
3726+
description: A generic table name
3727+
required: true
3728+
schema:
3729+
type: string
3730+
example: sales
35083731
examples:
35093732
ListNamespacesNonEmptyExample:
35103733
summary: A non-empty list of namespaces

0 commit comments

Comments
 (0)