Asterisk in Java Play MVC Framework's Routes File - java

I've inherited a project in the Play Framework. I'm in the process of modifying the conf/routes file and was wondering why asterisks were used instead of the normal HTTP methods as described in the documentation here:
http://www.playframework.com/documentation/2.0/JavaRouting
Here's and example of what I mean:
# Top level pages
GET /how-tradjenta-works Application.about
GET /prescription-savings-card SavingsCard.index
* /prescription-savings-card/qualify SavingsCard.qualify
As you can see, the third route definition has that asterisk. What gives?

Its the request type to serve for the route, GET, POST, or either/both (*). It lets you specify a different route for the same url based on the request type. For example you could set a different controller action on post for the same URI.

If you look at an older version of the doc:
http://www.playframework.com/documentation/1.0/routes
you'll see it says:
If you specify * as method, this route will match the HTTP Request for
any methods.

Related

Multiple content-types for request in webservice

I have one webservice which can take multiple content-types in request
text/plain
application/json
Now, client can send any of them either json or text.
I have two options available on server
I can create separate apis for different content types
I can parse request data and check if its json or text?
What is better approach here?Is there a design pattern suited for this need?
Note: Management prefer to have one api which can support multiple content-types.
The client must include a Content-Type header indicating the format of the entity they are sending to the server. If the server does not support the format which a client has sent, the expected response is 415 Unsupported Media Type.
I would go with option 1 and have the common logic placed in a seperate method. That way you let the API check and parse the input data for you.
In http you use the "accept"- header to define what type you expect the response to be. The server delivers the content as defined in accept header, the default if it's not set or 406 - "Not acceptable" if the type is not supported
https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
One way would be to use #Path annotations more thoroughly-
The #javax.ws.rs.Path annotation must exist on either the class and/or a resource method. If it exists on both the class and method, the relative path to the resource method is a concatenation of the class and method.
See this link https://docs.jboss.org/resteasy/docs/1.1.GA/userguide/html/Using__Path_and__GET___POST__etc..html

Can you specify preferred default media type for a single path in Spring MVC?

I have a Jersey application which has been converted to Spring MVC. One piece of functionality that I don't see a way to port directly over is the ability, per path, to specify the preferred media type if none is specified. In Jersey, I could specify the "qs" property on the media type, and it would use that to determine which response type to send if none were specified (or if multiple options were specified in the Accept header, I believe this value was multiplied by the quality scores specified).
#Produces("application/json")
#GET
#Path("/some/path")
public Response preferredResponseType() {
//Implementation goes here
}
#Produces({"application/schema+json;qs=0.9"})
#GET
#Path("/some/path")
public Response otherResponseType() {
//Implementation goes here
}
In this example, if I do a GET request against /some/path with no Accept header, it will return the application/json response.
I don't see any easy way to do this in Spring MVC, particularly not if I want to restrict the default to applying to just that one endpoint (there are other endpoints in the app that should have a different preferred default). I do see that there is a way to globally set a default content type (per the "defaultContentType" and "defaultContentTypeStrategy" methods in ContentNegotiationConfigurer), but that does not easily address the per-path use case.
Is there an easy way to achieve per-path media type defaults different from the application global default?
Spring issue 19050 requests this functionality. Per the conversation there, it looks like there is no simple way to declaratively specify the default content type to use. Furthermore, the Spring team has closed the issue with a decision not to implement this functionality.
The "defaultContentTypeStrategy" allows to provide your own ContentNegotiationStrategy to use. It has access to the full request so you can make path based decisions possibly with the an AntPathMatcher to support patterns easily.

Play framework route parameter authorization

I have REST api on my page and for authentication I use the Play session.
Problem is with authorization, I have tens of endpoints looking like this:
GET /api/domains/:domainId/properties/:propertyId/reports
I could add and if statement on each controller method to check whether user has permissions to that domain or property, but can I handle it somehow globally?
I found this module, but it does not seem to handle parameters, just checks if user is in some group/role or not. https://www.playframework.com/documentation/1.0.2.1/secure
I solved this using a custom RequestHandler. There you can extract parameters from the path and validate them. (In scala I could even modify the request route in order to avoid repeating these parameters in all routes, I don't know if you can do it in java too).
(See:
https://www.playframework.com/documentation/2.4.x/JavaHttpRequestHandlers)
You can use the Security.Authenticated annotation as detailed here. For more specific permissions, I recommend Deadbolt

Jersey resource that matches any path

I am using Jersey v1.x and a Guice Servlet.
What I'm trying to do is bind a Jersey Resource that matches any #Path, such that I can use Jersey to respond with a 404.
I'm looking to do this, since my servlet consists of different components (e.g. a rest API that lives under /api, and a web UI that lives under /.
In Guice terms, that means I have several ServletModules that each set up one part of the servlet:
In my ApiServletModule: serve("/api").with(GuiceContainer.class, conf)
In my WebUiServletModule: serve("/").with(GuiceContainer.class, conf)
In this setup, I want to define what the 404 response body looks like for each part of the webapp (/api or /) from the codebase of each subproject responsible, without having to reimplement Jersey
So far I have tried to bind a resource that match #Path("/"), #Path("*") and #Path("/*"), but none of these seem to be picked up when I request /some/path/that/doesnt/exist
You need to use the regex format of the path expression, i.e.
#Path("{any: .*}")
You could inject List<PathSegment> to look at all the segments if you need them.
public Response getSomething(#PathParam("any") List<PathSegment> segments)
#peeskillet's answer is indeed correct, in the sense that it describes how you can create a Jersey resource that matches any path.
However, my goal of creating a resource that delivers 404 responses for whenever any other unmatched path is requested is not quite met by this answer:
At least in combination with Guice, will such a "match all"-resource intercept all requests, regardless of whether any more specific resources are available. Additionally, you cannot modify the HTTP response status code from within a resource.
For this purpose, Jersey has ExceptionMappers that can be implemented and loaded by adding the #Provider annotation. One particular type would be a ExceptionMapper<NotFoundException>, which is invoked when a Resource throws a NotFoundException. The ExceptionMapper can then decide what response to generate, including the status code.

Playframework routes question

I have this in my applcation routes file:
GET /new Tweets.create
POST /new Tweets.save
And in my view I'm creating a form like this:
#{form #save()}
...
#{/form}
But once is submit the form it's sending me to /tweets/save and not to /new. Any ideas how I can fix this? Thanks!
If you have already tried the route below (which is the correct way to use routes)
#{form #Tweets.save()}
and this did not work, I think you may have put your route in the wrong place. Make sure it is at the top of the routes file, and not after the catch-all route. The routes file is processed in order, so if the catch-all is found, this is used first and your other route is ignored. The catch-all looks like
* /{controller}/{action} {controller}.{action}
Try using
#{form #Tweets.save()}
I think it is suggested to use class names with method names.
EDIT:
The way the play framework routing works is you define some route as
GET /clients Clients.index
If a request encountered with URI /clients then it will be intercepted to Clients.index(). If you have another routing such that
GET /clients Clients.save
Then the framework ignores this routing because /clients aready has a mapping. (Most probably it is giving some error in the console or logging stream, check your logs.)
Therefore you can't make it work like that. I see, you request a reverse mapping that will return the same URI for different methods. However the framework aims to intercept requests so that it will simply ignore your second routing.
Try to separate pages. Most probably what you want is to render the same views for two functions. You can do that without redirecting them to the same URI.
I think (if I did not misread) that the issue is you expecting the wrong behavior.
As I understand you expect that the submit will go to Tweet.save() (POST method) and then back to Tweet.create() (GET method) as both share the same path (/new).
In reality Play is calling Tweet.save() and it expects a render at the end of Tweet.save() to display some result. If you want to redirect to Tweet.create() you can do a call to that method at the end of the implementation of Tweet.save(), with either:
create(<params>);
or
render("#create", <params>);
and that should redirect (via 302) to the GET version.

Categories

Resources