I’d like to share an approach for integrating SwaggerUI into Scala projects, using http4s as example.
With webjars available you don’t need to copy its complete code into your project,
you’ll need just a small piece of it along with 2 dependencies to your build.sbt
file -
one with SwaggerUI code, and another - webjar ulitity library:
libraryDependencies ++= {
"org.webjars" % "webjars-locator" % "0.34",
"org.webjars" % "swagger-ui" % "3.17.3"
}
Now we need to customize index.html
- it hardcodes the URL of the specification, that’s not what we want. Copy index.html
from SwaggerUI code into src/main/resources/swagger-ui
folder of your project, then change SwaggerUIBundle
instantiation code to the following:
const ui = SwaggerUIBundle({
configUrl: "config.json", //Customization - replaces hardcoded URL
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
Now you can define HttpService
somewhere in your project and use it the same way you use other HTTP services in your http4s
application:
private val applicationUrl = "http://some.server.com:8080" //should be configurable to match your deploy
private val swaggerUiPath = Path("swagger-ui")
val service = org.http4s.HttpService[IO] {
case request @ GET -> `swaggerUiPath` / "config.json" =>
//Specifies Swagger spec URL
Ok(Json.obj("url" -> Json.fromString(s"$applicationUrl/swagger.yaml")))
//Entry point to Swagger UI
case request @ GET -> `swaggerUiPath` =>
PermanentRedirect(Location(uri("swagger-ui/index.html")))
case request @ GET -> path if path.startsWith(swaggerUiPath) =>
//Serves Swagger UI files
val file = "/" + path.toList.drop(swaggerUiPath.toList.size).mkString("/")
(if(file == "/index.html") {
StaticFile.fromResource("/swagger-ui/index.html", Some(request))
} else {
StaticFile.fromResource(swaggerUiResources + file, Some(request))
}).getOrElseF(NotFound())
}
private val swaggerUiResources = s"/META-INF/resources/webjars/swagger-ui/$swaggerUiVersion"
private lazy val swaggerUiVersion: String = {
Option(new WebJarAssetLocator().getWebJars.get("swagger-ui")).fold {
throw new RuntimeException(s"Could not detect swagger-ui webjar version")
} { version =>
version
}
}
Now you can run your application and open /swagger-ui
in browser - it will redirect you to /swagger-ui/index.html
with swagger spec location <applicationUrl>/swagger.yaml
. If you don’t already have Swagger spec exposed there and you have that spec in static YAML file you might want to add another endpoint:
case request @ GET -> "swagger.yaml" =>
StaticFile.fromResource("/swagger.yaml", Some(request)).getOrElseF(NotFound())