@GET
public Collection<Integer> listStudentIds() {
return STUDENTS.keySet();
}
or
@DELETE
@Path("{uid: [0-9]+}")
public boolean deleteStudent(@PathParam("uid") int uid) {
final Student deletedStudent = STUDENTS.remove(uid);
if (deletedStudent == null) {
throw new WebApplicationException(Response.Status.NOT_FOUND);
} else {
return true;
}
}
I'll grant that Java programs often become more verbose than their Python/Ruby counterparts - but I would argue that trait can be held to a minimum with the proper libraries and coding style.
the last line generally wouldn't be this complex, in Flask you'd just call `flask.abort(404)` (which can be used inline with an `or`, as with waffle_ss's ruby example, but that's not usual/good Python style), in Django it'd be `raise Http404()`.
Although in Django you'd really use the `get_object_or_404` shortcut for ORM objects:
And you wouldn't bother with the return since a 200 result would mean the deletion was correctly executed.
[0] Used Python's MutableMapping API here, it works slightly differently than Java's equivalent Map interface: `.keys()` returns a sequence of the mapping's keys and `.pop()` asks for a default value to return in case nothing was found there, otherwise it raises `KeyError` if the key was not found)
In Ruby, everything evaluates to true except false and nil. Also, the last statement executed is your return value. Therefore your first function could be written as
def delete_student(uid)
STUDENTS.remove(uid) || raise WebApplicationException.new(Response.Status.NOT_FOUND)
end
I have no idea what the annotations mean, but if we use exceptions for transmitting error conditions, then there is no point having a true | exception function.
public void deleteStudent(int uid) {
if (STUDENTS.remove(uid) == null) {
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
}
In that case it is preferable to use "or" over "||" since then you do not have to worry so much about operator precedence because "or" has about the weakest of all operators. This means in this case that you can skip the explicit ".new" for the exception.
def delete_student(uid)
STUDENTS.remove(uid) or raise WebApplicationException, Response.Status.NOT_FOUND
end
You could make it shorter by using something like sinatra[1]. Here is my pseudo-sinatra code.
get "/list_student_ids" do
STUDENTS.key_set
end
delete "/delete_student/:uid" do
STUDENTS.remove(params[:uid]) or raise WebApplicationException, Response::Status::NOT_FOUND
true
end
1. Thing's most of those types provide no value in being spelled out like that. The ones on the methods have documentary advantages, but that's about it, the rest is magical invocations to make a stupid compiler happy.
2. There's also a gain from the framework being able to map things to each other without being told explicitly. `@PathParam("uid")` for instance, it's only there because the framework has no way to match the parameter name `uid` to the URL-extracted parameter `uid`. Likewise with HTTP methods being part of the routing instead of a separate annotation, in part.
3. Java's APIs and type system, such as implicit nulls and not being able to use arbitrary types in boolean contexts
I would say they are mainly from removing the need for decorators due to there being a nice lambda function/block syntax. So we can define methods like "get" and "delete" which does the job of the decorators, creating something kind of like a mini-DSL.
Some savings through the removal of types, sure, but that is not what I personally see as most import here.
With Ruby folks can always try to remove redundancy. :-)
I find it amazing that "DRY" has become such a positive pattern when it was touted as one of the driving points of the Ruby on Rails framework. Don't repeat yourself.
For instance, Java folks are always ready to throw exceptions instead of letting stuff resolve itself if it doesn't quite work.
In that example I only throw an exception when you try to delete a student who doesn't exist. The reason I do so is that it contains semantic information which is useful for the client.
If I returned a fake value - the client would get a 200 response on his attempt to delete a non-existent resource, which is clearly the incorrect behavior. I could return nothing - but then the client would see a 204. So, I choose to throw an exception with a response 'NOT_FOUND'
throw new WebApplicationException(Response.Status.NOT_FOUND);
I did try and build your code to run the test (I've no idea where the CsvParam and DateParam classes come from) but I think that the following will give you what you want without throwing the exception.
@DELETE
@Path("{uid: [0-9]+}")
public Response deleteStudent(@PathParam("uid") int uid) {
final Student deletedStudent = STUDENTS.remove(uid);
if (deletedStudent == null) {
return Response.status(Response.Status.NOT_FOUND).build();
} else {
return Response.ok().entity(true).build();
}
}
There are a few things I'd like to point out to add to this example:
1) JAX-RS is still new. In the future, they might improve the exception handling or whatnot (so if you return null, they might decided to return 404 ... who knows)
2) We can always wrap all JAX-RS with a Filter. So you can throw JPA level exception (not found) and let the filter catch it and convert it to WebApplicationException(404). Thus in theory, your JAX-RS implementation won't have any RuntimeException explicitly in the code.