I'm constructing a restful service which needs to accept any number of parameters instead of the one from the sample below.
Assuming the following service routine
#RequestMapping("/start/id/{id}", RequestMethod.GET)
public void startService(#PathVariable String id) {...}
there's a client implementation based on RestTemplate
restTemplate.getForObject("/start/id/{id}", null, id);
Question: But given that it might be thousands of ids, what restful approaches do I have to sending all parameters in one request using RestTemplate? I've seen the suggestions
Add request body to GET request - Doesn't seem possible with RestTemplate?
Use a separator in id, (e.g., id1|id2|....|idn) - Seems like a hack
PUT the parameters first, then issue a GET to reference the ids - Double requests, seems non-intuitive
Adding multiple URL parameters (?id=foo&id=bar&.....&id=foobar)
I know similar questions (calling-a-restful-service-with-many-parameters, how-to-create-rest-urls-without-verbs, can-you-build-a-truly-restful-service-that-takes-many-parameters) has been asked before but I found it hard to spot a satisfactory answer, or at least an answer based on RestTemplate.
I don't think any part of RESTful design states that your url structure should be able to resolve entire collections. Your first (request parameter) and third (url parameter) suggestions are likely the best.
I would recommend the first. I'm sure its allowed in resttemplate. Looking at the documentation you provided, just implement one of the post methods. Each of them takes the request as a parameter. Inside there, I'm sure there is some kind of implementation of a getRequestParameters() method you can use to parse json/xml from the request body containing your ids.
Or, even better, how are all of these id's related? Do they all have a common parent resource? If so, then you could (and probably should) do something like...
/commonparent/{parentId}
And then inside your request handler, query for all of the ids, and procede like normal.
You could use a query parameter for all the ids:
/search?ids=1,2,3,4,5,6,7
Then tokenize by the comma and do your search. Remember that you will be capped by the maximum URL length if you issue this as a GET query string parameter.
Related
I am using a Filter to detect some api operations and do some validation work. what is the normal way to get which api operation is currently called using HttpServletRequest? Right now, I am doing something like this :
if (httpRequest.getMethod().equalsIgnoreCase("GET")
&& httpRequest.getRequestURI().toLowerCase().contains("expectedOperatinName"))
to check if it is the expected api call. However,
it is not a smart way to do that to me
more importantly, how does it distinguish btw list and get a single
Please help. Thanks
Did you look into the UriInfo interface that has methods on which resource matched the passed in request? You can access the UriInfo from the request like this:
containerRequestContext.getUriInfo()
I think you can easily find out which operation was honored using getMatchedResources() on the UriInfo. If you are trying to find the exact method that honored the request, look into UriRoutingContext class.
I am building a REST API using JAX-RS. In angular front-end, I am sending the object to be deleted in the body of the HTTP request (JSON format). Now I need a way to map this HTTP DELETE body request which is containing the object that needs to be deleted to a local variable in the REST method.
For instance, on SPRING I did this by simply annotating an object variable with #RequestBody.
I was checking oracle's javaEE7 docs but the examples there are really basic and don't include complex objects, also the different tutorials that I found elsewhere were on the track of simple delete requests mapping a simple id with #PathParam.
Maybe before this question, the first question I should ask is whether sending the object in an HTTP's request body is at all a good approach? I was reading some articles which designated it as not such a good practice, although it is not explicitly forbidden. What would be the disadvantages of this approach?
I remember while I was researching about this method in SPRING, I read somewhere that malicious attacks could be possible by specially crafted user inputs (the persistence framework that I am using is JPA, EclipseLink).
Would it perhaps be better to map the primary key on a series of #Path variables and then map them using #PathParam?
So to sum up, first of all, is this a good approach?
And how can I read the object in the HTTP's request body?
Some pointers would be highly appreciated!
Unlike Spring MVC, JAX-RS does not define any annotation for the request payload.
The JAX-RS approach is slightly different: the value of the parameter not annotated with any #***Param annotations is mapped from the request entity body. Such parameter is called entity parameter.
The first question I should ask is whether sending the object in an HTTP's request body is at all a good approach?
Please refrain from doing that, as it's not how DELETE is supposed to work.
Find below a quote from the RFC 7231, the document that currently defines the semantics and content of the HTTP/1.1 protocol:
A payload within a DELETE request message has no defined semantics; sending a payload body on a DELETE request might cause some existing implementations to reject the request.
For interoperability, I advise you to stick to the standards as much as you can. And you definitely shouldn't be require to send any payload to identify the resource to be deleted.
Its primary key is 8 fields long.
The URI, which stands for Universal Resource Identifier, is meant to identify a resource.
As you have a bunch of fields that, in conjunction, identify a resource, I advise you to rethink your application design. You could, for example, introduce some sort of unique value to identify your resources. Have a look at UUID.
With JAX-RS you don't need a something like a #RequestBody.
You can simply add the class as parameter and it will be filled with the request body.
In you case passing the data in the body makes sense but how does your URL look like? As with REST you should have resources that are addressable by a URL
In my Rest application, the resource url also support query parameters like pageSize, pageNum , name etc. So the request url looks like
/resource/{id}?pageNum=1&pageSize=25&desc="hello"
Now suppose a client adds an extra query parameter say 'lang' which my server is not supporting like
/resource/{id}?pageNum=1&pageSize=25&desc="hello"&lang="eng" , but my server doesnt support any lang parameter.
what should be the best design decision
Option 1 : Ignore the extra invalid queryparam and serve the request.
Option 2 : Throws bad request message to the client.
Thanks in Advance
Singla
No Doubt that clients must stick to the Api docs.
But what about certain changes in the APis ( just a small changes which does not involve migrating to a new API version )
Like say, an API resource : /dummy/api/Iid1 supports 3 query parameter, namely, a, b, c
so the complete URi : /dummy/api/Id1?a=1&b=20&c=45 is a valid request exposed by the API, and all the query params i.e a, b, c are optional params,
i.e if these params are not present in the request, then the server processes them to some default value like a = 0, b = 0, c= 0
Over sometime, a large number of clients build their application based in the above URL scheme.
Now the API provider, wants to scrap off the parameter 'b' and decides to throw off exception on extra/unknown parameters
This would , mean that all the clients application build around the last URL scheme that involved parameter 'b' would fail !
This simply suggests that, throwing exceptions for extra/unknown query parameters, invariably, leads to a tight coupling of client and server concerns, which I guess, completely goes against
the REST principles, which probably has a central theme to 'completely separte client and server concerns, so that both can evolve separately'
So I think only the missing/invalid 'mandatory' params should throw an exception, and not the options ones, never.
Just ignore it. Most other web servers would ignore request parameters it didn't understand.
Google ignore my two extra parameters here
https://www.google.com/#q=search+for+something&invalid=param&more=stuff
I guess ignoring bad parameters is standard practice, but it seems totally wrong to me in many cases.
Say I have a widget API with a widgets collection endpoint that finds widgets. Widgets have a foo attribute, so the following searches for widgets where foo = bar
GET https://example.com/widgets?foo=bar
Now an API client makes a typo.
GET https://example.com/widgets?foi=bar
Instead of returning only widgets where foo = bar, the typo is silently ignored and all widgets are returned (properly limited to some default size because I make well-designed API). My API client could spend hours trying to figure out why her call isn't working, or more likely light up my support site wondering why my API sucks.
Isn't it better to return a 400 status with an error message stating that "foi" is not a recognized parameter? This seems especially true because for the same kind of typo in a request body the best behavior is to return 400. (For example, see this answer: https://stackoverflow.com/a/20686925/2716301)
Ignoring it is common pattern, but query parameters are also part of URL (the resource id) and proper response code on this kind of request is 404 Not Found.
There is no general design pattern. You have to ask yourself what is best for your users. Is better to tell them that the resource they are asking is not available in the format they required or just give them another resource?
Note
HTTP contains great mechanism for dealing with languages; see Accept-Language and Content-Language headers (all browsers are using it)
This must have been answered previously, but my Google powers are off today and I have been struggling with this for a bit. We are migrating from an old PHP base to a Jersey-based JVM stack, which will ultimately provide a JSON-based RESTful API that can be consumed from many applications. Things have been really good so far and we love the easy POJO-to-JSON conversion. However, we are dealing with difficulties in Cross-Domain JSON requests. We essentially have all of our responses returning JSON (using #Produces("application/json") and the com.sun.jersey.api.json.POJOMappingFeature set to true) but for JSONP support we need to change our methods to return an instance of JSONWithPadding. This of course also requires us to add a #QueryParam("callback") parameter to each method, which will essentially duplicate our efforts, causing two methods to be needed to respond with the same data depending on whether or not there is a callback parameter in the request. Obviously, this is not what we want.
So we essentially have tried a couple different options. Being relatively new to Jersey, I am sure this problem has been solved. I read from a few places that I could write a request filter or I could extend the JSON Provider. My ideal solution is to have no impact on our data or logic layers and instead have some code that says "if there is a call back parameter, surround the JSON with the callback, otherwise just return the JSON". A solution was found here:
http://jersey.576304.n2.nabble.com/JsonP-without-using-JSONWithPadding-td7015082.html
However, that solution extends the Jackson JSON object, not the default JSON provider.
What are the best practices? If I am on the right track, what is class for the default JSON filter that I can extend? Is there any additional configuration needed? Am I completely off track?
If all your resource methods return JSONWithPadding object, then Jersey automatically figures out if it should return JSON (i.e. just the object wrapped by it) or the callback as well based on the requested media type - i.e. if the media type requested by the client is any of application/javascript, application/x-javascript, text/ecmascript, application/ecmascript or text/jscript, then Jersey returns the object wrapped by the callback. If the requested media type is application/json, Jersey returns the JSON object (i.e. does not wrap it with the callback). So, one way to make this work is to make your resource method produce all the above media types (including application/json), always return JSONWithPadding and let Jersey figure out what to do.
If this does not work for you, let us know why it does not cover your use case (at users at jersey.java.net). Anyway, in that case you can use ContainerRequest/ResponseFilters. In the request filter you can modify the request headers any way you want (e.g. adjust the accept header) to ensure it matches the right resource method. Then in the response filter you can wrap the response entity using the JSONWithPadding depending on whether the callback query param is available and adjust the content type header.
So what I ultimately ended up doing (before Martin's great response came in) was creating a Filter and a ResponseWrapper that intercepted the output. The basis for the code is at http://docs.oracle.com/cd/B31017_01/web.1013/b28959/filters.htm
Essentially, the filter checks to see if the callback parameter exists. If it does, it prepends the callback to the outputted JSON and appends the ) at the end. This works great for us in our testing, although it has not been hardened yet. While I would have loved for Jersey to be able to handle it automatically, I could not get it to work with jQuery correctly (probably something on my side, not a problem with Jersey). We have pre-existing jQuery calls and we are changing the URLs to look at the new Jersey Server and we really didn't want to go into each $.ajax call to change any headers or content types in the calls if we didn't have to.
Aside from the small issue, Jersey has been great to work with!
I am creating a web application that incorporates REST-style services and I wanted some clarification as to the preferred (standard) method of how the POST requests should be accepted by my Java server side:
Method 1:
http://localhost:8080/services/processser/uid/{uidvalue}/eid/{eidvalue}
Method 2:
http://localhost:8080/services/processuser
{uid:"",eid:""} - this would be sent as JSON in the post body
Both methods would use the "application/json" content-type, but are there advantages, disadvantages to each method. One disadvantage to method 2, I can immediately think of is that the JSON data, would need to be mapped to a Java Object, thus creating a Java object any time any user access the "processuser" servlet api. Your input is much appreciated.
In this particular instance, the data would be used to query the database, to return a json response back to the client.
I think we need to go back a little from your question. Your path segment starts with:
/services/processuser
This is a mistake. The URI should identify a resource, not an operation. This may not be always possible, but it's something you should strive for.
In this case, you seem to identify your user with a uid and an eid (whatever those are). You could build paths such as a user is referred to by /user/<uid>/<eid>, /user/<uid>-<eid> (if you must /user/uid/<uid>/eid/<eid>); if eid is a specialization, and not on equal footing with uid, then /user/<uid>;eid=<eid> would be more appropriate.
You would create new users by posting to /user/ or /user/<uid>/<eid> if you knew the identifiers in advance, deleting users by using DELETE on /user/<uid>/<eid> and change state by using PUT on /user/<uid>/<eid>.
So to answer your question, you should use PUT on /user/<uid>/<eid> if "processuser" aims to change the state of the user with data you provide. Otherwise, the mapping to the REST model is not so clean, possibly the best option would be to define a resource /user/process/<uid>/<eid> and POST there with all the data, but a POST to /user/process with all the data would be more or less the same, since we're already in RPC-like camp.
For POST requests, Method 2 is usually preferred, although often the resource name will be pluralized, so that you actually post to:
http://localhost:8080/services/processusers
This is for creating new records, however.
It looks like you're really using what most RESTful services would use a GET request for (retrieving a record), in which case, Method 1 is preferred.
Edit:
I realize I didn't source my answer, so consider the standards set by Rails. You may or may not agree that it is a valid standard.