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())
Related
I am using refined for my requests in order to ensure that the request body confronts to certain specs, such as
case class NewGenreRequest(
name: GenreNameParam,
parent: Option[GenreParentParam]
)
where
type GenreNameString = String Refined MinSize[3]
When the request body sends something with 2 characters, this results in the error Predicate taking size(me) = 2 failed: Predicate (2 < 3) did not fail.: DownField(name) in the response body. However I think this isn't the best error to return to the client.
I would like to find a way to customize this response. The logical thing to try was to write a middleware
def handleErr(resp: Response[F]): Response[F] =
resp match {
case Status.BadRequest(resp) =>
logger.info("HERE IS MY ERR")
resp.????
case _ =>
resp
}
However I need to extract the info regarding which field has failed the predicates. The response body is an fs2 Stream and I am not quite sure about how to go about effectively modifying it using the existing info in the body. I tried maping it but to no result.
Is there an easy way of modifying these error messages?
P.S.: Cross posting from http4s discord as I wasn't able to get an answer
I have problem extracting form parameters (in body) from POST with Unfiltered.
From http://unfiltered.databinder.net/Within+the+Parameters.html I understood that Params(p) would put into p both url parameters and also form parameters inside body. But I just can't get form parameters in body.
Of course I could take body as string and build parser for that, but it would just be silly as would expect there would be something ready for such basic operation ...but I just can't find it.
My service is following and it prints out any parameters from url but not form-data parameters, if I use x-www-form-urlencoded then it seems to works.
def intent {
case POST(ContextPath(_, Seg("accounts" :: "providers" :: AsLong(id) :: "mfa" :: Nil)) & Params(params)) ⇒
println(s"${params.mkString("\n")}")
Ok
}
Must be a syntax issue on my part, but can't quite pin it:
In my controller I have this defined:
request.format match {
case "json" => Json(output)
case "xml" => toXml(parse(output.toString))
case _ => BadRequest
}
And in my routes I have this defined:
# Map the API to the proper domain
GET /{key}/{action}/{param}.{format} API.{action}
POST /{key}/{action}/{param}.{format} API.{action}
I posted something like: /34523452345/job/today.json
So when I go to actually run the request, it takes {param} and includes the period. So the result for {param} is today.js and the {format} becomes on
The catch if I switch the period to a forward slash / it works just fine
What is the cause of the problem?
I believe you have to escape the dot as in \., as Play uses regexp in the routes files.
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.
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.