users@jersey.java.net

Re: [Jersey] Idea for new contribution -- a pattern for handling HTTP errors as Java exceptions?

From: Kevin Duffey <andjarnic_at_yahoo.com>
Date: Thu, 30 Oct 2008 22:00:23 -0700 (PDT)

Hey all..

I would also love to see this error handling added to Jersey! I think it would be a great addition and using JAXB makes it so nice to return server side errors in a REST friendly manner all while we developers stay in the Java domain. Very slick indeed! Count me in on another vote for adding this to Jersey.

Thanks.





________________________________
From: Craig McClanahan <Craig.McClanahan_at_Sun.COM>
To: users_at_jersey.dev.java.net
Sent: Friday, October 24, 2008 10:39:47 AM
Subject: Re: [Jersey] Idea for new contribution -- a pattern for handling HTTP errors as Java exceptions?

Jeff Schmidt wrote:
Hello again:

It sounds like we're thinking more alike than I had originally
guessed. Please see comments below.

Snipping and answering the questions -- see previous messages in the
thread to get the whole context.



On Oct 23, 2008, at 10:35 PM, Craig McClanahan wrote:

Jeff Schmidt wrote:


On Oct 23, 2008, at 6:22 PM, Craig McClanahan wrote:


...

* Passing error messages in a consistent format that the
client can rely on, and
parse to good effect. For example, if your API offers a POST URI to
create a new
resource, but several of the input fields in the entity have incorrect
or missing values,
it would be nice to have a data structure that lets me include zero or
more error
messages, optionally tagged to the corresponding field names (so that a
client side
UI can present them nicely).

I would like to return some entity to help out the client. My thought
was to provide the entity as a class instance added to the exception
constructor (FaultInfo). The code that detects the problem can populate
this class to better assist the client. I would like for this entity
to be marshaled in the same manner a proper response would be by
JAX-RS, using @Produces/_at_Consumed to return the right format. Starting
with something from the SOAP side of things, I defined this class:

@XmlRootElement(name = "Error")
@XmlType(name = "ErrorType")
@XmlAccessorType(XmlAccessType.FIELD)
public class FaultInfo {

@XmlElement(name
= "Code")
protected
ErrorCode _errorCode;
@XmlElement(name
= "Message")
protected
String _message;
@XmlElement(name
= "Resource")
protected
String _resource;
@XmlElement(name
= "DevInfo")
protected
String _devInfo;

public
FaultInfo() {
}

public
FaultInfo(ErrorCode errorCode) {
_errorCode
= errorCode;
_message
= errorCode.getMessage();
}

public
FaultInfo(ErrorCode errorCode, String resource) {
this(errorCode);
_resource
= resource;
}

public
FaultInfo(ErrorCode errorCode, String resource, String devInfo) {
this(errorCode,
resource);
_devInfo
= devInfo;
}

public
ErrorCode getErrorCode() {
return
_errorCode;
}

public
String getResource() {
return
_resource;
}
}

Hmm ... I think we rapidly reach a point where a fixed set of fields
describing an error message will always seem like overkill for some use
cases, and not enough for others. It'll be interesting to consider
whether we can generalize the set of information carried along in
interesting ways.

Leveraging the providers (produces/consumes) for error-specific entity
data might be an interesting approach, but I'm betting we'd end up
wanting multipart message formats so that the client who receives this
would be able to parse it more easily.

...

The properties I've currently
included in a Message bean (what actually gets serialized is a
collection of such beans, so you can have zero or more messages) are:
* text -- Localized text for this message (required)
* code -- String identifier to look a particular error up in some
catalog (optional)
* field -- Name of the field this error is associated wth (optional;
default interpretation is "global error")
Does the field refer to an input parameter (@PathParam, @QueryParam) as
well as some XML element or attribute for any uploaded entity? I'm not
sure how general you can make this.

I didn't specifically define what "field" means, but the intuitive
concept is that it identifies an individual chunk of data from the
request. For an HTTP form post, that would literally be the field
name. For an XML or JSON representation, it would be the name of an
XML element (or a JSON field). The important thing is that the client
needs to know the mappings for *this* particular request type ... but
it should generally be pretty obvious.

* stackTrace -- If error
caused by an exception, a place to include a stack trace
  (although our best practices recommend *not* including this for
messages visible
  to a third party client, because stack traces can reveal a lot about
your internal architecture)
I agree. Being able to switch this on for development mode would be
very helpful. But, in production, this stuff must not get out.

Yep.

* hint -- Mechanism for the
server to describe potential workarounds that might
  be displayed by a client UI (optional)
Do you see that as text to be more or less directly displayed by the UI.
Yes.

Would it be localized too?

Yep ... it should also be localized. And, by "localized", I'm
referring to doing so based on the *client* settings (specified by the
Accept-Language header), not by the server domain.

...



This all does seem a bit awkward, and as you can see only a
single fault is being reported.
My validation exception class has a property of type
Map<String,List<String>> where the key is the field name
(empty string for "global" validation errors) and the value is zero or
more localized messages related to this particular field.
That sounds more generally useful then what I've provided above. :)

Julio Faerman raises a different scenario on the mailing list ... what
if you're doing multiple transactions in a batch processing style? You
might really want to report multiple "exceptions". As I mentioned in
my response to him, I haven't run into that use case in our server
code, but it's certainly something interesting to think about.

The library would provide an exception mapper that
enforces our "best practice" policy to use an HTTP 404 "Not Found"
status for this condition, and package an appropriate message body
containing the message text, in a standard XML or JSON format.

I'm very interested in seeing what you have in mind. I don't know if
you'll get it into Jersey to meet my timeframe, but I am interested in
learning about your approach and perhaps implementing something similar
for now, and using it directly in Jersey 1.1 or whenever you've
integrated it.

...


Cool ... I'll take a crack at this fairly soon, and we can spend some
time refining it. If you're using Maven to build, you'll be able to
declare dependencies on the snapshots if you're willing to deal with
that ... they will get published by the Hudson builds.
Great! Our project is still based on Ant, no Maven yet. I guess I can
use Maven to build your snapshots and then use the resulting jars in
our Ant build.

Yep. The Maven project also provides a set of Ant tasks that can do
the "download the right version from the right repository" trick, and
still fit things into an Ant build environment. I also understand that
Ivy can do this sort of thing directly.

Craig