Get all active Routes / Paths in a running Play application - scala

Is there a standard way to get all possible (excluding wildcards of course) routes / paths valid within a play application ?
I can do it with
Play.current.routes.map( _.documentation.map(_._2))
which gives me all available routes but it looks a bit hacky to me.

Just for elaboration, what I do is this ( exactly what you did ):
val myroutes = Play.current.routes map (routes => routes.documentation) getOrElse (Nil)
myroutes foreach { r =>
println("%-10s %-50s %s".format(r._1, r._2, r._3))
}
And I also get:
GET / controllers.Application.index
GET /apis controllers.Application.apis
GET /docs controllers.Application.docs
GET /sampleapi/status/$id<[^/]+> controllers.SampleAPI.status(id:String)
GET /city/$id<[^/]+> controllers.CityAPI.findById(id:Long)
GET /city1/$id<[^/]+> controllers.CityAPI.findById1(id:Long)
GET /apps/authorize/ controllers.Apps.authorize
POST /apps/send_auth/ controllers.Apps.send_auth
GET /clients/ controllers.Clients.list
GET /client/new controllers.Clients.create
POST /client/add controllers.Clients.add
POST /client/update controllers.Clients.update
GET /client/edit/$id<[^/]+> controllers.Clients.edit(id:String)
PUT /client/ controllers.Clients.update
GET /client/$id<[^/]+> controllers.Clients.get(id:String)
DELETE /client/$id<[^/]+> controllers.Clients.delete(id:String)
GET /login controllers.Auth.login
POST /authenticate controllers.Auth.authenticate
GET /logout controllers.Auth.logout
POST /oauth2/access_token controllers.OAuth2Controller.accessToken
GET /webjars/$file<.+> controllers.WebJarAssets.at(file:String)
GET /assets/$file<.+> controllers.Assets.at(path:String = "/public", file:String)
This also includes webjar and assets path, so you may want to filter them out.

Related

Connecting to Facebook's API

I am facing this issue connecting with Facebook's API using httr package, while testing on 'me' node I came along the following problem.
I was under the impression that me node does not require special permissions.
Testing on the browser with 'https://graph.facebook.com/me' gave the same results, it would be great if some one could provide an explanation.
# Define keys
app_id = 'my_app_id'
app_secret = 'my_app_secret'
# Define the app
fb_app <- oauth_app(appname = "facebook",
key = app_id,
secret = app_secret)
# Get OAuth user access token
fb_token <- oauth2.0_token(oauth_endpoints("facebook"),
fb_app,
scope = 'public_profile',
type = "application/x-www-form-urlencoded",
cache = TRUE)
response <- GET("https://graph.facebook.com",
path = "/me",
config = config(token = fb_token))
# Show content returned
content(response)
$error
$error$message
[1] "An active access token must be used to query information about the current user."
$error$type
[1] "OAuthException"
$error$code
[1] 2500
$error$fbtrace_id
[1] "ARRnb93rZHmWLlXK_MMJlfi"
Noting that I have signed in using the app.

Getting restrictions from Confluence page

I'm not very savvy with web API calls, but I've been using the following powershell code (this site in this example is one I found that has some public data... my site is internal and requires I pass the credential, which has been working for me without issue):
If(-not (Get-InstalledModule -Name 'ConfluencePS')){Install-Module ConfluencePS}
Import-Module ConfluencePS
Set-ConfluenceInfo -BaseUri "https://wiki.opnfv.org"
$space = Get-confluencepage -Spacekey ds
ForEach($item in $space)
{
$splatParams = #{
Uri = "https://wiki.opnfv.org/rest/api/content/$($item.ID)/restriction"
ContentType = 'application/json'
method = 'GET'
}
#reference https://developer.atlassian.com/cloud/confluence/rest/#api-api-content-id-restriction-get
Invoke-RestMethod #splatParams
}
The documentation for the ConfluencePS shows that restrictions is still an open feature request but I need to get this working for a project.
I put a breakpoint in on line 982 from ConfluencePS.psm1 and was able to see the various calls and how the params are structured but when I try to mimic it (and change the URI based on the confluence documentation) I get an error "HTTP error 405 - MethodNotAllowed". Anyone have suggestions on how I can get this working? I'm trying to return back the permissions applied for all pages in a specific space.
Get Restrictions by Content ID
As you found out by yourself, it is required to add "byOperation".
I was able to get the restrictions of a specific page with the following code:
# for testing purposes ONLY, I've specified the URL and ID
$wikiUrl = "https://wiki.opnfv.org"
$itemId = "6820746"
$splatParams = #{
Uri = "$wikiUrl/rest/api/content/$itemId/restriction/byOperation"
ContentType = 'application/json'
method = 'GET'
}
$result = Invoke-RestMethod #splatParams
Tested on version 6.0.4 and 6.15.9
Filter by user name
If you like to filter the result by a specific username, you can use the following URI:
"$wikiUrl/rest/api/content/$itemId/restriction/byOperation/.../user?userName=".
Bt, there's an open bug on this way of action:
restriction returns ambiguous responses

Getting cors errors in Scala Play Framework v2.6.x

I'm trying to get around a CORS error for a simple "hello world" style REST API in Scala/Play 2.6.x and I have tried everything that I can think of at this point. As far as I can tell there is not a good solution or example to be found on the internet, so even if this should be an easy fix then anyone that has a good solution would really help me out by posting it in full. I am simply trying to send a post request from localhost:3000 (a react application using axios) to localhost:9000 where my Scala/Play framework lives.
THE ERRORS
The error that I am getting on the client-side is the following:
XMLHttpRequest cannot load http://localhost:9000/saveTest.
Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:3000' is therefore not allowed
access. The response had HTTP status code 403.
The error that I am getting on the server-side is
success] Compiled in 1s
--- (RELOAD) ---
[info] p.a.h.EnabledFilters - Enabled Filters
(see <https://www.playframework.com/documentation/latest/Filters>):
play.filters.csrf.CSRFFilter
play.filters.headers.SecurityHeadersFilter
play.filters.hosts.AllowedHostsFilter
play.filters.cors.CORSFilter
[info] play.api.Play - Application started (Dev)
[warn] p.f.c.CORSFilter - Invalid CORS
request;Origin=Some(http://localhost:3000);
Method=OPTIONS;Access-Control-Request-Headers=Some(content-type)
MY CODE
I have the following in my application.conf file
# https://www.playframework.com/documentation/latest/Configuration
play.filters.enabled += "play.filters.cors.CORSFilter"
play.filters.cors {
pathPrefixes = ["/"]
allowedOrigins = ["http://localhost:3000", ...]
allowedHttpMethods = ["GET", "POST", "PUT", "DELETE"]
allowedHttpHeaders = ["Accept"]
preflightMaxAge = 3 days
}
I've tried changing pathPrefixes to /saveTest (my endpoint), and tried changing allowedOrigins to simply 'https://localhost'. I've tried changing allowedHttpHeaders="Allow-access-control-allow-origin". I've tried setting allowedOrigins, allowedHttpMethods, and allowedHttpHeaders all to null which, according to the documentation (https://www.playframework.com/documentation/2.6.x/resources/confs/filters-helpers/reference.conf) should allow everything (as should pathPrefixes=["/"]
My build.sbt is the following, so it should be adding the filter to the libraryDependencies:
name := """scalaREST"""
organization := "com.example"
version := "1.0-SNAPSHOT"
lazy val root = (project in file(".")).enablePlugins(PlayScala)
scalaVersion := "2.12.2"
libraryDependencies += guice
libraryDependencies += "org.scalatestplus.play" %% "scalatestplus-play" % "3.1.0" % Test
libraryDependencies += filters
According to documentation available here: https://www.playframework.com/documentation/2.6.x/Filters#default-filters you can set the default filters like this:
import javax.inject.Inject
import play.filters.cors.CORSFilter
import play.api.http.{ DefaultHttpFilters, EnabledFilters }
class Filters #Inject()(enabledFilters: EnabledFilters, corsFilter: CORSFilter)
extends DefaultHttpFilters(enabledFilters.filters :+ corsFilter: _*)
I'm not sure exactly where that should go in my project - it doesn't say, but from other stackoverflow answers I kind of assume it should go in the root of my directory (that is /app). So that's where I put it.
Finally, there was one exotic stackoverflow response that said to put this class in my controllers and add it as a function to my OK responses
implicit class RichResult (result: Result) {
def enableCors = result.withHeaders(
"Access-Control-Allow-Origin" -> "*"
, "Access-Control-Allow-Methods" ->
"OPTIONS, GET, POST, PUT, DELETE, HEAD"
// OPTIONS for pre-flight
, "Access-Control-Allow-Headers" ->
"Accept, Content-Type, Origin, X-Json,
X-Prototype-Version, X-Requested-With"
//, "X-My-NonStd-Option"
, "Access-Control-Allow-Credentials" -> "true"
)
}
Needless to say, this did not work.
WRAP UP
Here is the backend for my current scala project.
https://github.com/patientplatypus/scalaproject1/tree/master/scalarest
Please, if you can, show a full working example of a CORS implementation - I cannot get anything I can find online to work. I will probably be submitting this as a documentation request to the Play Framework organization - this should not be nearly this difficult. Thank you.
Your preflight request fails because you have a Content-Type header set
Add content-type to allowedHttpHeaders in your application.conf like so
#application.conf
play.filters.cors {
#other cors configuration
allowedHttpHeaders = ["Accept", "Content-Type"]
}
I had this problem too and I added these code in application.conf
play.filters.enabled += "play.filters.cors.CORSFilter"
play.filters.cors {
allowedHttpMethods = ["GET", "HEAD", "POST"]
allowedHttpHeaders = ["Accept", "Content-Type"]"
}
and now everything is OK!
for more info
For playframework version 2.8.x , we can wrap the Response in a function as below -
def addCorsHeader (response : Result) : Result = {
response.withHeaders(
("Access-Control-Allow-Origin", "*"),
("Access-Control-Allow-Methods" , "GET,POST,OPTIONS,DELETE,PUT")
)
}
Now in the controller, wrap the Results using the above function.
val result = myService.swipeOut(inputParsed)
addCorsHeader(Ok(s"$result row successfully updated. Trip complete"))
}
else {
addCorsHeader(InternalServerError("POST body is mandatory"))
}

PHPBrowser Hidden API method "_loadPage" is not following 301 Redirects

I am writing a test with PHPBowser, in Codeception v2.2.11 that uses the hidden API method of _loadpage.
I have added this into my \Helper\Api as follows:
public function loadpage($link)
{
$this->getModule('PhpBrowser')->_loadPage('POST', $link);
}
And call it in an Api Codeception test, as follows:
$link = 'http://www.fiercebiotech.com/contact';
$I->loadpage($link);
The issue I am facing is that when using _loadpage, it does not follow redirects. This exampled link when finally resolved is 301 redirected to:
http://www.fiercebiotech.com/contact-us.
Here is the header response console output when _loadpage opens $link.
I loadpage "http://www.fiercebiotech.com/contact"
[Request Headers] []
[Page] http://www.fiercebiotech.com/contact
[Response] 404
I need help getting _loadpage to not stop at ~/contact but follow the 301 redirect to ~/contact-us, so I can get the output header response to be
[page] http://www.fiercebiotech.com/contact-us
[response] 200
Currently I cant get _loadpage to follow 301 redirects. Anyone out there have success doing so?
Ive attempted to use Codeception REST function startFollowingRedirects and adding allow_redirects: true as follows, but neither technique seems to work (as the redirect is not followed).
class_name: ApiTester
modules:
enabled:
- WebDriver:
url: ''
browser: 'chrome'
window_size: 1200x993
clear_cookies: true
allow_redirects: true
- \Helper\Acceptance
- REST:
url: 'host'
depends: PhpBrowser
allow_redirects: true
- \Helper\Api
I found the solution to my issue:
The issue began with, as I suspected is that _loadpage does not follow redirects, it only loads the page requested and stops. In this case '~/contact-us', ignoring the fact that the page gets redirected to (with a 301) to '~/contact-us'.
I cant simply load the page (via _loadpage)
Get the header response
and assume that I will be getting the header response of the redirected URL
I will only get the header response of the original URL.
The Solution:
I have to in my foreach loop:
Go to the URL
send a GET
Grab the HTTP Header
Assert that the HTTP header has a 200OK response
Solution - As it is in Codeception code:
public function Validate_httpStatus_mainNav($mainNavLocator)
{
//Used to test main navigation -- 404 tests
$I = $this;
$mainNavLinks = $I->grabMultiple($mainNavLocator, 'href');
codecept_debug($mainNavLinks);
foreach ($mainNavLinks as $link) {
$I->amOnUrl($link);
$I->sendGET($link);
$I->grabHttpHeader($link);
$I->canSeeResponseCodeIs(HttpCode::OK);
}
}

How to get http request header info from the server side with spray RestAPI

I am new to Scala and Spray. I have written a simple REST API according to the instructions given in this blog post.
http://www.smartjava.org/content/first-steps-rest-spray-and-scala
And all are working as expected.
Now I want to modify the program to print the HTTP headers like Encoding, Language, remote-address, etc.. I would like to print all the header information (purpose is to log these information)
But I could not find a proper documentation or examples. Could anyone please help me to get this done.
If you need to extract a specific header:
optionalHeaderValueByName("Encoding") { encodingHeader =>
println(encodingHeader)
complete("hello")
}
alternatively you can access the raw request object and directly extractive the headers. Here's a custom directive that logs all the headers:
def logHeaders(): Directive0 = extract(_.request.headers).map(println)
Usage
logHeaders() {
complete("hello")
}
Here's how I got it working.
Directive:
def logHeaders(innerRoute: Route): (RequestContext => Unit) = extract(_.request.headers) { headers =>
headers.foreach(h => logger.info("header: {} = {}", h.name, h.value))
innerRoute
}
Usage:
logHeaders() {
complete("hello")
}