How to add a dynamically generated route in Play 2.5 Scala - scala

I am trying to use Play to create a simple server in Scala.
I want to provide an endpoint for a webhook that is generated from a secret token set in an environment variable.
export SECRET_TOKEN="asntoehu"
I want to create a route like POST /asntoehu controllers.Application.webhook
I can't work out how to either pass such an environment variable to conf/routes file or how to manually override routing in my app.
I am using the scala play seed created by running sbt new playframework/play-scala-seed.g8
Scala 2.5 using Dependency Injection method (so can't use GlobalSettings override)
How should I do this?

Related

how to disclude development.conf from docker image creation of play framework application artifact

Using scala playframework 2.5,
I build the app into a jar using sbt plugin PlayScala,
And then build and pushes a docker image out of it using sbt plugin DockerPlugin
Residing in the source code repository conf/development.conf (same where application.conf is).
The last line in application.conf says include development which means that in case development.conf exists, the entries inside of it will override some of the entries in application.conf in such way that provides all default values necessary for making the application runnable locally right out of the box after the source was cloned from source control with zero extra configuration. This technique allows every new developer to slip right in a working application without wasting time on configuration.
The only missing piece to make that architectural design complete is finding a way to exclude development.conf from the final runtime of the app - otherwise this overrides leak into production runtime and obviously the application fails to run.
That can be achieved in various different ways.
One way could be to some how inject logic into the build task (provided as part of the sbt pluging PlayScala I assume) to exclude the file from the jar artifact.
Other way could be injecting logic into the docker image creation process. this logic could manually delete development.conf from the existing jar prior to executing it (assuming that's possible)
If you ever implemented one of the ideas offered,
or maybe some different architectural approach that gives the same "works out of the box" feature, please be kind enough to share :)
I usually have the inverse logic:
I use the application.conf file (that Play uses by default) with all the things needed to run locally. I then have a production.conf file that starts by including the application.conf, and then overrides the necessary stuff.
for deploying to production (or staging) I specify the production/staging.conf file to be used
This is how I solved it eventually.
conf/application.conf is production ready configuration, it contains placeholders for environment variables whom values will be injected in runtime by k8s given the service's deployment.yaml file.
right next to it, conf/development.conf - its first line is include application.conf and the rest of it are overrides which will make the application run out of the box right after git clone by a simple sbt run
What makes the above work, is the addition of the following to build.sbt :
PlayKeys.devSettings := Seq(
"config.resource" -> "development.conf"
)
Works like a charm :)
This can be done via the mappings config key of sbt-native-packager:
mappings in Universal ~= (_.filterNot(_._1.name == "development.conf"))
See here.

How can I easily serve the Swagger UI in the root of my Scala Play2 microservice?

I'm developing a microservice with Scala and Play 2.5 and trying to document my endpoints with Swagger.
I added the Swagger UI webjar to my dependencies:
"org.webjars" % "swagger-ui" % "2.1.8-M1"
And the Swagger Play2 plugin:
"io.swagger" %% "swagger-play2" % "1.5.3"
Note: Version 1.5.3 of the Swagger Play2 plugin is not officially released yet. I built it from the master branch of the project, because it is the only version that can work with Play 2.5.8, which is the version I am using.
Then, I added the following to my routes file:
GET /assets/*file controllers.Assets.at(path="/public", file)
GET /api-docs controllers.ApiHelpController.getResources
By doing so, I am able to access the Swagger UI through:
http://localhost:9000/assets/lib/swagger-ui/index.html?/url=http://localhost:9000/api-docs
However, that is a huge URL. I want to simplify it to something as simple as the root (/), but there are the following challenges:
How can I make Play2 dynamically pass the url parameter to the static HTML page? How can I do so in a way that the host and port are adjusted to whatever they are on the server where the service is running? I considered using controllers.Default.redirect, but I couldn't find a way to interpolate the host and port in the argument string.
How can I map / to assets/lib/swagger-ui/index.html and pass the url argument?
Here is the best way you can make things work generically without any hardcoded url and port numbers
Add a route to handle Redirect
GET /swaggerDocs controller.Application.redirectDocs
Use the same logic you know, but just use relative URLs instead of absolute.
def redirectDocs = Action {
Redirect(url = "/assets/lib/swagger-ui/index.html", queryString = Map("url" -> Seq("/api-docs")))
}

Accessing application.conf from SBT build file

I'm working on a Play library that's designed to plug into both the build process and the application code. I want the library to be centrally configured from the application's application.conf, and both the build-time and run-time parts need to access that configuration. At run-time, this is no problem; I just define a reference.conf with any defaults and use ConfigFactory.load, as usual.
However, I'm not sure what's best for build-time. I'm using the following in an SBT task:
import com.typesafe.config.ConfigFactory
val baseDir = baseDirectory.value
val config = ConfigFactory.parseFile(baseDir / "conf/application.conf")
, because ConfigFactory.load doesn't seem to work at build-time. But this strikes me as poor form, because it bypasses the normal logic of load. Is there a preferred way of doing this?

Playframework settings depending on environment

I'm using playframework 2.1-RC2. First of all I've seen all the similar questions, so I followed the common instruction of separating application.conf file per environment. So I have application.test.conf and I run tests this way:
play -Dconfig.file=./conf/application.test.conf "test"
I tried different combinations, like
play -Dconfig.file=./conf/application.test.conf ~test
or
play -Dconfig.file=conf/application.test.conf ~test
Still no luck, it just does not get picked, default one (application.conf) is instead.
From the other side, if I do
play -Dconfig.file=./conf/application.dev.conf "run"
then application picks the right config.
So how can I specify the test configuration file?
I found the most robust way to specifiy this in a cross-platform compatible manner is to include it directly in the Build.scala:
val main = play.Project(appName, appVersion, appDependencies).settings(
javaOptions in Test += "-Dconfig.file=conf/test.conf",
...
)
Bonus: configure once and forget ;-)
Another approach is to override method on GlobalSettings / Global named onLoadConfig and that enables you to have control where your app will look for your configuration.
So in one of our application I have this setup below for my conf/ folder.
conf/application.conf --> configurations common for all environment
conf/dev/application.conf --> configurations for development environment
conf/test/application.conf --> configurations for testing environment
conf/prod/application.conf --> configurations for production environment
With that, you are able to implement inheritance like setup for configuration, you have common and 3 others for specific environment mode.
The code inside your onLoadConfig method should just load main configuration and set correct fallback configuration specific to your environment then return the configuration instance like below:
**return new Configuration(baseConfig.withFallback(envConfig));**
Try check this blog post for complete snippet of the code.
I hope this helps.

Different routes for prod and dev in play 2.0

My Play 2.0 application runs under different directories during development and in production:
During dev we use /, in production it runs as /crm/.
Is it possible to define a "root directory" of some sort for play?
This article suggests using the isDev() sort of methods and this one to use a config variable, but it seems like the routes file no longer allows code inclusion: adding %{ }—style tags to the routes file results in compilation errors.
In 2.0 or 2.0.1 you can't do it.
If you use the trunk-version you can define a property:
application.context="/AwesomePlayApplication"
This property can be set by in the usual way at production.
But this is only possible with the future version.
As there seems to be no other solution, I decided to go with a shell script that modifies the routes file on deployment and adds the necessary prefix to every route.