I have a resource that has a public and a private response, and only some users in determinant situations can access the private response.
What would be the best implementation?
Two urls, one for the public and another for the private: resource/{id} and resource/{id}/private.
Same url, different response for each user: resource/{id}.
Same url with and a parameter that different the public and private: resource/{id}?private=true.
Other?
Your terminology is a little mixed up. You have one resource, and multiple representations. The resource should have one canonical location (URL). It's perfectly fine for different users to get different representations based on their auth level.
If you want a user to be able to request a specific representation of the resource, you have a couple of options. If you're using custom MIME types, the Accept header would be the best choice. A query parameter is your best bet if you're not using custom MIME types, but make sure it's something generic and consistent throughout the application. Don't just use ?private=true, but instead use something like ?representation=public. That allows you to add representations later and use the same parameter, and share the same query parameter with other resources that need to specify a representation. You should avoid using a separate URL.
IMO one resource should have only one URL. You can make use of auth-token in HTTP to check if the server should respond with a private response or a public response. Also if some user is requesting for some unauthorized resource, you can send a 4xx status.
Thus resource/{id} seems like a good choice.
Related
I've set up an API in Spring where the client can specify the ids of the objects they want to receive. It returns a JSON list (using the #ResponseBody annotation) of the objects.
But, since the request can be a long list, I've set it up as a POST, where it's received as an object named ProductRequest (using the #RequestBody annotation). This seemingly isn't conformant to the official REST API standard, since posts are official to create new objects, but it seems better to implement it this way since you're not cluttering up the URL with a bunch of ids. Also, I can specify additional parameters customizing the output.
So my question is, can this be considered a valid RESTful design? Post isn't being used to create an object, so it's not strictly conformant to restful. Thoughts?
It is a simple GET request.
#GetMapping(path = "/your-url")
public List<Object> method(#RequestParam(name="ids") List<Long> objectIds) {
}
You can receive your list just as a simple java list.
/api?ids=1,2,3
You can very well do an http POST to "get" the resource(s). There are some very valid examples of doing so,
GraphQL -- All we are doing is sending (POSTing) some Queries in requestbody to "GET" some data in the format that we prefer
Assume that you have to authenticate with a username and password to get a specific data, you will either send it in Header in GET request or you will do a POST to 'GET' a data.
Couldn't that overflow the max allowable for the URL string?
Actually, there is no limitation on the length of a URI. However, practically, you can encounter some.
According to RFC7230 (emphasis mine),
HTTP does not place a predefined limit on the length of a request-line, as described in Section 2.5. A server that receives a method longer than any that it implements SHOULD respond with a 501 (Not Implemented) status code. A server that receives a request-target longer than any URI it wishes to parse MUST respond with a 414 (URI Too Long) status code.
Various ad-hoc limitations on request-line length are found in practice. It is RECOMMENDED that all HTTP senders and recipients support, at a minimum, request-line lengths of 8000 octets.
It clearly suggests that we can't rely on a request-line while we are dealing with your issue.
Can this be considered a valid RESTful design?
Due to the limitation mentioned above, using POST is a valid workaround.
As stated by this Wikipedia article,
The common workaround for these problems is to use POST instead of GET and store the parameters in the request body. The length limits on request bodies are typically much higher than those on URL length.
To completely free you from hesitation, there is a common non-standard header X-Http-Method-Override. It requests a web application to override the method specified in the request with the method given in the header:
X-Http-Method-Override: GET
I am not sure whether Spring handles the header. Though, it has the HiddenHttpMethodFilter filter which seems to do similar work.
I have some sensitive domain objects that I would like to convert to json and xml. I am using spring view resolution to do this, but that is beside the point.
I'd like to add annotations to the domain objects to specify which fields should be converted to xml / json.
Something like
#XmlRootElement
public class SensitiveDomainObject {
...
public String getPassword() {...}
#XmlAttribute
#JsonValue
public String getAccountName() {...}
#XmlAttribute
#JsonValue
public String getGoldMemberStatus() {...}
}
I want getAccountName() and getGoldMemberStatus() to be serialised to json and xml, but getPassword to never be serialised.
What I don't want is
1) Separate 'annotation placement strategies' for json and xml as that gets confusing if one needs to markup different methods in different ways as standard.
2) To be explicitly ignoring fields. This is because if some programmer comes along in the future and adds a newly sensitive field without including for example the #JsonIgnore annotation, suddenly that sensitive field is shared.
3) To have to make methods like getPassword() private. I still want to be able to call getPassword() internally.
Has anyone done this or have any thoughts?
EDIT
Included a picture from IBM showing essentially the design I ran with, with explicit DTOs with annotations in the business logic layer. The presentation layer figures out which DTO to request and serve based on the incoming URL.
If you care so much about differentiating what you your business classes are and what is transferred, you may consider implementing a separate package of DTO classes which will explicitly include only those properties you'd like to transfer.
In this case you'll have to explicitly include the transfer properties, this can't happen because the programmer forgot it.
There are other approaches to this like adding some validation rules that the property like password is ignored and enforce them on JAXB context level. But this will only work until someone not knowing will name it kennwort or credentials or whatever may come in mind and your validation rules will be out of effect.
So I see two way:
* Either you trust the programmer (and all the QA/QS process like code reviews etc.) to support her/him.
* Or you make your transfer classes explicit.
For important external interfaces I'd probably go with the second approach (explicit DTOs). If password ends up there, it can't be by forgetting, it will only be on purpose.
A REST API can have arguments in several places:
In the request body - As part of a json body, or other MIME type
In the query string - e.g. /api/resource?p1=v1&p2=v2
As part of the URL-path - e.g. /api/resource/v1/v2
What are the best practices and considerations of choosing between 1 and 2 above?
2 vs 3 is covered here.
What are the best practices and considerations of choosing between 1
and 2 above?
Usually the content body is used for the data that is to be uploaded/downloaded to/from the server and the query parameters are used to specify the exact data requested. For example when you upload a file you specify the name, mime type, etc. in the body but when you fetch list of files you can use the query parameters to filter the list by some property of the files. In general, the query parameters are property of the query not the data.
Of course this is not a strict rule - you can implement it in whatever way you find more appropriate/working for you.
You might also want to check the wikipedia article about query string, especially the first two paragraphs.
I'll assume you are talking about POST/PUT requests. Semantically the request body should contain the data you are posting or patching.
The query string, as part of the URL (a URI), it's there to identify which resource you are posting or patching.
You asked for a best practices, following semantics are mine. Of course using your rules of thumb should work, specially if the web framework you use abstract this into parameters.
You most know:
Some web servers have limits on the length of the URI.
You can send parameters inside the request body with CURL.
Where you send the data shouldn't have effect on debugging.
The following are my rules of thumb...
When to use the body:
When the arguments don't have a flat key:value structure
If the values are not human readable, such as serialized binary data
When you have a very large number of arguments
When to use the query string:
When the arguments are such that you want to see them while debugging
When you want to be able to call them manually while developing the code e.g. with curl
When arguments are common across many web services
When you're already sending a different content-type such as application/octet-stream
Notice you can mix and match - put the the common ones, the ones that should be debugable in the query string, and throw all the rest in the json.
The reasoning I've always used is that because POST, PUT, and PATCH presumably have payloads containing information that customers might consider proprietary, the best practice is to put all payloads for those methods in the request body, and not in the URL parms, because it's very likely that somewhere, somehow, URL text is being logged by your web server and you don't want customer data getting splattered as plain text into your log filesystem.
That potential exposure via the URL isn't an issue for GET or DELETE or any of the other REST operations.
I am trying to build my application's admin UI using sling's userManager REST interface, but I would like to customize the json rendering. For example, I would like the response of "Get group" to include the members only if the requestor is a member.
I started by adding libs/sling/group/json.esp but I don't understand how I can get hold of the default response and customize it. Even if I had to query and form the json from scratch, where can I find information about APIs available to get this data from JCR/Sling?
I found that I could use ResourceTraversor to dump the resource object in json form but using new Packages.org.apache.sling.servlets.get.impl.helpers.ResourceTraversor(-1, 10000, resource, true) in the esp throws up an error
There are a few things to note here.
First, you should avoid putting your code under the libs directory. Your app code should live under the apps directory. When attempting to resolve a servlet for a URI, Sling will check apps before it checks libs so if you need to completely override functionality delivered with Sling, you would place your code in apps.
Second, what is (probably, depending on how you have things setup) happening when you request http://localhost:8080/system/userManager/group/administrators.tidy.1.json is the request is being handled by Sling's default GET servlet, because it finds no other script or servlet which is applicable. For research purposes it might be worth looking at the code for the default get servlet, org.apache.sling.servlets.get.impl.DefaultGetServlet, to see what it's using to render JSON. If you need to handle the rendering of a user group in a manner different than what the default GET servlet is doing, then you would need to create a servlet which is listening for requests for resources of type sling/group. It would probably be ideal to create a servlet for this purpose and register it with OSGI. http://sling.apache.org/site/servlets.html provides the various properties you would need to set to ensure the servlet resolver finds your servlet. Your servlet then would handle the request and as such would have direct and easy access to the requested resource.
Third, the particular need you specified is that you do not want the group members to render unless the requesting user is a member of the group requested. This is more of an access control issue than a rendering issue. Sling and Jackrabbit, out of the box, make as few assumptions as possible concerning how you might want your application to be setup. That being the case, you need to establish the access controls that are applicable for your particular use case. The wiki post on Access Control in the Jackrabbit wiki ( http://wiki.apache.org/jackrabbit/AccessControl ) goes into this to an extent.
Using directions from Paul Michelotti's answer, I researched further and found a suitable solution to my problem.
Sling accepts request filters (javax.servlet.Filter) through SCR annotations like the one below
#SlingFilter(scope = SlingFilterScope.REQUEST, order = Integer.MIN_VALUE)
Every request is passed down to the filter before it is processed by the servlet. Using the resourceType, I was able to distinguish requests to group.1.json and group/mygroup.1.json. Since the filter also has access to the current user, I was able to decide to deny the request if it did not abide by my security model and return a 404 status code.
Please refer to this page for details on filters. You can also check out the sample project urlfilter for directions on usage.
The Sun Cloud API at http://kenai.com/projects/suncloudapis/pages/Home is a good example to follow for a RESTful API. True to RESTful principles, when you GET a resource you get no more nor less than a representation of that resource.
The Content-Type header in the response tells you exactly what the type of that resource is, for example application/vnd.com.sun.cloud.Snapshot+json. Sun has registered these mimetypes with the IANA.
How practical is this in general currently? Most API's I have seen have used the Content-Type of "application/json". This tells you that the response is JSON but nothing more about it. You have to have something in the JSON object, like a "type" property, to know what it is.
I'm designing a RESTful API (which will not be made public, therefore I wouldn't be registering mimetypes). I have been using RESTEasy and I find that even if I specify a complete mimetype, the Content-Type in the response header will be exactly what the Accept request header specified. If the request asks for "application/*+json" by default the response header will have "application/*+json". I can probably fix this by changing the header before the response goes out, but should I try to do that? Or should the response have a wildcard just like the request did?
Or should I just serve up "application/json" like most APIs seem to do?
Additional thoughts added later:
Another way of stating the question is: Should I use HTTP as the protocol, or should I use HTTP only as a transport mechanism to wrap my own protocol?
To use HTTP as the protocol, the entity body of the response contains the representation of the object requested (or the representation of an error message object), the "Content-Type" header contains the exact type of the object, and the "Status" header contains a success or error code.
To use HTTP as merely a transport mechanism, the "Status" header is always set to 200 OK, the "Content-Type" is something generic like "application/json", and the entity body contains something that itself has an object, an object type, an error code and whatever else you want. If your own protocol is RESTful, then the whole scheme is RESTful. (HTTP is a RESTful protocol but not the only possible one.)
Your own protocol will be opaque to all the transport layers. If you use HTTP as the protocol, all the transport layers will understand it and may do things you don't want; for instance a browser will intercept a "401 Unauthorized" response and put up a login dialog, even if you want to handle it yourself.
I use my own vnd.mycompany.mymediatype+xml media types for many of my representations. On the client I dispatch to the appropriate controller class based on the media type of the returned representation. This really allows the server to control the behavior of my client application in response to the user following a link.
Personally, I believe that using application/xml and application/json are one of the worst choices you can make if you hoping to support REST clients. The only exception to this is when the client only uses downloaded code (like Javascript) to interpret the data.
Or should I just serve up "application/json" like most APIs seem to do?
I don't think so.
A media type is the only point of coupling between your RESTful web application and the clients that use it. The documentation of your media types is the documentation of your API. Your media types are the contract between your clients and your application. Eliminate the specific media type and you eliminate an important element that makes REST workable.
Sun has registered these mimetypes with the IANA.
Couldn't find any mention of that here. AFAIK, there is no requirement to actually register your custom media type with the IANA. The convention seems to be to use the inverted domain notation of application/vnd.com.example.app.foo+json, which prevents namespace conflicts. If and when your media type becomes stable and public, it might be a good idea, but there's no requirement. Could be wrong on this, though.
Will you get any value by specifying a complete mimetype? Would you do anything with the complete mimetype different than you would if the mimetype was application/json?
My 2 cents- If the API is not going to be made public, then I see no reason for a complete mimetype. A mimetype of application/json should be more than enough. You already know the type of json that the response is returning. If the API eventually becomes public, then worry about a complete mimetype... or just let people figure it out.