This is an automated email from the ASF dual-hosted git repository.
lzljs3620320 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git
The following commit(s) were added to refs/heads/master by this push:
new 96bcfda253 [core] Update drop Database API and remove api in URL
(#4691)
96bcfda253 is described below
commit 96bcfda2531dca1270d02bc81a98636f71b8a72c
Author: lining <[email protected]>
AuthorDate: Thu Dec 12 17:02:19 2024 +0800
[core] Update drop Database API and remove api in URL (#4691)
---
.../java/org/apache/paimon/rest/HttpClient.java | 38 +++-------
.../java/org/apache/paimon/rest/RESTCatalog.java | 14 ++--
.../java/org/apache/paimon/rest/RESTClient.java | 2 +-
.../java/org/apache/paimon/rest/ResourcePaths.java | 6 +-
.../paimon/rest/requests/DropDatabaseRequest.java | 56 ---------------
.../org/apache/paimon/rest/HttpClientTest.java | 5 +-
.../org/apache/paimon/rest/MockRESTMessage.java | 12 ++--
.../org/apache/paimon/rest/RESTCatalogTest.java | 81 +++++++++++++++++++---
.../apache/paimon/rest/RESTObjectMapperTest.java | 10 ---
paimon-open-api/rest-catalog-open-api.yaml | 60 +++++++---------
.../paimon/open/api/RESTCatalogController.java | 40 ++++-------
.../paimon/open/api/config/OpenAPIConfig.java | 36 ++++++++++
.../src/main/resources/application.properties | 4 ++
13 files changed, 180 insertions(+), 184 deletions(-)
diff --git a/paimon-core/src/main/java/org/apache/paimon/rest/HttpClient.java
b/paimon-core/src/main/java/org/apache/paimon/rest/HttpClient.java
index 97696aef09..87f3fad9b2 100644
--- a/paimon-core/src/main/java/org/apache/paimon/rest/HttpClient.java
+++ b/paimon-core/src/main/java/org/apache/paimon/rest/HttpClient.java
@@ -65,17 +65,9 @@ public class HttpClient implements RESTClient {
@Override
public <T extends RESTResponse> T get(
String path, Class<T> responseType, Map<String, String> headers) {
- try {
- Request request =
- new Request.Builder()
- .url(uri + path)
- .get()
- .headers(Headers.of(headers))
- .build();
- return exec(request, responseType);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ Request request =
+ new Request.Builder().url(uri +
path).get().headers(Headers.of(headers)).build();
+ return exec(request, responseType);
}
@Override
@@ -90,26 +82,16 @@ public class HttpClient implements RESTClient {
.headers(Headers.of(headers))
.build();
return exec(request, responseType);
- } catch (Exception e) {
- throw new RuntimeException(e);
+ } catch (JsonProcessingException e) {
+ throw new RESTException(e, "build request failed.");
}
}
@Override
- public <T extends RESTResponse> T delete(
- String path, RESTRequest body, Map<String, String> headers) {
- try {
- RequestBody requestBody = buildRequestBody(body);
- Request request =
- new Request.Builder()
- .url(uri + path)
- .delete(requestBody)
- .headers(Headers.of(headers))
- .build();
- return exec(request, null);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ public <T extends RESTResponse> T delete(String path, Map<String, String>
headers) {
+ Request request =
+ new Request.Builder().url(uri +
path).delete().headers(Headers.of(headers)).build();
+ return exec(request, null);
}
@Override
@@ -135,6 +117,8 @@ public class HttpClient implements RESTClient {
} else {
throw new RESTException("response body is null.");
}
+ } catch (RESTException e) {
+ throw e;
} catch (Exception e) {
throw new RESTException(e, "rest exception");
}
diff --git a/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java
b/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java
index 3c2538df0c..03b257efbf 100644
--- a/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java
+++ b/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java
@@ -32,7 +32,6 @@ import org.apache.paimon.rest.auth.CredentialsProviderFactory;
import org.apache.paimon.rest.exceptions.AlreadyExistsException;
import org.apache.paimon.rest.exceptions.NoSuchResourceException;
import org.apache.paimon.rest.requests.CreateDatabaseRequest;
-import org.apache.paimon.rest.requests.DropDatabaseRequest;
import org.apache.paimon.rest.responses.ConfigResponse;
import org.apache.paimon.rest.responses.CreateDatabaseResponse;
import org.apache.paimon.rest.responses.DatabaseName;
@@ -47,6 +46,7 @@ import
org.apache.paimon.shade.guava30.com.google.common.collect.ImmutableList;
import
org.apache.paimon.shade.jackson2.com.fasterxml.jackson.databind.ObjectMapper;
import java.time.Duration;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -160,11 +160,15 @@ public class RESTCatalog implements Catalog {
@Override
public void dropDatabase(String name, boolean ignoreIfNotExists, boolean
cascade)
throws DatabaseNotExistException, DatabaseNotEmptyException {
- DropDatabaseRequest request = new
DropDatabaseRequest(ignoreIfNotExists, cascade);
try {
- client.delete(resourcePaths.database(name), request, headers());
+ if (!cascade && !this.listTables(name).isEmpty()) {
+ throw new DatabaseNotEmptyException(name);
+ }
+ client.delete(resourcePaths.database(name), headers());
} catch (NoSuchResourceException e) {
- throw new DatabaseNotExistException(name);
+ if (!ignoreIfNotExists) {
+ throw new DatabaseNotExistException(name);
+ }
}
}
@@ -180,7 +184,7 @@ public class RESTCatalog implements Catalog {
@Override
public List<String> listTables(String databaseName) throws
DatabaseNotExistException {
- throw new UnsupportedOperationException();
+ return new ArrayList<String>();
}
@Override
diff --git a/paimon-core/src/main/java/org/apache/paimon/rest/RESTClient.java
b/paimon-core/src/main/java/org/apache/paimon/rest/RESTClient.java
index d0244f309e..a255d688bc 100644
--- a/paimon-core/src/main/java/org/apache/paimon/rest/RESTClient.java
+++ b/paimon-core/src/main/java/org/apache/paimon/rest/RESTClient.java
@@ -29,5 +29,5 @@ public interface RESTClient extends Closeable {
<T extends RESTResponse> T post(
String path, RESTRequest body, Class<T> responseType, Map<String,
String> headers);
- <T extends RESTResponse> T delete(String path, RESTRequest body,
Map<String, String> headers);
+ <T extends RESTResponse> T delete(String path, Map<String, String>
headers);
}
diff --git
a/paimon-core/src/main/java/org/apache/paimon/rest/ResourcePaths.java
b/paimon-core/src/main/java/org/apache/paimon/rest/ResourcePaths.java
index a6d0000a22..b58053374d 100644
--- a/paimon-core/src/main/java/org/apache/paimon/rest/ResourcePaths.java
+++ b/paimon-core/src/main/java/org/apache/paimon/rest/ResourcePaths.java
@@ -23,7 +23,7 @@ import java.util.StringJoiner;
/** Resource paths for REST catalog. */
public class ResourcePaths {
- public static final String V1_CONFIG = "/api/v1/config";
+ public static final String V1_CONFIG = "/v1/config";
private static final StringJoiner SLASH = new StringJoiner("/");
public static ResourcePaths forCatalogProperties(String prefix) {
@@ -37,10 +37,10 @@ public class ResourcePaths {
}
public String databases() {
- return
SLASH.add("api").add("v1").add(prefix).add("databases").toString();
+ return SLASH.add("v1").add(prefix).add("databases").toString();
}
public String database(String databaseName) {
- return
SLASH.add("api").add("v1").add(prefix).add("databases").add(databaseName).toString();
+ return
SLASH.add("v1").add(prefix).add("databases").add(databaseName).toString();
}
}
diff --git
a/paimon-core/src/main/java/org/apache/paimon/rest/requests/DropDatabaseRequest.java
b/paimon-core/src/main/java/org/apache/paimon/rest/requests/DropDatabaseRequest.java
deleted file mode 100644
index d97f211c1c..0000000000
---
a/paimon-core/src/main/java/org/apache/paimon/rest/requests/DropDatabaseRequest.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.
- */
-
-package org.apache.paimon.rest.requests;
-
-import org.apache.paimon.rest.RESTRequest;
-
-import
org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonCreator;
-import
org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonGetter;
-import
org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonProperty;
-
-/** Request for DropDatabase. */
-public class DropDatabaseRequest implements RESTRequest {
-
- private static final String FIELD_IGNORE_IF_EXISTS = "ignoreIfExists";
- private static final String FIELD_CASCADE = "cascade";
-
- @JsonProperty(FIELD_IGNORE_IF_EXISTS)
- private final boolean ignoreIfNotExists;
-
- @JsonProperty(FIELD_CASCADE)
- private final boolean cascade;
-
- @JsonCreator
- public DropDatabaseRequest(
- @JsonProperty(FIELD_IGNORE_IF_EXISTS) boolean ignoreIfNotExists,
- @JsonProperty(FIELD_CASCADE) boolean cascade) {
- this.ignoreIfNotExists = ignoreIfNotExists;
- this.cascade = cascade;
- }
-
- @JsonGetter(FIELD_IGNORE_IF_EXISTS)
- public boolean getIgnoreIfNotExists() {
- return ignoreIfNotExists;
- }
-
- @JsonGetter(FIELD_CASCADE)
- public boolean getCascade() {
- return cascade;
- }
-}
diff --git
a/paimon-core/src/test/java/org/apache/paimon/rest/HttpClientTest.java
b/paimon-core/src/test/java/org/apache/paimon/rest/HttpClientTest.java
index f12af12a9d..a3b06b8ce3 100644
--- a/paimon-core/src/test/java/org/apache/paimon/rest/HttpClientTest.java
+++ b/paimon-core/src/test/java/org/apache/paimon/rest/HttpClientTest.java
@@ -43,6 +43,7 @@ import static org.mockito.Mockito.verify;
/** Test for {@link HttpClient}. */
public class HttpClientTest {
+
private MockWebServer mockWebServer;
private HttpClient httpClient;
private ObjectMapper objectMapper = RESTObjectMapper.create();
@@ -113,14 +114,14 @@ public class HttpClientTest {
@Test
public void testDeleteSuccess() {
mockHttpCallWithCode(mockResponseDataStr, 200);
- MockRESTData response = httpClient.delete(MOCK_PATH, mockResponseData,
headers);
+ MockRESTData response = httpClient.delete(MOCK_PATH, headers);
verify(errorHandler, times(0)).accept(any());
}
@Test
public void testDeleteFail() {
mockHttpCallWithCode(mockResponseDataStr, 400);
- httpClient.delete(MOCK_PATH, mockResponseData, headers);
+ httpClient.delete(MOCK_PATH, headers);
verify(errorHandler, times(1)).accept(any());
}
diff --git
a/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTMessage.java
b/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTMessage.java
index f111c41f6a..a605e5e77c 100644
--- a/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTMessage.java
+++ b/paimon-core/src/test/java/org/apache/paimon/rest/MockRESTMessage.java
@@ -19,9 +19,9 @@
package org.apache.paimon.rest;
import org.apache.paimon.rest.requests.CreateDatabaseRequest;
-import org.apache.paimon.rest.requests.DropDatabaseRequest;
import org.apache.paimon.rest.responses.CreateDatabaseResponse;
import org.apache.paimon.rest.responses.DatabaseName;
+import org.apache.paimon.rest.responses.ErrorResponse;
import org.apache.paimon.rest.responses.GetDatabaseResponse;
import org.apache.paimon.rest.responses.ListDatabasesResponse;
@@ -46,12 +46,6 @@ public class MockRESTMessage {
return new CreateDatabaseRequest(name, ignoreIfExists, options);
}
- public static DropDatabaseRequest dropDatabaseRequest() {
- boolean ignoreIfNotExists = true;
- boolean cascade = true;
- return new DropDatabaseRequest(ignoreIfNotExists, cascade);
- }
-
public static CreateDatabaseResponse createDatabaseResponse(String name) {
Map<String, String> options = new HashMap<>();
options.put("a", "b");
@@ -71,4 +65,8 @@ public class MockRESTMessage {
databaseNameList.add(databaseName);
return new ListDatabasesResponse(databaseNameList);
}
+
+ public static ErrorResponse noSuchResourceExceptionErrorResponse() {
+ return new ErrorResponse("message", 404, new ArrayList<>());
+ }
}
diff --git
a/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java
b/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java
index cffac60466..0fff81afdc 100644
--- a/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java
+++ b/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java
@@ -18,10 +18,12 @@
package org.apache.paimon.rest;
+import org.apache.paimon.catalog.Catalog;
import org.apache.paimon.catalog.Database;
import org.apache.paimon.options.CatalogOptions;
import org.apache.paimon.options.Options;
import org.apache.paimon.rest.responses.CreateDatabaseResponse;
+import org.apache.paimon.rest.responses.ErrorResponse;
import org.apache.paimon.rest.responses.GetDatabaseResponse;
import org.apache.paimon.rest.responses.ListDatabasesResponse;
@@ -35,6 +37,7 @@ import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -42,13 +45,19 @@ import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
/** Test for REST Catalog. */
public class RESTCatalogTest {
- private ObjectMapper mapper = RESTObjectMapper.create();
+ private final ObjectMapper mapper = RESTObjectMapper.create();
private MockWebServer mockWebServer;
private RESTCatalog restCatalog;
+ private RESTCatalog mockRestCatalog;
@Before
public void setUp() throws IOException {
@@ -64,8 +73,9 @@ public class RESTCatalogTest {
String.format(
"{\"defaults\": {\"%s\": \"%s\"}}",
RESTCatalogInternalOptions.PREFIX.key(), "prefix");
- mockResponse(mockResponse);
+ mockResponse(mockResponse, 200);
restCatalog = new RESTCatalog(options);
+ mockRestCatalog = spy(restCatalog);
}
@After
@@ -85,7 +95,7 @@ public class RESTCatalogTest {
String key = "a";
String value = "b";
String mockResponse = String.format("{\"defaults\": {\"%s\":
\"%s\"}}", key, value);
- mockResponse(mockResponse);
+ mockResponse(mockResponse, 200);
Map<String, String> header = new HashMap<>();
Map<String, String> response =
restCatalog.fetchOptionsFromServer(header, new HashMap<>());
assertEquals(value, response.get(key));
@@ -95,7 +105,7 @@ public class RESTCatalogTest {
public void testListDatabases() throws JsonProcessingException {
String name = MockRESTMessage.databaseName();
ListDatabasesResponse response =
MockRESTMessage.listDatabasesResponse(name);
- mockResponse(mapper.writeValueAsString(response));
+ mockResponse(mapper.writeValueAsString(response), 200);
List<String> result = restCatalog.listDatabases();
assertEquals(response.getDatabases().size(), result.size());
assertEquals(name, result.get(0));
@@ -105,7 +115,7 @@ public class RESTCatalogTest {
public void testCreateDatabase() throws Exception {
String name = MockRESTMessage.databaseName();
CreateDatabaseResponse response =
MockRESTMessage.createDatabaseResponse(name);
- mockResponse(mapper.writeValueAsString(response));
+ mockResponse(mapper.writeValueAsString(response), 200);
assertDoesNotThrow(() -> restCatalog.createDatabase(name, false,
response.getOptions()));
}
@@ -113,7 +123,7 @@ public class RESTCatalogTest {
public void testGetDatabase() throws Exception {
String name = MockRESTMessage.databaseName();
GetDatabaseResponse response =
MockRESTMessage.getDatabaseResponse(name);
- mockResponse(mapper.writeValueAsString(response));
+ mockResponse(mapper.writeValueAsString(response), 200);
Database result = restCatalog.getDatabase(name);
assertEquals(name, result.name());
assertEquals(response.getOptions().size(), result.options().size());
@@ -121,15 +131,64 @@ public class RESTCatalogTest {
}
@Test
- public void testDropDatabase() {
- String name = "name";
- mockResponse("");
- assertDoesNotThrow(() -> restCatalog.dropDatabase(name, false, false));
+ public void testDropDatabase() throws Exception {
+ String name = MockRESTMessage.databaseName();
+ mockResponse("", 200);
+ assertDoesNotThrow(() -> mockRestCatalog.dropDatabase(name, false,
true));
+ verify(mockRestCatalog, times(1)).dropDatabase(eq(name), eq(false),
eq(true));
+ verify(mockRestCatalog, times(0)).listTables(eq(name));
+ }
+
+ @Test
+ public void testDropDatabaseWhenNoExistAndIgnoreIfNotExistsIsFalse()
throws Exception {
+ String name = MockRESTMessage.databaseName();
+ ErrorResponse response =
MockRESTMessage.noSuchResourceExceptionErrorResponse();
+ mockResponse(mapper.writeValueAsString(response), 404);
+ assertThrows(
+ Catalog.DatabaseNotExistException.class,
+ () -> mockRestCatalog.dropDatabase(name, false, true));
+ }
+
+ @Test
+ public void testDropDatabaseWhenNoExistAndIgnoreIfNotExistsIsTrue() throws
Exception {
+ String name = MockRESTMessage.databaseName();
+ ErrorResponse response =
MockRESTMessage.noSuchResourceExceptionErrorResponse();
+ mockResponse(mapper.writeValueAsString(response), 404);
+ assertDoesNotThrow(() -> mockRestCatalog.dropDatabase(name, true,
true));
+ verify(mockRestCatalog, times(1)).dropDatabase(eq(name), eq(true),
eq(true));
+ verify(mockRestCatalog, times(0)).listTables(eq(name));
+ }
+
+ @Test
+ public void testDropDatabaseWhenCascadeIsFalseAndNoTables() throws
Exception {
+ String name = MockRESTMessage.databaseName();
+ boolean cascade = false;
+ mockResponse("", 200);
+ when(mockRestCatalog.listTables(name)).thenReturn(new ArrayList<>());
+ assertDoesNotThrow(() -> mockRestCatalog.dropDatabase(name, false,
cascade));
+ verify(mockRestCatalog, times(1)).dropDatabase(eq(name), eq(false),
eq(cascade));
+ verify(mockRestCatalog, times(1)).listTables(eq(name));
+ }
+
+ @Test
+ public void testDropDatabaseWhenCascadeIsFalseAndTablesExist() throws
Exception {
+ String name = MockRESTMessage.databaseName();
+ boolean cascade = false;
+ mockResponse("", 200);
+ List<String> tables = new ArrayList<>();
+ tables.add("t1");
+ when(mockRestCatalog.listTables(name)).thenReturn(tables);
+ assertThrows(
+ Catalog.DatabaseNotEmptyException.class,
+ () -> mockRestCatalog.dropDatabase(name, false, cascade));
+ verify(mockRestCatalog, times(1)).dropDatabase(eq(name), eq(false),
eq(cascade));
+ verify(mockRestCatalog, times(1)).listTables(eq(name));
}
- private void mockResponse(String mockResponse) {
+ private void mockResponse(String mockResponse, int httpCode) {
MockResponse mockResponseObj =
new MockResponse()
+ .setResponseCode(httpCode)
.setBody(mockResponse)
.addHeader("Content-Type", "application/json");
mockWebServer.enqueue(mockResponseObj);
diff --git
a/paimon-core/src/test/java/org/apache/paimon/rest/RESTObjectMapperTest.java
b/paimon-core/src/test/java/org/apache/paimon/rest/RESTObjectMapperTest.java
index 622a989936..7fee81ef10 100644
--- a/paimon-core/src/test/java/org/apache/paimon/rest/RESTObjectMapperTest.java
+++ b/paimon-core/src/test/java/org/apache/paimon/rest/RESTObjectMapperTest.java
@@ -19,7 +19,6 @@
package org.apache.paimon.rest;
import org.apache.paimon.rest.requests.CreateDatabaseRequest;
-import org.apache.paimon.rest.requests.DropDatabaseRequest;
import org.apache.paimon.rest.responses.ConfigResponse;
import org.apache.paimon.rest.responses.CreateDatabaseResponse;
import org.apache.paimon.rest.responses.ErrorResponse;
@@ -73,15 +72,6 @@ public class RESTObjectMapperTest {
assertEquals(request.getOptions().size(),
parseData.getOptions().size());
}
- @Test
- public void dropDatabaseRequestParseTest() throws Exception {
- DropDatabaseRequest request = MockRESTMessage.dropDatabaseRequest();
- String requestStr = mapper.writeValueAsString(request);
- DropDatabaseRequest parseData = mapper.readValue(requestStr,
DropDatabaseRequest.class);
- assertEquals(request.getIgnoreIfNotExists(),
parseData.getIgnoreIfNotExists());
- assertEquals(request.getCascade(), parseData.getCascade());
- }
-
@Test
public void createDatabaseResponseParseTest() throws Exception {
String name = MockRESTMessage.databaseName();
diff --git a/paimon-open-api/rest-catalog-open-api.yaml
b/paimon-open-api/rest-catalog-open-api.yaml
index 2a5d1dc584..9b69b3de27 100644
--- a/paimon-open-api/rest-catalog-open-api.yaml
+++ b/paimon-open-api/rest-catalog-open-api.yaml
@@ -28,7 +28,7 @@ servers:
- url: http://localhost:8080
description: Server URL in Development environment
paths:
- /api/v1/{prefix}/databases:
+ /v1/{prefix}/databases:
get:
tags:
- database
@@ -66,21 +66,21 @@ paths:
schema:
$ref: '#/components/schemas/CreateDatabaseRequest'
responses:
- "500":
- description: Internal Server Error
- "409":
- description: Resource has exist
- content:
- '*/*':
- schema:
- $ref: '#/components/schemas/ErrorResponse'
"200":
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/CreateDatabaseResponse'
- /api/v1/{prefix}/databases/{database}:
+ "409":
+ description: Resource has exist
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ "500":
+ description: Internal Server Error
+ /v1/{prefix}/databases/{database}:
get:
tags:
- database
@@ -107,7 +107,7 @@ paths:
"404":
description: Resource not found
content:
- '*/*':
+ application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
"500":
@@ -128,35 +128,30 @@ paths:
required: true
schema:
type: string
- requestBody:
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/DropDatabaseRequest'
responses:
"404":
description: Resource not found
content:
- '*/*':
+ application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
"500":
description: Internal Server Error
- /api/v1/config:
+ /v1/config:
get:
tags:
- config
summary: Get Config
operationId: getConfig
responses:
- "500":
- description: Internal Server Error
"200":
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/ConfigResponse'
+ "500":
+ description: Internal Server Error
components:
schemas:
CreateDatabaseRequest:
@@ -170,6 +165,15 @@ components:
type: object
additionalProperties:
type: string
+ CreateDatabaseResponse:
+ type: object
+ properties:
+ name:
+ type: string
+ options:
+ type: object
+ additionalProperties:
+ type: string
ErrorResponse:
type: object
properties:
@@ -182,15 +186,6 @@ components:
type: array
items:
type: string
- CreateDatabaseResponse:
- type: object
- properties:
- name:
- type: string
- options:
- type: object
- additionalProperties:
- type: string
DatabaseName:
type: object
properties:
@@ -223,10 +218,3 @@ components:
type: object
additionalProperties:
type: string
- DropDatabaseRequest:
- type: object
- properties:
- ignoreIfNotExists:
- type: boolean
- cascade:
- type: boolean
diff --git
a/paimon-open-api/src/main/java/org/apache/paimon/open/api/RESTCatalogController.java
b/paimon-open-api/src/main/java/org/apache/paimon/open/api/RESTCatalogController.java
index 364cc5adbb..19f6f8cdf6 100644
---
a/paimon-open-api/src/main/java/org/apache/paimon/open/api/RESTCatalogController.java
+++
b/paimon-open-api/src/main/java/org/apache/paimon/open/api/RESTCatalogController.java
@@ -20,7 +20,6 @@ package org.apache.paimon.open.api;
import org.apache.paimon.rest.ResourcePaths;
import org.apache.paimon.rest.requests.CreateDatabaseRequest;
-import org.apache.paimon.rest.requests.DropDatabaseRequest;
import org.apache.paimon.rest.responses.ConfigResponse;
import org.apache.paimon.rest.responses.CreateDatabaseResponse;
import org.apache.paimon.rest.responses.DatabaseName;
@@ -57,11 +56,7 @@ public class RESTCatalogController {
@ApiResponses({
@ApiResponse(
responseCode = "200",
- content = {
- @Content(
- schema = @Schema(implementation =
ConfigResponse.class),
- mediaType = "application/json")
- }),
+ content = {@Content(schema = @Schema(implementation =
ConfigResponse.class))}),
@ApiResponse(
responseCode = "500",
content = {@Content(schema = @Schema())})
@@ -80,15 +75,13 @@ public class RESTCatalogController {
@ApiResponse(
responseCode = "200",
content = {
- @Content(
- schema = @Schema(implementation =
ListDatabasesResponse.class),
- mediaType = "application/json")
+ @Content(schema = @Schema(implementation =
ListDatabasesResponse.class))
}),
@ApiResponse(
responseCode = "500",
content = {@Content(schema = @Schema())})
})
- @GetMapping("/api/v1/{prefix}/databases")
+ @GetMapping("/v1/{prefix}/databases")
public ListDatabasesResponse listDatabases(@PathVariable String prefix) {
return new ListDatabasesResponse(ImmutableList.of(new
DatabaseName("account")));
}
@@ -100,19 +93,21 @@ public class RESTCatalogController {
@ApiResponse(
responseCode = "200",
content = {
- @Content(
- schema = @Schema(implementation =
CreateDatabaseResponse.class),
- mediaType = "application/json")
+ @Content(schema = @Schema(implementation =
CreateDatabaseResponse.class))
}),
@ApiResponse(
responseCode = "409",
description = "Resource has exist",
- content = {@Content(schema = @Schema(implementation =
ErrorResponse.class))}),
+ content = {
+ @Content(
+ schema = @Schema(implementation =
ErrorResponse.class),
+ mediaType = "application/json")
+ }),
@ApiResponse(
responseCode = "500",
content = {@Content(schema = @Schema())})
})
- @PostMapping("/api/v1/{prefix}/databases")
+ @PostMapping("/v1/{prefix}/databases")
public CreateDatabaseResponse createDatabases(
@PathVariable String prefix, @RequestBody CreateDatabaseRequest
request) {
Map<String, String> properties = new HashMap<>();
@@ -125,11 +120,7 @@ public class RESTCatalogController {
@ApiResponses({
@ApiResponse(
responseCode = "200",
- content = {
- @Content(
- schema = @Schema(implementation =
GetDatabaseResponse.class),
- mediaType = "application/json")
- }),
+ content = {@Content(schema = @Schema(implementation =
GetDatabaseResponse.class))}),
@ApiResponse(
responseCode = "404",
description = "Resource not found",
@@ -138,7 +129,7 @@ public class RESTCatalogController {
responseCode = "500",
content = {@Content(schema = @Schema())})
})
- @GetMapping("/api/v1/{prefix}/databases/{database}")
+ @GetMapping("/v1/{prefix}/databases/{database}")
public GetDatabaseResponse getDatabases(
@PathVariable String prefix, @PathVariable String database) {
Map<String, String> options = new HashMap<>();
@@ -157,9 +148,6 @@ public class RESTCatalogController {
responseCode = "500",
content = {@Content(schema = @Schema())})
})
- @DeleteMapping("/api/v1/{prefix}/databases/{database}")
- public void dropDatabases(
- @PathVariable String prefix,
- @PathVariable String database,
- @RequestBody DropDatabaseRequest request) {}
+ @DeleteMapping("/v1/{prefix}/databases/{database}")
+ public void dropDatabases(@PathVariable String prefix, @PathVariable
String database) {}
}
diff --git
a/paimon-open-api/src/main/java/org/apache/paimon/open/api/config/OpenAPIConfig.java
b/paimon-open-api/src/main/java/org/apache/paimon/open/api/config/OpenAPIConfig.java
index 0e28cd95f9..71ac066d4a 100644
---
a/paimon-open-api/src/main/java/org/apache/paimon/open/api/config/OpenAPIConfig.java
+++
b/paimon-open-api/src/main/java/org/apache/paimon/open/api/config/OpenAPIConfig.java
@@ -21,17 +21,21 @@ package org.apache.paimon.open.api.config;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
+import io.swagger.v3.oas.models.responses.ApiResponses;
import io.swagger.v3.oas.models.servers.Server;
+import org.springdoc.core.customizers.OpenApiCustomiser;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.List;
/** Config for OpenAPI. */
@Configuration
public class OpenAPIConfig {
+
@Value("${openapi.url}")
private String devUrl;
@@ -56,4 +60,36 @@ public class OpenAPIConfig {
servers.add(server);
return new OpenAPI().info(info).servers(servers);
}
+
+ /** Sort response alphabetically. So the api generate will in same order
everytime. */
+ @Bean
+ public OpenApiCustomiser sortResponseAlphabetically() {
+ return openApi -> {
+ openApi.getPaths()
+ .values()
+ .forEach(
+ path ->
+ path.readOperations()
+ .forEach(
+ operation -> {
+ ApiResponses responses
=
+
operation.getResponses();
+ if (responses != null)
{
+ ApiResponses
sortedResponses =
+ new
ApiResponses();
+ List<String> keys =
+ new
ArrayList<>(
+
responses.keySet());
+
keys.sort(Comparator.naturalOrder());
+
+ for (String key :
keys) {
+
sortedResponses.addApiResponse(
+ key,
responses.get(key));
+ }
+
+
operation.setResponses(sortedResponses);
+ }
+ }));
+ };
+ }
}
diff --git a/paimon-open-api/src/main/resources/application.properties
b/paimon-open-api/src/main/resources/application.properties
index 58a9751611..1e7a987c9d 100644
--- a/paimon-open-api/src/main/resources/application.properties
+++ b/paimon-open-api/src/main/resources/application.properties
@@ -19,4 +19,8 @@ springdoc.api-docs.path=/swagger-api-docs
springdoc.swagger-ui.deepLinking=true
springdoc.swagger-ui.tryItOutEnabled=true
springdoc.swagger-ui.filter=true
+springdoc.swagger-ui.tagsSorter=alpha
+springdoc.swagger-ui.operations-sorter=alpha
+# define response default media type
+springdoc.default-produces-media-type=application/json
openapi.url=http://localhost:8080