Pattern for invoking function that returns LiftResponse

64 views
Skip to first unread message

Mads Hartmann Jensen

unread,
Apr 6, 2012, 4:39:58 AM4/6/12
to lif...@googlegroups.com
Hi guys,

So I know that you can create a function on the server than can be invoked
using the following pattern

val fname = Helpers.nextFuncName

val func = () => {
// do something.
}

S.addFunctionMap(fname, func)

You can then invoke the function using http://url?<fname>

Now, what is the pattern if I want the function to return a LiftResponse? I
have the following but the actual LiftResponse is not what is returned.

val imageFuncName = Helpers.nextFuncName

val imageUpload: () => Box[LiftResponse] = () => for {
req <- S.request
image <- req.uploadedFiles.headOption
fileName = UploadManager.store(image)
_ = user.avatar(fileName).save // TODO: Delete the old avatar if it exists.
} yield PlainTextResponse(fileName)

S.addFunctionMap(imageFuncName, imageUpload)

Peter Brant

unread,
Apr 6, 2012, 9:21:47 AM4/6/12
to lif...@googlegroups.com
You could use ResponseShortcutException.shortcutResponse from your
function. (You might want to use S.fmapFunc too [which is basically
just a convenience method over the code above]).

Pete

> --
> Lift, the simply functional web framework: http://liftweb.net
> Code: http://github.com/lift
> Discussion: http://groups.google.com/group/liftweb
> Stuck? Help us help you: https://www.assembla.com/wiki/show/liftweb/Posting_example_code

Antonio Salazar Cardozo

unread,
Apr 6, 2012, 10:51:39 AM4/6/12
to lif...@googlegroups.com
Yeah, I think if you're hitting it via AJAX, returning a LiftResponse is sufficient, but the way regular page requests are wired up, that won't work for non-AJAX requests. In particular, dispatchStatefulRequest in LiftServlet calls liftSession.runParams and ignores the return value -> https://github.com/lift/framework/blob/master/web/webkit/src/main/scala/net/liftweb/http/LiftServlet.scala#L343 . ResponseShortcutException should work, but I feel like that's still a hack. Maybe a dispatch function paired with a SessionVar is a better way to go? I mean, you'd basically be replicating Lift's function map on a per-session basis, but you could do something like:

object responseFns extends SessionVar[Map[String,()=>LiftResponse]](Map())
def hasRunnableParam_?(req:Req) = {
  req.params.exists {
    case (name, _) if responseFns.get.hasKey(name) =>
      true
    case _ => false
  }
}
def runFirstParam(req:Req) = {
  () => {
    req.params.collectFirst {
      case (name, _) if responseFns.get.hasKey(name) =>
        responseFns.get.get(name)()
    }
  }
}
def dispatch : DispatchPF = {
  case req:Req if hasRunnableParam_?(req) => 
    () => runFirstParam(req)
}

Then instead of calling S.addFunctionMap, you'd add an entry to the SessionVar above.

Just a quick idea though, not sure that this really qualifies as any cleaner :p
Thanks,
Antonio

Mads Hartmann Jensen

unread,
Apr 6, 2012, 12:10:46 PM4/6/12
to lif...@googlegroups.com

On Apr 6, 2012, at 3:21 PM, Peter Brant wrote:

> You could use ResponseShortcutException.shortcutResponse from your
> function.

Using ResponseShortcutException I have

--
val imageFuncName = Helpers.nextFuncName

val imageUpload: () => ResponseShortcutException = () => {
val name = for {


req <- S.request
image <- req.uploadedFiles.headOption
fileName = UploadManager.store(image)
_ = user.avatar(fileName).save // TODO: Delete the old avatar if it exists.

} yield fileName
ResponseShortcutException.shortcutResponse(PlainTextResponse(name openOr "error"))
}

S.addFunctionMap(imageFuncName, imageUpload)
--

Using doesn't change anything. Maybe it's relevant to mention I invoke the function
from the client through ajax:

--
var xhr = new XMLHttpRequest();
xhr.open('POST', "?"+post_url);
xhr.onload = function() {
// do something with the data returned
};
xhr.send(formData);
--

where post_url is the name of the function generated by Lift.


> (You might want to use S.fmapFunc too [which is basically
> just a convenience method over the code above]).

The thing is I need the name later so S.fmapFunc doesn't quite cut it :)

Peter Brant

unread,
Apr 6, 2012, 12:29:28 PM4/6/12
to lif...@googlegroups.com
ResponseShortcutException.shortcutResponse returns the exception. You
still have to throw it yourself.

Pete

Mads Hartmann Jensen

unread,
Apr 6, 2012, 12:38:10 PM4/6/12
to lif...@googlegroups.com
Okay, that actually gets the job done! It feel like it's a bit
hacky though; throwing an exception when things goes
well I mean :)

Mads Hartmann Jensen

unread,
Apr 6, 2012, 12:39:33 PM4/6/12
to lif...@googlegroups.com
I tried this for a bit - wasn't able to get it to do what I wanted. I tried adding it
to LiftRules.earlyResponse LiftRules.dispatch but it seems that it didn't get
invoked in either case

Antonio Salazar Cardozo

unread,
Apr 6, 2012, 1:21:27 PM4/6/12
to lif...@googlegroups.com
I don't know if earlyResponse would have the SessionVar set? But it seems like dispatch should work as long as it's prepended to the list so it always gets hit before other dispatches. Not sure if Lift's own SiteMap handling happens before dispatch runs though.
Thanks,
Antonio
Reply all
Reply to author
Forward
0 new messages