I have 2 simple APIs:
GET /users/me/photos controllers.api.UserController.getMyPhotos
GET /users/:userId/photos controllers.api.UserController.getPhotos(userId: Int)
Here's getPhotos:
def getPhotos(userId: Int) = SecuredAction.async {
logger.info(s"Searching for user $userId's photos")
userPhotosRepo.findByUserId(userId).map {
photos => Ok(Json.toJson(photos))
}
}
Here's getMyPhotos:
def getMyPhotos = SecuredAction.async { request =>
request.identity.id.map { currentUserId =>
logger.info(s"Searching for current user's photos")
getPhotos(currentUserId) // doesn't work
}.getOrElse(Future.successful(InternalServerError))
}
How can I make getMyPhotos proxy through to getPhotos without creating a helper method they both call?
Here you can use reverse routing provided by Play Framework
[full package].routes.[controller].[method]
In your case
routes.api.UserController.getPhotos(request.identity.id)
If you want the result of first action
val ans: Result = Redirect(routes.api.UserController.getPhotos(request.identity.id))
I hope that's what you were trying to ask.
EDIT:
For your concern this should be a proper way to do it
def getPhotos(userId: Long) = SecuredAction.async {
userPhotosRepo findByUserId(userId) map {
photos => Ok(Json.toJson(photos))
}
}
def getMyPhotos = SecuredAction.async { request =>
request.identity.id map { id =>
Redirect(routes.HomeController.getPhotos(id))
}
}
Related
In Scala + Play, how to put a variable into response ?
In page
#lastName #firstName
In application controller:
def index = Action {
implicit request =>{
request.setAttribute("lastName", "john"); // not work
Ok(views.html.index("xxx"))
}
}
if in java servlet , we can do this way:
request.setAttribute("name", "value");
request.getRequestDispatcher("page.jsp").forward(request, response);
how to do the same in Scala + Play ?
You want to use view/page variables.
In your view:
#(myStringVar: String)
<b>Hello #myStringVar</b>
Your controller:
def index = Action {
implicit request => {
Ok(views.html.index(myStringVar = "Ooo!"))
}
}
Ref: https://playframework.com/documentation/2.5.x/ScalaTemplates#Overview
I'm trying to make a general method for sending SOAP requests and getting responses. I'm programming using Groovy and I'm using the wslite library to help me out with SOAP. Here's a sample snippet for making a SOAP request and getting a response:
#Grab('com.github.groovy-wslite:groovy-wslite:1.1.2')
import wslite.soap.*
SOAPClient client = new SOAPClient('http://www.dneonline.com/calculator.asmx')
def response = client.send(SOAPAction: 'http://tempuri.org/Add') {
body {
Add(xmlns: 'http://tempuri.org/') {
intA(x)
intB(y)
}
}
}
By general, I meant being able to dynamically create a SOAP request (given certain information such as the service/method name, the parameters contained in the method, etc.) and obtain the SOAP response. I'm thinking something like this:
#Grab('com.github.groovy-wslite:groovy-wslite:1.1.2')
import wslite.soap.*
def getResponse(String clientURL, String action, String service, String serviceNamespace, Map parameters, ...) {
SOAPClient client = new SOAPClient(clientURL)
def response = client.send(SOAPAction: action) {
body {
"$service"(xmlns: serviceNameSpace) {
...
}
}
}
}
My problem lies in constructing the closure for the request body. Like, in example, if my method received a service Add, a serviceNamespace http://tempuri.org/, and a parameter map like so: [intA: x, intB: y]... how do I merge all of these so that I can construct this kind of closure:
Add(xmlns: 'http://tempuri.org/') {
intA(x)
intB(y)
}
I'm pretty much a newbie to Groovy, so don't be too harsh. If there's a better way to implement this concept of a general method, I would gladly like to hear it. The concept is similar to this. But I'd rather play with Map than a String. I'm not using Grails, really. Just plain Groovy.
In short, cfrick is correct:
[intA: x, intB: y].each{fn,arg -> delegate."$fn"(arg) }
How does it work?
An easy way to see how this works is to simulate it with a fake client class:
groovy.util.NodeBuilder
class Client {
def send(String action, Closure closure) {
closure.delegate = new NodeBuilder()
closure()
}
}
def client = new Client()
def response = client.send('http://tempuri.org/Add') {
body {
Add(xmlns: 'http://tempuri.org/') {
intA(1)
intB(2)
}
}
}
assert response.Add[0].#xmlns == 'http://tempuri.org/'
assert response.Add.intA.text() == '1'
assert response.Add.intB.text() == '2'
In the example above, the response object is created by Groovy's NodeBuilder. It's just a quick way to prototype something that processes the closure passed to Client.send().
With this testable code I'll try what cfrick suggested and validate that it works:
def doIt(String action, String service, String serviceNamespace, Map params) {
def client = new Client()
client.send(action) {
body {
"$service"(xmlns: serviceNamespace) {
params.each { method, argument ->
delegate."$method"(argument)
}
}
}
}
}
response = doIt('http://tempuri.org/Add', 'Add', 'http://tempuri.org/', [intA: 1, intB: 2])
assert response.Add[0].#xmlns == 'http://tempuri.org/'
assert response.Add.intA.text() == '1'
assert response.Add.intB.text() == '2'
Request Body
In addition, you can factor out the process of creating the request body:
def getRequestBody(String service, String serviceNamespace, Map params) {
{ ->
"$service"(xmlns: serviceNamespace) {
params.each { method, argument ->
delegate."$method"(argument)
}
}
}
}
def doIt(String action, String service, String serviceNamespace, Map params) {
def client = new Client()
client.send(action) {
body(getRequestBody(service, serviceNamespace, params))
}
}
I'm having some problems when trying to map some different objects so that I can extract some fields from it.
I've the function in my controller like this:
def index = SecuredAction.async { implicit request =>
transportService.allNonActive().map { transports =>
val sourceEmailsListBuffer = ListBuffer[String]()
val destinyEmailsListBuffer = ListBuffer[String]()
val sortingCenterStockListBuffer = ListBuffer[SortingCenterStock]()
val transportsListBuffer = ListBuffer[Transport]()
transports.map { transport =>
transportsListBuffer.append(transport)
// gets SC of this transport
sortingCenterStockService.retrieve(transport.idSCStock).map { sortingCenterStock =>
Logger.debug(s"Entry on SCS")
sortingCenterStockListBuffer.append(sortingCenterStock)
}
// gets email from source
userDAO.find(transport.idSourceUser).map { option =>
option.map { user =>
user.email.map { email =>
sourceEmailsListBuffer.append(email)
Logger.debug(s"Entry on Source Email")
}
}
}
// gets email from destiny
userDAO.find(transport.idDestinyUser).map { option =>
option.map { user =>
user.email.map { email =>
destinyEmailsListBuffer.append(email)
Logger.debug(s"Entry on Destiny Email")
}
}
}
}
Logger.debug(s"Size of source emails: ${sourceEmailsListBuffer.size}")
Logger.debug(s"Size of destiny emails: ${destinyEmailsListBuffer.size}")
Logger.debug(s"Size of scs: ${sortingCenterStockListBuffer.size}")
Logger.debug(s"Size of transp: ${transportsListBuffer.size}")
Ok(views.html.transports.index(request.identity, sourceEmailsListBuffer.toList, destinyEmailsListBuffer.toList, sortingCenterStockListBuffer.toList, transportsListBuffer.toList))
}
}
When I load the page for the first time (with any minor change, i.e. I change the string I use to indicate what I'm debugging), it gets the info from the last map userDAO.find(transport.idDestinyUser).map. When I refresh the page, the list's size destinyEmailsListBuffer is 0 and it is returned to the view before doing the map (at least I think so).
This is what I get after refreshing, after getting the correct output for the first time:
second load of the page
Thanks in advance, I hope you can help me!
I think your general structure is wrong. For instance:
userDAO.find(transport.idDestinyUser).map { option =>
option.map { user =>
user.email.map { email =>
destinyEmailsListBuffer.append(email)
Logger.debug(s"Entry on Destiny Email") // This returns Unit!
}
}
}
So you are using map operations and chaining those results to other functions, but instead if returning lists of items, you are incrementing an existing list that is never returned. Either return destinyEmailsListBuffer after logging or re-write to use forEach and to pick up the right values from somewhere.
I have (formerly) REST spray.io webservice. Now, I need to generate SESSIONID in one of my methods to be used with some other methods. And I want it to be in the response header.
Basically, I imagine logic like the following:
path("/...") {
get {
complete {
// some logic here
// .....
someResult match {
case Some(something) =>
val sessionID = generateSessionID
session(sessionID) = attachSomeData(something)
// here I need help how to do my imaginary respond with header
[ respond-with-header ? ]("X-My-SessionId", sessionID) {
someDataMarshalledToJSON(something)
}
case None => throw .... // wrapped using error handler
}
}
}
}
But, it doesn't work inside complete, I mean respondWithHeader directive. I need an advice.
There is a respondWithHeader directive in Spray. Here is official doc and example of how you could use it:
def respondWithSessionId(sessionID: String) =
respondWithHeader(RawHeader("X-My-SessionId", sessionID))
path("/...") {
get {
// some logic here
// .....
sessionIDProvider { sessionID =>
respondWithMediaType(`application/json`) { // optionally add this if you want
respondWithSessionId(sessionID) {
complete(someDataMarshalledToJSON(something))
}
}
}
}
}
In order to achieve a streaming upload I have written a custom PartHandler (Thread here ).
I now need to access a value that is stored inside the play! session inside the PartHandler.
How can I do that ?
Code sample:
def uploadFile() =
Action( parse.multipartFormData(myPartHandler) )
{ request =>
request.session.get("myValue") // <-- Recovering value is fine here
Ok("Done") }
def myPartHandler: BodyParsers.parse.Multipart.PartHandler[MultipartFormData.FilePart[Result]] = {
parse.Multipart.handleFilePart {
case parse.Multipart.FileInfo(partName, filename, contentType) =>
// ** Need to access a value in session here **
//request.session.get("myValue")...
// Handle part ...
Thanks!
With the help of other users of the play! framework google group, here is how to access the request inside a custom partHandler.
//Create a body parser
val myBodyParser = BodyParser { request =>
parse.multipartFormData(myPartHandler(request)).apply(request)
}
def uploadFile() = Action(myBodyParser)
{request =>Ok("Done")}
def myPartHandler(request: RequestHeader) : BodyParsers.parse.Multipart.PartHandler[MultipartFormData.FilePart[Result]] = {
parse.Multipart.handleFilePart {
case parse.Multipart.FileInfo(partName, filename, contentType) =>
println(request.session.get("myValueKey"));