Как раскрыть пользовательский интерфейс чванства с помощью http4k?
Я создаю микросервис с фреймворком http4k, используя их API контрактов. Я могу легко раскрыть описание API чванства в формате JSON, например./swagger.json
с
fun app(): HttpHandler = "/" bind contract {
renderer = OpenApi3(ApiInfo("GoOut Locations API", "1.0"), Jackson)
descriptionPath = "/swagger.json"
routes += ...
}
Есть ли простой способ раскрыть пользовательский интерфейс swagger, чтобы 1) я мог указать путь, по которому он будет доступен. (например./swagger-ui
) 2) Пользовательский интерфейс будет предварительно настроен для получения описания JSON из descriptionPath
указанное выше.
Идеальный API будет выглядеть примерно так
fun app(): HttpHandler = "/" bind contract {
renderer = OpenApi3(ApiInfo("GoOut Locations API", "1.0"), Jackson)
descriptionPath = "/swagger.json"
uiPath = "/swagger-ui"
routes += ...
}
4 ответа
После небольшого поиска я добился этого с помощью комбинации Web Jars и статической маршрутизации http4k.
Потенциальный зритель документов должен просто посетить /docs
путь, по которому его перенаправляют /docs/index.html?url=<path to Api description>
где
index.html
- статическая точка входа пользовательского интерфейса Swagger, обслуживаемая из веб-файла.url
Параметр запроса сообщает пользовательскому интерфейсу Swagger, откуда брать описание OpenApi.
С точки зрения DX у нас есть простое приложение http4k:
// path the OpenApi description will be exposed on
private const val API_DESCRIPTION_PATH = "/swagger.json"
fun app(): HttpHandler {
val api = contract {
renderer = OpenApi3(ApiInfo("Your API summary", "1.0"), Jackson)
descriptionPath = API_DESCRIPTION_PATH
// the actual API routes
routes += ...
}
return routes(
// the docs routes are not considered part of the API so we define them outside of the contract
swaggerUi(API_DESCRIPTION_PATH),
api
)
}
В swaggerUi
реализация обработчика следует
/**
* Exposes Swagger UI with /docs path as its entry point.
* @param descriptionPath absolute path to API description JSON. The UI will be configured to fetch it after load.
*/
fun swaggerUi(descriptionPath: String): RoutingHttpHandler = routes(
"docs" bind Method.GET to {
Response(Status.FOUND).header("Location", "/docs/index.html?url=$descriptionPath")
},
// For some reason the static handler does not work without "/" path prefix.
"/docs" bind static(Classpath("META-INF/resources/webjars/swagger-ui/3.25.2"))
)
Мы также должны включить webjar swagger-ui в качестве нашей зависимости. Вот директива Gradle:
implementation 'org.webjars:swagger-ui:3.25.2'
См. Веб-сайт webjars для получения информации о директивах Maven (и других).
Обратите внимание, что swaggerUi
обработчик предполагает, что он привязан к /
корневой путь всего сервиса. Однако это легко исправить.
Решение с использованием webjar больше не работает для версии SwaggerUI >= 4.1.3, так как параметр игнорируется (см. эту проблему / примечания к выпуску ). URL-адрес должен быть указан либо в HTML, либо в
url
параметр должен быть включен в HTML. Так что на данный момент решение, похоже, состоит в том, чтобы распаковать пользовательский интерфейс, обновить
index.html
и обслуживать напрямую, а не через webjar.
Начиная с http4k 4.28.1.0, теперь есть способ сделать это. См. следующий код, взятый с этой страницы документации :
package guide.howto.create_a_swagger_ui
import org.http4k.contract.contract
import org.http4k.contract.meta
import org.http4k.contract.openapi.ApiInfo
import org.http4k.contract.openapi.v3.OpenApi3
import org.http4k.contract.ui.swaggerUi
import org.http4k.core.Body
import org.http4k.core.ContentType
import org.http4k.core.Method.GET
import org.http4k.core.Request
import org.http4k.core.Response
import org.http4k.core.Status.Companion.OK
import org.http4k.core.Uri
import org.http4k.core.with
import org.http4k.lens.string
import org.http4k.routing.routes
import org.http4k.server.SunHttp
import org.http4k.server.asServer
fun main() {
val greetingLens = Body.string(ContentType.TEXT_PLAIN).toLens()
// Define a single http route for our contract
val helloHandler = "/v1/hello" meta {
operationId = "v1Hello"
summary = "Say Hello"
returning(OK, greetingLens to "Sample Greeting")
} bindContract GET to { _: Request ->
Response(OK).with(greetingLens of "HI!")
}
// Define a contract, and render an OpenApi 3 spec at "/spec"
val v1Api = contract {
routes += helloHandler
renderer = OpenApi3(
ApiInfo("Hello Server - Developer UI", "99.3.4")
)
descriptionPath = "spec"
}
// Build a Swagger UI based on the OpenApi spec defined at "/spec"
val ui = swaggerUi(
Uri.of("spec"),
title = "Hello Server",
displayOperationId = true
)
// Combine our api, spec, and ui; then start a server
// The Swagger UI is available on the root "/" path
routes(v1Api, ui)
.asServer(SunHttp(8080))
.start()
.block()
}
Http 4k не поставляется с версией пользовательского интерфейса OpenApi. Вы можете легко отправить версию пользовательского интерфейса:
- распаковка пользовательского интерфейса OpenApi в папку src / main / resources / public
- Используя
static
блокировка маршрутизации на сервер ресурсов. Вот пример этого: https://github.com/http4k/http4k-by-example/blob/22dcc9a83c497253c29830d5bc981afa5fbbe4ff/src/main/kotlin/verysecuresystems/SecuritySystem.kt