Skip to content
This repository has been archived by the owner on Apr 8, 2021. It is now read-only.

Fix swagger ui #57

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
12 changes: 9 additions & 3 deletions src/main/g8/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ lazy val $name;format="norm,word"$ = (project in file("."))
.disablePlugins(HeaderPlugin)

lazy val play = (project in file("play"))
.enablePlugins(ProjectDockerBuildPlugin)
.enablePlugins(ProjectPlugin, ProjectDockerBuildPlugin)
.enablePlay
.enableIntegrationTests
.settings(
name := "$name;format="norm"$",
buildInfoPackage := s"\${organization.value}.$name;format="norm,word"$.build",
libraryDependencies ++= Seq(
Cats.core,
guice,
Expand All @@ -26,7 +28,9 @@ lazy val play = (project in file("play"))
webjars,
// Play WebServer client library
ws % "it,test"
)
),
envVars in Test += "STARTUPLOGGING_ENABLED" -> "false",
envVars in IntegrationTest += "STARTUPLOGGING_ENABLED" -> "false"
)
.dependsOn(testCommon % "it,test")

Expand All @@ -38,9 +42,11 @@ lazy val testCommon = (project in file("testCommon"))
)

lazy val perf = (project in file("perf"))
.enablePlugins(ProjectDockerBuildPlugin)
.enablePlugins(ProjectPlugin, ProjectDockerBuildPlugin)
.enableIntegrationTests
.settings(
name := "$name;format="norm"$-perf",
buildInfoPackage := s"\${organization.value}.$name;format="norm,word"$.perf.build",
libraryDependencies ++= Seq(
Cats.core,
GatlingDependencies.app,
Expand Down
2 changes: 1 addition & 1 deletion src/main/g8/docker/docker-compose-perf.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ version: "2.1"

services:
perf:
image: $name;format="norm,word"$/perf
image: $organisation;format="norm"$/$name;format="norm"$-perf
depends_on:
play:
condition: service_healthy
Expand Down
3 changes: 2 additions & 1 deletion src/main/g8/docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ version: "2.1"
# **All** services within this file should be defined with healthchecks
services:
play:
image: $name;format="norm,word"$/play
image: $organisation;format="norm"$/$name;format="norm"$
healthcheck:
test: ["CMD", "wget", "-qO", "-", "http://localhost:9000/health"]
interval: 5s
Expand All @@ -16,6 +16,7 @@ services:
APP_HOST: "0.0.0.0"
APP_PORT: "9000"
APPLICATION_SECRET: change_me
ALLOWED_HOST: \${ALLOWED_HOST}
ports:
- "9000:9000"
networks:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ object Docker extends Tag("Docker")
class $name;format="norm,Camel"$IntegrationTest @Inject() extends RestApiIntegrationTest {
"When application is running" - {
"Health-check" - {
"should always return status okay" taggedAs (Docker) in {
"should always return status okay" taggedAs Docker in {
wsClient
.url(s"\$appUrl/health")
.addHttpHeaders(Http.HeaderNames.HOST -> "localhost")
Expand All @@ -21,7 +21,7 @@ class $name;format="norm,Camel"$IntegrationTest @Inject() extends RestApiIntegra
}
}
"Build info" - {
"should return a JSON object with current version" taggedAs (Docker) in {
"should return a JSON object with current version" taggedAs Docker in {
wsClient
.url(s"\$appUrl/version")
.addHttpHeaders(Http.HeaderNames.HOST -> "localhost")
Expand All @@ -33,46 +33,41 @@ class $name;format="norm,Camel"$IntegrationTest @Inject() extends RestApiIntegra
}
}
"OpenAPI specs" - {
"should return the yaml specs" taggedAs (Docker) in {
"should return the yaml specs" taggedAs Docker in {
wsClient
.url(s"\$appUrl/specs.yml")
.addHttpHeaders(Http.HeaderNames.HOST -> "localhost")
.url(s"\$appUrl/$name;format="norm"$.yml")
.get()
.map(res => {
res.status shouldEqual 200
})
.map(res => res.status shouldEqual 200)
}
"should redirect to the API docs" taggedAs (Docker) in {
"should redirect to the API docs" taggedAs Docker in {
wsClient
.url(s"\$appUrl/docs")
.addHttpHeaders(Http.HeaderNames.HOST -> "localhost")
.withFollowRedirects(false)
.get()
.map(res => {
.map { res =>
res.status shouldEqual 303
res
.header("Location")
.get shouldEqual "/docs/index.html?url=/specs.yml"
})
.get shouldEqual "/assets/lib/swagger-ui/index.html?url=%2F$name;format="norm"$.yml"
}
}
"should show the API docs" taggedAs (Docker) in {
"should show the API docs" taggedAs Docker in {
wsClient
.url(s"\$appUrl/docs?url=/specs.yml")
.addHttpHeaders(Http.HeaderNames.HOST -> "localhost")
.url(s"\$appUrl/assets/lib/swagger-ui/index.html?url=/$name;format="norm"$.yml")
.get()
.map(res => {
res.status shouldEqual 200
})
.map(res => res.status shouldEqual 200)
}
"default route should re-direct to API docs" taggedAs (Docker) in {
"default route should re-direct to API docs" taggedAs Docker in {
wsClient
.url(s"\$appUrl/")
.addHttpHeaders(Http.HeaderNames.HOST -> "localhost")
.withFollowRedirects(false)
.get()
.map(res => {
.map { res =>
res.status shouldEqual 303
})
res
.header("Location")
.get shouldEqual "/assets/lib/swagger-ui/index.html?url=%2F$name;format="norm"$.yml"
}
}
}
}
Expand Down

This file was deleted.

1 change: 1 addition & 0 deletions src/main/g8/play/src/main/resources/application.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ include "env"
include "akka"
include "play"
include "services"
include "logging"
4 changes: 4 additions & 0 deletions src/main/g8/play/src/main/resources/env.conf
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,9 @@ env {
TEST_ACTOR_MESSAGE_SERIALISATION = \${?TEST_ACTOR_MESSAGE_SERIALISATION}
# Whether Java serialisation should be used or not
USE_JAVA_SERIALISATION = \${?USE_JAVA_SERIALISATION}
# The host address which will be added to allowed hosts which will be used both in integration tests and production
ALLOWED_HOST = \${?ALLOWED_HOST}
# Log JVM props, configuration on application startup
STARTUPLOGGING_ENABLED = \${?STARTUPLOGGING_ENABLED}
}
}
5 changes: 5 additions & 0 deletions src/main/g8/play/src/main/resources/logging.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
startuplogging {
# Log JVM props, configuration on application startup
enabled = true
enabled = \${?STARTUPLOGGING_ENABLED}
}
17 changes: 16 additions & 1 deletion src/main/g8/play/src/main/resources/play.conf
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,22 @@ play {
}
http.secret.key = "\${?env.required.APPLICATION_SECRET}"
modules.enabled += "$organisation_domain$.$organisation;format="norm,word"$.$name;format="norm,word"$.core.CoreModule"
filters.enabled += "$organisation_domain$.$organisation;format="norm,word"$.$name;format="norm,word"$.core.api.filters.ErrorHandlingFilter"

filters {
headers {
contentSecurityPolicy = "default-src 'self' 'sha256-nhwGBMLdamxIibfUBcAZV1BeJ3oFoeNBYiIbKkxRyuY='; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' https://online.swagger.io data:"
# If true, allow an action to use .withHeaders to replace one or more of the security headers
allowActionSpecificHeaders = false
}
hosts {
allowed = [
\${?env.optional.ALLOWED_HOST},
".",
"localhost"
]
}
enabled += "$organisation_domain$.$organisation;format="norm,word"$.$name;format="norm,word"$.core.api.filters.ErrorHandlingFilter"
}
}

environment {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ class StartUpLogging @Inject()(
* Logs environment, JVM, properties and configuration data.
*/
def logAllTheThings(): Unit = {
logEnvironmentData()
logJVMData()
logPropertyData()
logConfigurationData(config)
val isEnabled = config.get[Boolean]("startuplogging.enabled")
if (isEnabled) {
logEnvironmentData()
logJVMData()
logPropertyData()
logConfigurationData(config)
}
}

private def logEnvironmentData(): Unit = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package $organisation_domain$.$organisation;format="norm,word"$.$name;format="no

import javax.inject.{Inject, Singleton}

import scala.concurrent.ExecutionContext

import play.api.routing.Router.Routes
import play.api.routing.SimpleRouter
import play.api.routing.sird._
Expand All @@ -14,27 +16,23 @@ class CoreRouter @Inject()(
buildInfoController: BuildInfoController,
assetsController: controllers.Assets,
defaultController: controllers.Default
)(
implicit executor: ExecutionContext
) extends SimpleRouter {

override def routes: Routes = {

// Base Routes
case GET(p"/health") => healthCheckController.health
case GET(p"/version") => buildInfoController.info

// Swagger Documentation and Specification routes
case GET(p"/specs.yml") =>
assetsController.at(path = "/", "$name;format="norm,word"$.yml")
case GET(p"/docs" ? q"url=\$url") =>
assetsController.at(path = "/public/lib/swagger-ui", file = "index.html")
case GET(p"/docs/index.html" ? q"url=\$specs") =>
assetsController.at(path = "/public/lib/swagger-ui", file = "index.html")
case GET(p"/docs") | GET(p"/docs/index.html") =>
defaultController.redirect("/docs/index.html?url=/specs.yml")
case GET(p"/docs/\$file*") =>
assetsController.at(path = "/public/lib/swagger-ui", file)
case GET(p"/") =>
defaultController.redirect("/docs")
}
override def routes: Routes =
exposeSwaggerUIAtPath(
assetsController,
"/",
"$name;format="norm"$.yml",
"/docs"
).orElse(
swaggerUiRoutes(assetsController, "/", "$name;format="norm"$.yml")(executor)
)
.orElse {
// Base Routes
case GET(p"/health") => healthCheckController.health
case GET(p"/version") => buildInfoController.info
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package $organisation_domain$.$organisation;format="norm,word"$.$name;format="norm,word"$.core.api

import scala.concurrent.ExecutionContext

import _root_.controllers.Assets
import play.api.mvc._
import play.api.routing.Router.Routes
import play.api.routing.sird._

package object routers {

/**
* A routing function allowing Play to serve the swagger UI.
*
* @param assets the assets controller
* @param swaggerPath the path of the directory at which the swagger file can be found
* @param swaggerFile the name of the swagger file
* @return a routing partial-function that can be composed with other routes
* and fed to a Play application
*/
def swaggerUiRoutes(assets: Assets, swaggerPath: String, swaggerFile: String)(
implicit ec: ExecutionContext
): Routes = {
case GET(p"/assets/\$file*") =>
assets.at(path = "/public/", file)
case GET(p"/docs") =>
new ActionBuilderImpl(BodyParsers.utils.empty).apply {
Results.Redirect(
url = "/assets/lib/swagger-ui/index.html",
queryString = Map("url" -> Seq(s"/\$swaggerFile"))
)
}
case GET(p"/") =>
new ActionBuilderImpl(BodyParsers.utils.empty).apply {
Results.Redirect(
url = "/assets/lib/swagger-ui/index.html",
queryString = Map("url" -> Seq(s"/\$swaggerFile"))
)
}
}

/**
* Generic function to expose specific swagger specs at specific url path
* @param assets the assets controller
* @param swaggerPath the path of the directory at which the swagger file can be found
* @param swaggerFile the name of the swagger file
* @param urlToServeSwagger url to server swagger ui
* @return
*/
def exposeSwaggerUIAtPath(
assets: Assets,
swaggerPath: String,
swaggerFile: String,
urlToServeSwagger: String
)(implicit ec: ExecutionContext): Routes = {
case GET(p"/\$url") if url == swaggerFile =>
assets.at(swaggerPath, swaggerFile)
case GET(p"/\$url*") if url == urlToServeSwagger.dropWhile(_ == '/') =>
new ActionBuilderImpl(BodyParsers.utils.empty).apply {
Results.Redirect(
url = "/assets/lib/swagger-ui/index.html",
queryString = Map("url" -> Seq(s"/\$swaggerFile"))
)
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class StartUpLoggingSpec extends PlaySpec {

private val application =
GuiceApplicationBuilder()
.configure("startuplogging.enabled" -> true)
.overrides(
bind[LoggerLike]
.qualifiedWith("startUpLogging")
Expand Down
Loading