Using the Sitemap, one can set certain paths to work on prefix matching, and allow requests for subpaths to be served. I'd like to specify that all requests below the given path go to a certain template. So I would like:
Menu(Loc("show_theme", Link("show" :: "theme" :: Nil, true, "/show/theme"), "Show Theme") )
to catch all requests to /show/theme/* (which it does), but serve them using the template at /show/theme (which it doesn't)
I want (e.g.) /show/theme/1 to use the template at /show/theme, and the snippets within that to pull the id out of the Req.
Is this possible? Or am I doing things the wrong way? At the moment, I'm using /show_theme?theme=1, but this is a bit ugly, and makes working with forms difficult
EDIT: I'm trying to get away from using CGI params to encode IDs, and keep them as part of the path structure
A Loc represents one page and one template. If you want to map multiple URLs to the Loc than you'll want to use Lift's URL rewriting. For example:
LiftRules.statefulRewrite.append {
case RewriteRequest(ParsePath("show" :: "theme" :: theme :: Nil, _, _, _), _, _) =>
RewriteResponse(ParsePath("show_theme" :: Nil, "", true, false), Map("theme" -> theme), false)
}
What that will do is match requests to /show/theme/* and rewrite them to /show_theme?theme={theme}. You them create your Loc to respond to that URL and you access the theme variable as a query parameter (S.param("theme")).
Note: You can do this more concisely by using the Loc DSL but I think it's good to understand what is going on behind the scenes.
If you need more help I would suggest you post a message to the Lift Google Group. I think you'll find quicker answers there than you will on SO.
Related
i am trying to define an Endpoint with param in the middle.
something similar to:
get("foo" :: param("id") :: "goo")
so, i can call it with the following rest call:
http://mydomain/foo?id=99/goo
but, for some reason, it doesn't work.
any idea ?
thanks,
Eran.
In your get("foo" :: param("id") :: "goo") handler, this "foo" :: param("id") :: "goo" is is called route path.
And this param("id") is actually a path-parameter and not a query-parameter.
Standard URL scheme looks like following,
scheme:[//[user[:password]#]host[:port]][/path][?query][#fragment]
path-parameters are actually not part of standard URL scheme but are extracted from path part of URL using regular expression matching by modern http frameworks.
So... you need to access it with http url - http://mydomain/foo/99/goo
Hi I'm building REST api for an app, I have a requirement in URL
such that url should be something like this e.g
www.abc.com/api/param1/value1/param2/value2/param3/value3.... and so on
There are cases
case: The number of params are not limited it can change frequent
if today it is something like this
www.abc.com/api/param1/value1/param2/value2/param3/value3
tomorrow it can be like this
www.abc.com/api/param1/value1/param2/value2/param3/value3/param4/value4
Is there a configuration where once you configure the url pattern
and every thing go smooth
and in conrtoller params should contain this kind of key-value pair
{ "param1" => "value1","param2" => "value2","param3" => "value3"...and so on }
any suggestion !! how to achieve this ??
If your params are not fixed you can use wildcard in routing
for e.g
get 'items/list/*specs', controller: 'items', action: 'list'
def list
specs = params[:specs] # e.g, "base/books/fiction/dickens" #split it and place in a hash
end
Rails routing provides a way to specify fully custom routes with static and dynamic segments as explained in the Rails Routing Guide.
Your requirement should be achievable with
get '/api/param1/:param1/param2/:param2/...', to: 'controller#action'
You can use route scoping for this particular kind of problem . In other way it is nested routes
More details : http://guides.rubyonrails.org/routing.html#nested-resources
This is a example,
GET /magazines/:magazine_id/ads/:id/edit ads#edit
return an HTML form for editing an ad belonging to a specific magazine
I think this would be helpful for you.
I use Scala and Lift for REST web-services and I have a method that generates dynamic jpg images that should be made accessible via a Get Request, so that for each Get-Request the method generates an image again and sends it back in the response.
I made a case in serve:
case "img.jpg" :: Nil Get _ => Full(OkResponse())
case _ => Full(NotFoundResponse())
But this case does not seem to be recognised, it always catches the Default-Case.
What is the proper way to serve routes on a . url? And what response type can be used to deliver the jpg?
The file extension is handled separately from the rest of the path, so matching as you do above won't work. You can see some more discussion about this in the Lift Cookbook.
To make the above work, you should be able to do this:
case "img" :: Nil Get req if req.path.suffix == "jpg" => Full(OkResponse())
I believe you can also use the Req object, which will let you specify the suffix like this:
case Req("img" :: Nil, "jpg", GetRequest) => Full(OkResponse())
My web application will be triggered from an external system. It will call one request path of my app, but uses different query parameters for different kinds of requests.
One of the parameters is the "action" that defines what is to be done. The rest of the params depend on the "action".
So I can get request params like these:
action=sayHello&user=Joe
action=newUser&name=Joe&address=xxx
action=resetPassword
...
I would like to be able to encode it similarly in the routes file for play so it does the query param based routing and as much of the validation of other parameters as possible.
What I have instead is one routing for all of these possibilities with plenty of optional parameters. The action processing it starts with a big pattern match to do dispatch and parameter validation.
Googling and checking SO just popped up plenty of samples where the params are encoded in the request path somehow, so multiple paths are routed to the same action, but I would like the opposite: one path routed to different actions.
One of my colleagues said we could have one "dispatcher" action that would just redirect based on the "action" parameter. It would be a bit more structured then the current solution, but it would not eliminate the long list of optional parameters which should be selectively passed to the next action, so I hope one knows an even better solution :-)
BTW the external system that calls my app is developed by another company and I have no influence on this design, so it's not an option to change the way how my app is triggered.
The single dispatcher action is probably the way to go, and you don't need to specify all of your optional parameters in the route. If action is always there then that's the only one you really need.
GET /someRoute controller.dispatcher(action: String)
Then in your action method you can access request.queryString to get any of the other optional parameters.
Note: I am NOT experienced Scala developer, so maybe presented snippets can be optimized... What's important for you they are valid and working.
So...
You don't need to declare every optional param in the routes file. It is great shortcut for type param's validation and best choice would be convince 'other company' to use API prepared by you... Anyway if you haven't such possibility you can also handle their requests as required.
In general: the dispatcher approach seems to be right in this place, fortunately you don't need to declare all optional params in the routes and pass it between actions/methods as they can be fetched directly from request. In PHP it can be compared to $_GET['action'] and in Java version of Play 2 controller - DynamicForm class - form().bindFromRequest.get("action").
Let's say that you have a route:
GET /dispatcher controllers.Application.dispatcher
In that case your dispatcher action (and additional methods) can look like:
def dispatcher = Action { implicit request =>
request.queryString.get("action").flatMap(_.headOption).getOrElse("invalid") match {
case "sayHello" => sayHelloMethod
case "newUser" => newUserMethod
case _ => BadRequest("Action not allowed!")
}
}
// http://localhost:9000/dispatcher?action=sayHello&name=John
def sayHelloMethod(implicit request: RequestHeader) = {
val name = request.queryString.get("name").flatMap(_.headOption).getOrElse("")
Ok("Hello " + name )
}
// http://localhost:9000/dispatcher?action=newUser&name=John+Doe&address=john#doe.com
def newUserMethod(implicit request: RequestHeader) = {
val name = request.queryString.get("name").flatMap(_.headOption).getOrElse("")
val address = request.queryString.get("address").flatMap(_.headOption).getOrElse("")
Ok("We are creating new user " + name + " with address " + address)
}
Of course you will need to validate incoming types and values 'manually', especially when actions will be operating on the DataBase, anyway biggest part of your problem you have resolved now.
Hi I'm having some trouble with Lift and URL rewriting. I've written a simple rewrite rule:
LiftRules.rewrite.append {
case RewriteRequest(
ParsePath(List("user", userID), _, _, _), _, _) => {
println(userID)
RewriteResponse(List("viewUser"), Map("userID" -> urlDecode(userID)))
}
}
So when I enter http://localhost:8080/user/brian I expect a call to be made to the viewUser.html file I have placed in the webroot directory.
The mark up of viewUser.html is very simple:
<lift:surround with="default" at="content">
<p>ViewUser</p>
</lift:surround>
But instead of seeing viewUser I get an error:
The Requested URL /user/brian was not found on this server
Also if I enter the URL of viewUser by hand: http://localhost:8080/user/brian I get the same error.
I am out of ideas on this one, I did find a similar error which happens through the SiteMap system.
I've tried this with a cleanly checked out lift-archetype-blank project, by adding the viewUser.html and adding the single chunk of rewrite code.
Make sure you've added "viewUser" to the site map. Without doing so Lift doesn't know where to find page.