All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pl.iterators.baklava.routes.BaklavaRoutes.scala Maven / Gradle / Ivy

The newest version!
package pl.iterators.baklava.routes

import cats.effect.IO
import org.http4s.headers.Location
import org.http4s.{Headers, Response, Status, Uri}
import pl.iterators.stir.server.Directives._
import org.webjars.WebJarAssetLocator
import pl.iterators.stir.server.Route
import pl.iterators.stir.server.directives.{CredentialsHelper, RouteDirectives}

import scala.io.Source
import scala.util.{Failure, Success, Try}

object BaklavaRoutes {
  def routes(config: com.typesafe.config.Config): Route = {
    implicit val internalConfig: BaklavaRoutes.Config = BaklavaRoutes.Config(config)
    if (internalConfig.enabled)
      authenticateBasic("docs", basicAuthOpt) { _ =>
        pathPrefix("docs") {
          pathSingleSlash {
            getFromFile(s"${internalConfig.fileSystemPath}/simple/index.html")
          } ~ getFromDirectory(s"${internalConfig.fileSystemPath}/simple")
        } ~ path("openapi") {
          complete(openApiFileContent)
        } ~ pathPrefix("swagger-ui") {
          swaggerWebJar
        } ~ pathPrefix("swagger") {
          get(complete(swaggerRedirectHttpResponse))
        }
      }
    else
      RouteDirectives.reject
  }

  private def basicAuthOpt(credentials: CredentialsHelper)(implicit internalConfig: BaklavaRoutes.Config): Option[String] =
    (internalConfig.basicAuthUser, internalConfig.basicAuthPassword) match {
      case (Some(user), Some(password)) =>
        credentials match {
          case p @ CredentialsHelper.Provided(id) if id == user && p.verify(password) => Some(id)
          case _                                                                      => None
        }
      case _ => Some("")
    }

  private def openApiFileContent(implicit internalConfig: BaklavaRoutes.Config): String = {
    val source       = Source.fromFile(s"${internalConfig.fileSystemPath}/openapi/openapi.yml")
    val lines        = source.getLines()
    val firstLine    = lines.next()
    val serverConfig = List("servers:", s"  - url: ${internalConfig.apiPublicPathPrefix}")
    val tailLines    = lines.toList
    val content      = firstLine :: serverConfig ::: tailLines
    source.close()
    content.mkString("\n")
  }

  private def swaggerRedirectHttpResponse(implicit internalConfig: BaklavaRoutes.Config) = {
    val swaggerUiUrl   = s"${internalConfig.publicPathPrefix}swagger-ui/3.40.0/index.html"
    val swaggerDocsUrl = s"${internalConfig.publicPathPrefix}openapi"
    Response[IO](status = Status.SeeOther, headers = Headers(Location(Uri.unsafeFromString(s"$swaggerUiUrl?url=$swaggerDocsUrl&layout=BaseLayout"))))
  }

  private lazy val swaggerWebJar: Route =
    extractUnmatchedPath { path =>
      Try((new WebJarAssetLocator).getFullPath("swagger-ui", path.toString)) match {
        case Success(fullPath) =>
          getFromResource(fullPath)
        case Failure(_: IllegalArgumentException) =>
          reject
        case Failure(e) =>
          failWith(e)
      }
    }

  private case class Config(
    enabled: Boolean,
    basicAuthUser: Option[String],
    basicAuthPassword: Option[String],
    fileSystemPath: String,
    publicPathPrefix: String,
    apiPublicPathPrefix: String)

  private object Config {
    def apply(config: com.typesafe.config.Config): Config = {
      val c = config.getConfig("baklavaRoutes")
      Config(
        enabled = c.getBoolean("enabled"),
        basicAuthUser = Try(c.getString("basicAuthUser")).toOption,
        basicAuthPassword = Try(c.getString("basicAuthPassword")).toOption,
        fileSystemPath = c.getString("fileSystemPath"),
        publicPathPrefix = c.getString("publicPathPrefix"),
        apiPublicPathPrefix = c.getString("apiPublicPathPrefix")
      )
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy