Reverse Route Not Generated - scala

I have encountered a situation where the routes are not being generated. In my play service I had situation where all the routes were defined in application routes file as follows:
GET /foo packageA.ControllerA.methodA()
… lots of other endpoints under ControllerA
GET /bar packageB.ControllerB.methodB()
… lots of other endpoints under ControllerB
GET /baz packageC.ControllerC.methodC()
… lots of other endpoints under ControllerC
When the application is the compiled, the reverse routes are generated.
Because the application routes file was getting too big, it was decided to split out the routes into separate routes file, one for each package like this:
routesForA.routes
GET /foo packageA.ControllerA.methodA()
… lots of other endpoints under ControllerA
etc
The reverse routes are again generated fine.
However, we wanted to put one endpoint from packageA.ControllerA into the routes file for packageB.ControllerB.
Say we moved
packageA.ControllerA.methodA into the routes file for packageB.controllerB.
Then what happened is that the reverse route for ControllerA.methodA was generated but all the other reverse routes for ControllerA routes (defined in the packageA routes file) were not generated.
Is this a bug or feature?

Our main routes file looks a bit different. We delegate in the main routes file to the special ones.
routes:
-> /foo foo.Routes
So in this example all requests that starts with /foo are forwarded to the foo.routes file (also in the conf folder)
foo.routes would look then like
GET /methodB packageB.ControllerB.methodB()
So the url for this would be /foo/methodB

Related

Play Framework returning 404 with play.http.context and trailing slash

I have a Play Framework application that serves an SPA. The routes file contains the following routes:
GET / controllers.Home.index
GET /index.html controllers.Home.index
# /api/* routes
GET /*file controllers.Assets.at(file)
controllers.Home.index serves the SPA's index after performing SSO routines.
When I run the application without any additional configuration, upon visiting localhost:3000 and localhost:3000/, the index action in Home controller is invoked as expected.
The problems start when I configure play.http.context:
When set to /my-app, requests to localhost:3000/my-app succeed; to localhost:3000/my-app/ return 404.
When set to /my-app/, requests to localhost:3000/my-app return 404; to localhost:3000/my-app/ succeed.
Is there a way to configure Play such that requests to both URLs succeed with controllers.Home.index?
I was looking for the same, but there is no good answer. For Play/Akka those are 2 different URLs,
Option 1)
is to define it 2x
GET /about controllers.HomeController.about
GET /about/ controllers.HomeController.about
Option 2)
redirect one url to another
GET /a controllers.HomeController.about
GET /a/ controllers.Default.redirect(to = "/a")
Option 3)
more advanced ways, but I did not testd it
https://doc.akka.io/docs/akka-http/current/routing-dsl/directives/path-directives/ignoreTrailingSlash.html
https://doc.akka.io/docs/akka-http/current/routing-dsl/directives/path-directives/redirectToNoTrailingSlashIfPresent.html
https://github.com/akka/akka-http/issues/880
Use both urls. With and without the trailing slash.

Scala Play route action can't be found

I don't understand why this isn't working.
# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~
# Serve index page from public directory
GET / controllers.HomeController.index
GET /index controllers.FrontendController.index
# An example route (Prefix all API routes with apiPrefix defined in application.conf)
GET /api/summary controllers.HomeController.appSummary
POST /api/getplt/:args controllers.UploadController.getPlt(args)# Serve static assets under public directory
GET /*file controllers.FrontendController.assetOrDefault(file)
Why can't it resolve the action? I can resolve the /api/summary without problems.
First for your assets use the following:
# Map static resources from the /public folder to the /assets URL path
GET /assets/*file controllers.Assets.at(file)
Then you could use the assetFinder within your views, something like:
<script src="#assetsFinder.path("javascripts/jquery.js")" type="text/javascript"></script>
This is because try to avoid any similar/identical routes, your first route and the asset related route, looks almost the same.
So to answer your question, either the Play is mixing these two routes, or you dont have index method within your HomeController class.

Play Swagger UI url alias

I have Swagger UI for API documentation, I use the same approach like in official specification for accessing it I use next URL:
http://localhost:9000/docs/swagger-ui/index.html?url=/assets/swagger.json
But I want to use http://localhost:9000/docs/ instead. I won't want to use WS for delegating, I would like to use single line in routes, like this:
GET /docs controllers.Assets.at(path:String="/public/lib/swagger-ui", file:String="index.html?url=/assets/swagger.json")
Or
GET /docs controllers.Assets.at(path:String="/public/lib/swagger-ui", file:String="index.html")
and http://localhost:9000/docs?url=/assets/swagger.json
What shold I change so it work?
You can't make shortness in route file for the URL /docs/swagger-ui/index.html?url=/assets/swagger.json because index.html is generated by swagger-ui plugin to public directory and requires access to files nearby (like js and css files). Play swagger-ui uses javascript for fetching json based description of your routes via URL parameter for further parsing this document to swagger-ui, in your case it's /assets/swagger.json endpoint.
I tried to make the mapping swagger's index.html file, so pass json location like URL parameter directly:
GET /swagger-ui controllers.Assets.at(path = "/public/lib/swagger-ui", file = "index.html")
Play couldn't render this page, and CSS wasn't found. I appended dummy mapping to every file in swagger's default directory /public/lib/swagger-ui:
GET /*file controllers.Assets.at(path = "/public/lib/swagger-ui", file)
Even after that Play couldn't properly render index.html.
How it can be solved without Play-Swagger:
Create directory public\swagger in your project;
Download all files from https://github.com/swagger-api/swagger-ui/tree/master/dist and copy them to public\swagger;
Copy your swagger.json (it's specification, right?) to public\specification;
Add to your routes file next line:
GET /docs
controllers.Assets.versioned(path="/public/specification", file: Asset
= "swagger.json")

How to do reverse routing from subcontroller to the sub routes in play scala?

I have created the sub routes from main route and I have created the subcontroller package e.g controllers.subcontrollers. Now how to access my sub routes from sub controllers.
You can access by using this:
// Redirect to /hello/Bob
def helloBob = Action {
Redirect(routes.Application.hello("Bob"))
}
As you can see in the playframework documentation.
https://playframework.com/documentation/2.3.x/ScalaRouting
But, if you meant that you have multiples controllers and divided them into packages and want to access them inside another another controller. You can achieve it using something like this:
controllers.packageName.routes.ControllerName.functionInsideController
Try to create a new route ex: subcontrollers.routes
main routes Ex:
-> /subcontrollers subcontrollers.Routes
subcontrollers.routes Ex:
# Map static resources from the /public folder to the /assets URL path
GET /assets/*file controllers.subcontrollers.Assets.at(path="/public", file)
GET /example controllers.subcontrollers.SubController.sample(parameter1:Long,parameter2: String)
Reference Link

Add a prefix to a bunch of urls

I have a bunch of routes with the same prefix:
# with prefixes
GET /api/v1.0/action1 controllers.Api.action1
GET /api/v1.0/action2 controllers.Api.action2
GET /api/v1.0/action3 controllers.Api.action3
GET /api/v1.0/action4 controllers.Api.action4
# normal urls
GET /action1 controllers.Home.action1
GET /action2 controllers.Home.action2
I want to get rid of repetition of /api/v1.0/. The urls must remain the same, I just want to not write them manually for each url in route file. In Rails it's possible. If there any way to do that?
Either you implement your own router for these actions following James Ropers' post, as mentioned by Rich. Doing so, allows you add the following to your route file:
-> /api/v1.0 YourPathBindableController
Alternatively you can use a plugin, such as navigator, which offers you advanced routing. Your navigator route file would then contain something like:
// Namespace ...
namespace("api"){
namespace("v1"){
GET on "index" to Application.index _
}
}
// ... or with reverse routing support
val api = new Namespace("api"){
val v2 = new Namespace("v2"){
val about = GET on "about" to Application.about _
}
}