I have a Java client that calls a RESTEasy (JAX-RS) Java server. It is possible that some of my users may have a newer version of the client than the server.
That client may call a resource on the server that contains query parameters that the server does not know about. Is it possible to detect this on the server side and return an error?
I understand that if the client calls a URL that has not been implemented yet on the server, the client will get a 404 error, but what happens if the client passes in a query parameter that is not implemented (e.g.: ?sort_by=last_name)?
Is it possible to detect this on the server side and return an error?
Yes, you can do it. I think the easiest way is to use #Context UriInfo. You can obtain all query parameters by calling getQueryParameters() method. So you know if there are any unknown parameters and you can return error.
but what happens if the client passes in a query parameter that is not implemented
If you implement no special support of handling "unknown" parameters, the resource will be called and the parameter will be silently ignored.
Personally I think that it's better to ignore the unknown parameters. If you just ignore them, it may help to make the API backward compatible.
You should definitely check out the JAX-RS filters (org.apache.cxf.jaxrs.ext.RequestHandler) to intercept, validate, manipulate request, e.g. for security or validatng query parameters.
If you declared all your parameters using annotations you can parse the web.xml file for the resource class names (see possible regex below) and use the full qualified class names to access the declared annotations for methods (like javax.ws.rs.GET) and method parameters (like javax.ws.rs.QueryParam) to scan all available web service resources - this way you don't have to manually add all resource classes to your filter.
Store this information in static variables so you just have to parse this stuff the first time you hit your filter.
In your filter you can access the org.apache.cxf.message.Message for the incoming request. The query string is easy to access - if you also want to validate form parameters and multipart names, you have to reas the message content and write it back to the message (this gets a bit nasty since you have to deal with multipart boundaries etc).
To 'index' the resources I just take the HTTP method and append the path (which is then used as key to access the declared parameters.
You can use the ServletContext to read the web.xml file. For extracting the resource classes this regex might be helpful
String webxml = readInputStreamAsString(context.getResourceAsStream("WEB-INF/web.xml"));
Pattern serviceClassesPattern = Pattern.compile("<param-name>jaxrs.serviceClasses</param-name>.*?<param-value>(.*?)</param-value>", Pattern.DOTALL | Pattern.MULTILINE);
Related
It is straightforward to put resource id into url if it is a int or long type. e.g.
GET files/123
But my problem is that my resource identifier is a path. e.g. /folder_1/folder_2/a.sh because the underlying implementation is a filesystem. So I can not put it as part of rest api url because it is conflict with url path.
Here's approaches what I can think of:
Put the path id as the request param. e.g.
GET files?path=/folder_1/folder_2/a.sh
Encode/decode the path to make it qualifier as part of url.
Introduce another int/long id for this resource in backend. And map it to the path. The int/long type resource id is stored in database. And I need to maintain the mapping for each CURD operation.
I am not sure whether approach 1 is restful, approach 2 needs extra encoding/decoding, and approach 3 needs extra work to maintain the mapping.
I wonder what is the best practice to design the rest api url for this kind of case.
Simple:
#GET
#Path("/files/{path:.+}")
#Produces({MediaType.TEXT_PLAIN})
public String files(
#PathParam("path") String path
) {
return path;
}
When you query files/test1/tes2 via url output is:
test1/tes2
Just put the path after a prefix, for example:
GET /files/folder_1/folder_2/a.sh
There isn't a conflict, since when the request path starts with your known prefix (/files/, in the above example), you know that the rest should be parsed as the path to the file, including any slashes.
Well, my experience designing "restful" APIs shows that you have to take into consideration future extensions of your API.
So, the guidelines work best when followed closely when it makes sense.
In your specific example, the path of the file is more of an attribute of the file, that can also serve as its unique ID.
From your API client's perspective, /files/123 would make perfect sense, but /files/dir1/file2.txt is debatable.
A query parameter here would probably help more, much like what you would do if you wanted to retrieve a filtered list of files, rather than the whole collection.
On the other hand, using a query parameter would also help for future extensions, since supporting /files/{path} would also mean conflicts when attempting to add sub-resources to your files endpoint.
For example, let's assume that you might need in the future another endpoint /files/attributes. But, having such an endpoint, would exclude any possibility for your clients to match a file named attributes.
I am creating HTTP request using Apache HTTP Client version 4.3.4. I see there are some classes like HttpGet,... and there is also a class BasicHttpRequest. I am not sure which one to use.
Whats the difference and which one should be used in which condition ?
BasicHttpRequest is provided by the core library. As its name suggests it is pretty basic: it enforces no particular method name or type, nor does it attempt to validate the request URI. The URI parameter can be any arbitrary garbage. HttpClient will dutifully transmit it to server as is, if it is unable to parse it to a valid URI.
HttpUriRequest variety on the other hand will enforce specific method type and will require a valid URI. Another important feature is that HttpUriRequest can be aborted at any point of their execution.
You should always be using classes that implement HttpUriRequest per default.
I was just browsing the 4.3.6 javadoc attempting to locate your BasicHttpRequest and was unable to find it. Do you have a reference to the javadoc of this class?
I would be under the impression that BasicHttpRequest would be a base class providing operations and attributes common to more than one HttpRequest. It may be extremely generic for extension purposes.
To the first part of your question, use HttpGet, HttpPost etc for their specific operations. If you only need to HTTP/GET information then use HttpGet, if you need to post a form or document body, then use HttpPost. If you are attempting to use things like the Head, Put, Delete method, then use the correspoding HttpXXX class.
I have code that contains several different DELETE methods, one of which takes a parameter, or at least ideally it would take a parameter. However when I make this request, either through CURL or through a web client, it doesn't work. The other DELETE requests function fine and I've hard-coded in the parameter that I want to pass just to see if the call works and it does. I've tried this with both PathParam and QueryParam and neither works. Here's how I'm using the PathParams, which I'm pretty sure is correct, QueryParams looks very similar so I don't want to post that too.
#DELETE
#Path("/byId/{id}")
public void deleteById(#PathParam("id") String id)
And then essentially the same thing for QueryParams but obviously the path is different
From what I understand a lot of RESTful APIs ignore any kind of request body with a DELETE request, or treat it as a PUT or POST. Is there any way around this? Basically I have a database that contains several objects and I need to delete one based on a unique identifier, to be passed in by the client. If there is no way around this is there some other way that I could do it?
Its possible that I'm missing something obvious here as I've only been using Jersey for a few weeks now and up to this point had never even heard of the concept of RESTful services.
You can send information to a RESTful service as either headers, path param, query param or message body.
If all the values go through as expected there is no problem with jax-rs/jersey. Now you need to debug the code and fix your implementation. jax-rs will only match a DELETE call with the DELETE http method you have implemented.
It is then your responsibility to actually perform a DELETE operation of the resource within the method. jax-rs or jersey is not going to complain if you do not DELETE or if you do some other action within the method.
I'm having two rest methods as follows
/objects/(int:type)/(id:objectID)/(ver:version)
/objects/(int:type)/(id:objectID)/(str:version)
if i send the request as like the following URI
http://localhost/REST/objects/0/123/latest which of the above method gets called.
whether the 2 methods are same or different.
need to know what are all the parameter types available and what is the actual usage of each type.
And how the URI identifies the exact method
That question is all about the server framework you are using and nothing about REST. REST says nothing about URI structure, and certainly nothing about how URIs are mapped to handlers.
I created a page called api.aspx
I am displaying my output using a JSON serialize.
Each type of function is based on query string. For example:
If Request.QueryString("action") = "getMember"
Then from there, I do a
Request.QueryString("memberid")
For the variable I required for my function to work. Lastly the output is displayed as JSON.
In REST, there should be no verbs in the URI, especially no things such as ?action=getMember. The core REST principle is HATEOAS - which says that the state of the application is represented by the state of its resources.
Furthermore, the application should use a uniform interface - that is, use the standard HTTP methods POST, GET, PUT and DELETE for CRUD operations respectively.
So, such a member resource from your example should be accessed via GET request to a URI such as:
http://example.com/api/member/{memberId}
Where {memberId} is path parameter that represents the memberId.
I would say it's not restful since the url scheme is depending on query string parameters. For a real restful API the url's shoud be http://asite/member/2 and not be named.
If you want to make your api truly restful, use the URL routing from ASP.NET MVC, it's possible to integrate with webforms.