Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding support for http4s-stir library #24

Merged
merged 4 commits into from
Sep 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
scala: [2.12.17, 2.13.10]
scala: [2.13.10]
java: [[email protected]]
runs-on: ${{ matrix.os }}
steps:
Expand Down
97 changes: 68 additions & 29 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import com.jsuereth.sbtpgp.PgpKeys

val scala_2_12 = "2.12.17"
val scala_2_13 = "2.13.10"
val mainScalaVersion = scala_2_13
val supportedScalaVersions = Seq(scala_2_12, scala_2_13)
val supportedScalaVersions = Seq(scala_2_13)

ThisBuild / crossScalaVersions := supportedScalaVersions
ThisBuild / scalaVersion := mainScalaVersion
Expand Down Expand Up @@ -41,28 +40,28 @@ lazy val baseSettings = Seq(
crossScalaVersions := supportedScalaVersions
)

val akkaV = "2.6.19"
val akkaHttpV = "10.2.9"
val typesafeConfigV = "1.4.2"
val kebsV = "1.9.4"
val reflectionsVersion = "0.10.2"
val specs2V = "4.16.1"
val jsonSchemaVersion = "0.7.9"
val swaggerV = "2.1.6"
val scalatestV = "3.2.12"
val webjarsLocatorV = "0.45"
val swaggerUiV = "3.40.0" //unfortunately we need to stuck with this version
val akkaV = "2.6.20"
val akkaHttpV = "10.2.10"
val http4sStirV = "0.2"
val typesafeConfigV = "1.4.2"
val kebsV = "1.9.5"
val reflectionsV = "0.10.2"
val specs2V = "4.16.1"
val jsonSchemaV = "0.7.11"
val swaggerV = "2.1.6"
val scalatestV = "3.2.12"
val webjarsLocatorV = "0.45"
val swaggerUiV = "3.40.0" //unfortunately we need to stuck with this version

lazy val routes = project
.in(file("routes"))
lazy val akkahttproutes = project
.in(file("akka-http-routes"))
.settings(baseSettings: _*)
.settings(
name := "routes",
moduleName := "baklava-routes"
name := "akka-http-routes",
moduleName := "baklava-akka-http-routes"
)
.settings(
libraryDependencies ++= {

Seq(
"com.typesafe.akka" %% "akka-http" % akkaHttpV,
"com.typesafe" % "config" % typesafeConfigV,
Expand All @@ -72,6 +71,25 @@ lazy val routes = project
}
)

lazy val http4sstirroutes = project
.in(file("http4s-stir-routes"))
.settings(baseSettings: _*)
.settings(
name := "http4s-stir-routes",
moduleName := "baklava-http4s-stir-routes"
)
.settings(
libraryDependencies ++= {

Seq(
"pl.iterators" %% "http4s-stir" % http4sStirV,
"com.typesafe" % "config" % typesafeConfigV,
"org.webjars" % "webjars-locator" % webjarsLocatorV,
"org.webjars" % "swagger-ui" % swaggerUiV
)
}
)

lazy val core = project
.in(file("core"))
.settings(baseSettings: _*)
Expand All @@ -85,9 +103,9 @@ lazy val core = project
"pl.iterators" %% "kebs-tagged-meta" % kebsV,
"pl.iterators" %% "kebs-jsonschema" % kebsV,
"pl.iterators" %% "kebs-scalacheck" % kebsV,
"com.github.andyglow" %% "scala-jsonschema" % jsonSchemaVersion,
"com.github.andyglow" %% "scala-jsonschema-enumeratum" % jsonSchemaVersion,
"org.reflections" % "reflections" % reflectionsVersion,
"com.github.andyglow" %% "scala-jsonschema" % jsonSchemaV,
"com.github.andyglow" %% "scala-jsonschema-enumeratum" % jsonSchemaV,
"org.reflections" % "reflections" % reflectionsV,
"org.specs2" %% "specs2-core" % specs2V % "test"
)
}
Expand Down Expand Up @@ -137,13 +155,13 @@ lazy val formatter = project
)

lazy val formatteropenapi = project
.in(file("formatteropenapi"))
.in(file("formatter-openapi"))
.dependsOn(core % "compile->compile;test->test")
.dependsOn(formatter % "compile->compile;test->test")
.settings(baseSettings: _*)
.settings(
name := "formatteropenapi",
moduleName := "baklava-formatteropenapi"
name := "formatter-openapi",
moduleName := "baklava-formatter-openapi"
)
.settings(
libraryDependencies ++= {
Expand All @@ -165,18 +183,18 @@ lazy val generator = project
.settings(
libraryDependencies ++= {
Seq(
"org.reflections" % "reflections" % reflectionsVersion
"org.reflections" % "reflections" % reflectionsV
)
}
)

lazy val akkahttp = project
.in(file("akkahttp"))
.in(file("akka-http"))
.dependsOn(core % "compile->compile;test->test")
.settings(baseSettings: _*)
.settings(
name := "akkahttp",
moduleName := "baklava-akkahttp"
name := "akka-http",
moduleName := "baklava-akka-http"
)
.settings(
libraryDependencies ++= {
Expand All @@ -191,6 +209,25 @@ lazy val akkahttp = project
}
)

lazy val http4sstir = project
.in(file("http4s-stir"))
.dependsOn(core % "compile->compile;test->test")
.settings(baseSettings: _*)
.settings(
name := "http4s-stir",
moduleName := "baklava-http4s-stir"
)
.settings(
libraryDependencies ++= {

Seq(
"pl.iterators" %% "http4s-stir" % http4sStirV,
"pl.iterators" %% "http4s-stir-testkit" % http4sStirV
)
},
crossScalaVersions := Seq(scala_2_13)
)

lazy val scalatest = project
.in(file("scalatest"))
.dependsOn(core % "compile->compile;test->test")
Expand Down Expand Up @@ -252,14 +289,16 @@ lazy val sbtplugin = project
lazy val baklava = project
.in(file("."))
.aggregate(
routes,
core,
circe,
sprayjson,
formatter,
formatteropenapi,
generator,
akkahttp,
akkahttproutes,
http4sstir,
http4sstirroutes,
scalatest,
specs2,
sbtplugin
Expand Down
20 changes: 20 additions & 0 deletions http4s-stir-routes/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
baklavaRoutes {
enabled = "true"
enabled = ${?BAKLAVA_ROUTES_ENABLED}

#Override this to set http basic auth for baklava routes
basicAuthUser = ${?BAKLAVA_ROUTES_BASIC_AUTH_USER}
basicAuthPassword = ${?BAKLAVA_ROUTES_BASIC_AUTH_PASSWORD}

#Filesystem path where output of baklava is stored
fileSystemPath = "./target/baklava"
fileSystemPath = ${?BAKLAVA_ROUTES_FILESYSTEM_PATH}

#HTTP serve prefix of baklava resources
publicPathPrefix = "/"
publicPathPrefix = ${?BAKLAVA_ROUTES_PUBLIC_PATH_PREFIX}

#API prefix
apiPublicPathPrefix = "/v1"
apiPublicPathPrefix = ${?BAKLAVA_ROUTES_API_PUBLIC_PATH_PREFIX}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
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")
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package pl.iterators.baklava.http4sstir

import org.http4s.Method
import pl.iterators.baklava.core.fetchers.RouteBaklavaSpec
import pl.iterators.stir.testkit.RequestBuilding

trait Http4sStirRouteBaklavaSpec extends RouteBaklavaSpec with RequestBuilding {

lazy val TestRequest = new RequestBuilder(Method.fromString(routeRepresentation.method).toOption.get)
}
Loading