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


Reply via email to