HATEOAS is one of the most important principles of a RESTful API and this includes navigability. I always like to use the following metaphor: when navigating a RESTful API from the browser, the user should get the feeling that they are playing with a poorly loaded website, which only displays the HTML structure and links, without any CSS.
This said, take the below JAX-RS class:
@Path("/teams")
public class Teams {
@GET
@Path("/{teamId}")
public Response team(@PathParam String teamId) {
//return team by its id
}
@GET
@Path("/{teamId}/projects")
public Response projects(@PathParam String teamId) {
//return a team's projects.
}
}
From my experience, currently, if the user calls example.com/api/teams (not knowhing the exact methods of /teams), they get 404 NOT FOUND. Instead, I think JAX-RS should automatically display a Json/XML/whatever (so Content Negotiation, somehow) containing the links offered by /teams. Something like this:
{
"Fetch a Team": {
"Method": "GET",
"Link": "example.com/api/teams/{teamId}"
},
"Fetch a Team's Projects": {
"Method": "GET",
"Link": "example.com/api/teams/{teamId}/projects"
}
}
At the moment, if we want the upper effect to happen, we have to make the Teams bean implement javax.json.JsonObject (or extend an abstract implementation of javax.json.JsonObject) and pass all the information to the super JsonObject in its ctor. It looks like this:
@Path(/teams)
public class Teams extends AbstractJsonObject {
private static final String TEAM_ID = "/{teamId}";
private static final String PROJECTS = "/{teamId}/projects";
public Teams() {
super(TEAM_ID, PROJECTS);
}
@GET
@Path("/")
public Response docs() {
return Response.ok().entity(this.toString()).build();
}
@GET
@Path(TEAM_ID);
//...
@GET
@Path(PROJECTS);
//...
}
Given this polymorphism is rather simple to implement, I would like to see JAX-RS do it out of the box. What do you think?
I believe this functionality could ultimately replace any automatically-generated documentation such as Swagger.
-1
OPTIONS returning Link headers.@mkarg
What you propose it is just syntactic sugar ontop of something you can already achieve without it
Well, the fact that it's easy to implement is not an argument. Most developers don't even understand what REST actually is. I suppose you know this famous rant of Mr. Fielding. Also, here are my (more elaborate) thoughts on it.
So, even if it's simple to implement, most don't think about it and JAX-RS should do as much as possible to lead developers on the right path. Not to mention, there are dozens of "rest" frameworks which don't really help developers make a RESTful api, they just help them expose some HTTP endpoints... I don't want JAX-RS to be just a kit for HTTP endpoints, I want it to be as helpful as possible in the "REST" direction. :D
Your proposal enforces exactly one particular solution
This can be discussed and the best solution can be found. I see no problem in having both the GET and the OPTIONS alternative :-?
@amihaiemil I well understand your point, but frankly spoken, your arguments still do not convince me. In particular the idea seems to be incomplete. Maybe you like to hack a PoC which demonstrates how OPTIONS and GET alternatives work together, and in particular, how GET (your solution) and GET (any other solution) work together? I mean, this smells like the need for a solution provider in the end.
@mkarg I only mentioned OPTIONS or others because you brought it on the table. :D
I personally think a GET would be enough, since it's the simplest, most intuitive way of seeing the APIs overview. It would be primarily for human usage (let's call it like this): developer reads it from the browser, same as they use Swagger. Then, I think fluent tests and clients would be designed much easier (see my article, linked in the previous comment).
The described polymorphim is just how I'd do it now. If JAX-RS had this, I would expect to have the default path / or /overview in each class (and probably specify ?format=xml or ?format=json to enforce the content-type.
Now, of course, some users may have their own / or /overview paths, so JAX-RS could have the @Overview("/path") annotation (to be used on classes).
So this is just a nice-to-have idea, simple indeed, but which I believe would greatly increase the quality (especially regarding REST paradigm) of apis built with JAX-RS.
May I ask, what is the process exactly? Do people vote on proposed ideas such as this one? Will it be discussed somewhere or simply stay here until some Github users upvote/downvote it? :D
@amihaiemil Jersey, just to name one, already provides such a self-description using WADL, but on a different path. So what you propose is incompatible. How to solve this discrepancy? Someone now needs to make WADL go away and implement your counter proposal. Why should he? Who pays for that, and who has the actual benefit? Your solution is just, different, but IMHO not any better than what Jersey already does.
The process at the EF is "code first" and "proven usefulness":
@mkarg I see, thanks for the thorough explanation. I'll try to see what the Jersey guys say :)
@amihaiemil I'm technically one of the Jersey guys (albeit a rather new one), but I'd personally say that if the proposal to add HATE OS to JAX-RS is accepted, then surely I'd like to look at implementing it in Jersey (according to the JAX-RS API/specs). However, I'd personally don't see any merit in implementing HATEOS specifically for Jersey in a proprietary way.
Of course I'm only one voice and not even the main voice of the Jersey project, so maybe the other committers think differently about this, but this is my opinion.
@arjantijms Can we also get an official statement of the Jersey team, e. g. from @jansupol?
@mkarg I opened an Issue to the Jersey repo, pointing here. I also opened one for RestEasy (they manage tickets in Jira, unfortunately, so no Github reference).
@amihaiemil So you now start implementing Jersey / RESTeasy or what is your next step?
@mkarg Well you said that a vendor should implement it first before it can be made a standard, so I asked Jersey and RestEasy about it, right? To my knowledge, they are the biggest vendors for JAX-RS.
@amihaiemil Let's see if a vendor is willing to implement your wish or simply nothing happens, because both are open source projects and you are assumed to provide a PR... ;-)
@mkarg of course, I could study the projects and maybe provide a PR, but first I want to see if someone supports the idea or not.
@amihaiemil Let's see what happens. ;-)
@mkarg I opened an Issue to the Jersey repo, pointing here. I also opened one for RestEasy (they manage tickets in Jira, unfortunately, so no Github reference).
@amihaiemil , how about a link to the jira you created?
@asoldano Right, here it is: https://issues.jboss.org/browse/RESTEASY-2022
@amihaiemil Can you please concicesly report on the progress of this issue? Is this feature already implemented somewhere? Is there already some feedback to share?
@mkarg As we discussed, I started looking into the Jersey source code (product implementation comes first, then maybe it becomes a standard, that's what I understood). Should I make a PR with the @Overview annotation which I described above?
@amihaiemil A PR against JAX-RS makes no sense as long a there is no feedback from users of the existing feature. So unless the feature you are working on got adopted by Jersey and produced a mostly positive user feedback, all you can share in the JAX-RS issue is a link to your Jersey PR.
@mkarg Closing, as explained here. Thanks!