views:

63

answers:

3

This title begs for more explanation.

Basically, I'm rolling an API that wraps a web service in a nice heirarchical model. This model exposes things in the form:

var obj = MyRemoteResource.GetForId(1234, SourceEnum.ThatSource);
ApiConsumerMethod(obj.SomeProperty);  //SomeProperty is lazily loaded, and often exposes such lazily loaded properties itself
... etc ...

Where many different RemoteResources* (each with many properties exist). There's really aggresive cacheing going on, and request throttling to prevent inadvertantly DOS'ing the servers (and getting the IP of the caller banned).

I've got all this code working, but I'm not doing much in the way of error handling at the moment. Basically, if the consumer of an API provides an invalid ID, the web server is down, a connection times out, or any other of a plethora of request layer errors occur an exception just percolates up when a property is accessed.

I consider this far less than ideal.

So my question is, how should I wrap these errors up so that it is convenient for a user of this API to manage them?

Some routes I have considered:

  • Just wrap all exceptions in some API defined ones, and document them as thrown.
  • Expose a static ErrorHandler class that allows a user to register notification callbacks for specific errors; falling back to the above behavior when no registration has been made for specific errors.**
  • Null properties on error, and set a LastErrorCode.

Each of these approachs have strengths and weaknesses. I'd appreciate opinons on them, as well as alternatives I haven't thought of.

If it impacts the discussion at all, the platform class throwing these exceptions is WebClient. Furthermore, usage of WebClient is sufficiently abstract that it could easily be replaced with some other download scheme if needed.

*Which is to say, many different classes

**This would be... wierd. But it maps to the global nature of the failure. This is my least favorite idea thus far.

A: 

I prefer to have an exception thrown at me when something bad happens. Exceptions are (for me, anyways) the common way to tell that something went wrong, and i find it more intuitive to catch, than to check a return value for null and check another property to see what went wrong..

hhravn
Heh. I'd much rather check return values than throw exceptions. I associate exceptions with something totally unexpected happening. Just goes to show different programming styles I guess.
Alex
+2  A: 

I wouldn't implement fancy error technologies (like events and stuff like this). It's not easy to judge where and how to use exceptions, but this is no reason to implements other stuff.

When you request an object by an id which doesn't exist, what do you have to tell the caller about this? If you just return null, the client knows that it doesn't exist, there is nothing more to say.

Exceptions force the caller to care about it. So they should only be used where the caller is expected to do something special. Exception can provide the information why something didn't work. But if it is an "error" the user could also ignore, an exception is not the best choice.

There are two common alternatives to exceptions.

  • Use return values which provide information about the result of an action. For instance, logon could return a LogonResult instead of throwing an exception.
  • Write two methods, one throwing an exception, and one (Try...) returning a boolean. The caller decides if it wants to ignore the "error" or not.
Stefan Steinegger
This is much better than my answer :o)
hhravn
The delayed loading nature of this API makes it difficult to determine if an id is valid or not immediately. A perfectly valid use case is to construct a large set of items from ID (say cached in a file) and then iterate over some set of their properties. Only once a property is accessed would the validity of the IDs be determinable.
Kevin Montrose
+2  A: 

Personally I believe this is entirely dependent on the context of what your API end-user is trying to do. If this is the case, you should let them decide how to handle erors.

Recently when working with CSV files (very error prone) I used an API that allowed you to define the exception behaviour. You could either ignore the error, replace by some default value/action, or pass them off to an event handler.

I really liked this approach of letting the end user decide how to handle internal exceptions, because unless your API is very specific its difficult to preempt all scenarios.

Alex
Basically I agree, but CSV parsing is much more general then a specific server API.
Stefan Steinegger
I dont think your suggestions are really that different. For instance, the LogonResult object will presumably contain some handling to swallow the exception and set a property specifying the occurrence of the error. I'd rather see this exposed via a simple property rather have them inside a wrapped type, as in many cases the end user will just map these LogonResult values to their own ApplicationXLogonResult (or straight to a GUI/command line/logfile). If you leave things up to the user then they can use the values directly without dealing with these other types.
Alex