diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/OpenAPIConfig.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/OpenAPIConfig.scala index b9b1988ef..d519ab518 100644 --- a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/OpenAPIConfig.scala +++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/OpenAPIConfig.scala @@ -17,27 +17,12 @@ package org.apache.kyuubi.server.api -import io.swagger.v3.jaxrs2.integration.resources.OpenApiResource -import io.swagger.v3.oas.annotations.OpenAPIDefinition -import io.swagger.v3.oas.annotations.info.{Contact, Info, License} -import io.swagger.v3.oas.annotations.tags.Tag import org.glassfish.jersey.server.ResourceConfig -@OpenAPIDefinition( - info = new Info( - title = "Apache Kyuubi REST API Documentation", - version = "1.4.0", - description = "Apache Kyuubi REST API Documentation", - contact = new Contact( - name = "Apache Kyuubi Community", - url = "https://kyuubi.apache.org/issue_tracking.html", - email = "dev@kyuubi.apache.org"), - license = new License( - name = "Apache 2.0", - url = "https://www.apache.org/licenses/LICENSE-2.0.html")), - tags = Array(new Tag(name = "Session"))) +import org.apache.kyuubi.server.api.v1.KyuubiOpenApiResource + class OpenAPIConfig extends ResourceConfig { packages("org.apache.kyuubi.server.api.v1") - register(classOf[OpenApiResource]); + register(classOf[KyuubiOpenApiResource]) register(classOf[KyuubiScalaObjectMapper]) } diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/KyuubiOpenApiResource.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/KyuubiOpenApiResource.scala new file mode 100644 index 000000000..d3e191596 --- /dev/null +++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/KyuubiOpenApiResource.scala @@ -0,0 +1,100 @@ +/* + * 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.kyuubi.server.api.v1 + +import javax.servlet.ServletConfig +import javax.ws.rs.{GET, Path, PathParam, Produces} +import javax.ws.rs.core.{Application, Context, HttpHeaders, MediaType, Response, UriInfo} + +import scala.collection.JavaConverters._ + +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter +import io.swagger.v3.jaxrs2.integration.JaxrsOpenApiContextBuilder +import io.swagger.v3.jaxrs2.integration.resources.BaseOpenApiResource +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.integration.api.OpenApiContext +import io.swagger.v3.oas.models.OpenAPI +import io.swagger.v3.oas.models.info.{Contact, Info, License} +import io.swagger.v3.oas.models.tags.Tag +import org.apache.commons.lang3.StringUtils + +@Path("/openapi.{type:json|yaml}") +class KyuubiOpenApiResource extends BaseOpenApiResource { + @Context + protected var config: ServletConfig = _ + + @Context + protected var app: Application = _ + + @GET + @Produces(Array(MediaType.APPLICATION_JSON, "application/yaml")) + @Operation(hidden = true) + def getOpenApi( + @Context headers: HttpHeaders, + @Context uriInfo: UriInfo, + @PathParam("type") tpe: String): Response = { + + val ctxId = getContextId(config) + val ctx: OpenApiContext = new KyuubiJaxrsOpenApiContextBuilder() + .servletConfig(config) + .application(app) + .resourcePackages(resourcePackages) + .configLocation(configLocation) + .openApiConfiguration(openApiConfiguration) + .ctxId(ctxId) + .buildContext(true) + + val openApi = setKyuubiOpenAPIDefinition(ctx.read()) + + if (StringUtils.isNotBlank(tpe) && tpe.trim().equalsIgnoreCase("yaml")) { + Response.status(Response.Status.OK) + .entity( + ctx.getOutputYamlMapper() + .writer(new DefaultPrettyPrinter()) + .writeValueAsString(openApi)) + .`type`("application/yaml") + .build() + } else { + Response.status(Response.Status.OK) + .entity( + ctx.getOutputJsonMapper + .writer(new DefaultPrettyPrinter()) + .writeValueAsString(openApi)) + .`type`(MediaType.APPLICATION_JSON_TYPE) + .build() + } + } + + private def setKyuubiOpenAPIDefinition(openApi: OpenAPI): OpenAPI = { + openApi.info( + new Info().title("Apache Kyuubi (Incubating) REST API Documentation") + .version(org.apache.kyuubi.KYUUBI_VERSION) + .description("Apache Kyuubi (Incubating) REST API Documentation") + .contact( + new Contact().name("Apache Kyuubi Community") + .url("https://kyuubi.apache.org/issue_tracking.html") + .email("dev@kyuubi.apache.org")) + .license( + new License().name("Apache License 2.0") + .url("https://www.apache.org/licenses/LICENSE-2.0.txt"))) + .tags(List(new Tag().name("Session"), new Tag().name("Operation")).asJava) + } +} + +class KyuubiJaxrsOpenApiContextBuilder + extends JaxrsOpenApiContextBuilder[KyuubiJaxrsOpenApiContextBuilder]