Twitter GitHub Facebook Instagram dirv.me

Daniel Irvine on building software

Beautiful errors with OpenRasta

9 June 2011

Disclaimer: I’m an OpenRasta newbie so what follows may be completely wrong, but it appears to work for me.

Here’s a common feature of web services: when an error occurs during processing of a server request, the server should return a “nice” error message to the client. It goes without saying that the appropriate HTTP status code (4xx or 5xx) should be set.

A “nice” error message in this context means two things.

  1. The message is concise, human-readable and useful.
  2. The message contains no sensitive information. In other words, forwarding exceptions and stack traces are out of the question.

So how do we do this with OpenRasta?

Let’s look at a very common example and its solution. We’ve got an OperationInterceptor that does some work in its BeforeExecute method. This work has the potential to throw an exception, at which point the server should hold its hands up and say “sorry, I’m borked.” In other words we want to return an HTTP 500 Internal Server Error and possibly tell the user exactly what happened.

public class MyInterceptor : OperationInterceptor {

  readonly ICommunicationContext _context;

  public MyInterceptor(ICommunicationContext context) {
    _context = context;
  }

  public override bool BeforeExecute(IOperation operation) {

    try {
       // ... do some stuff
    } catch(Exception ex) {

       // log all the gory details to the server log, available
       // only to the system admins
       LogToServerLog(ex);

       // and display a nice message to the user, see below
       // for an example of what this might say
       string description = Strings.UserSafeErrorMessage;

       // todo: how do we return this to OpenRasta?
    }

    return true;

  }
}

The key to this problem is the // todo above, which we can fill in the with code below.

_context.OperationResult = new OperationResult.InternalServerError
{
    ResponseResource = description;
}

This isn’t enough on its own, however. OpenRasta looks for a codec that matches the type of the object assigned to ResponseResource, and right now we haven’t registered a codec for the string type. Well that’s simple; we just add the following to our IConfigurationSource implementation:

ResourceSpace.Has
  .ResourcesOfType<string>()
  .WithoutUri
  .AsJsonDataContract();

Everything should now work, and (depending on how you’ve defined Strings.UserSafeErrorMessage) your response will be something like:

"An exception occurred while attempting to process
the request. The operation will not be allowed. The 
server log contains a full exception report. Please
notify the system administrator."

Awesome! But: there’s one more thing. This is probably the minimum amount of code you can get away with to achieve this, but it’s cheeky of us. We’re registering the string type as a resource! It’s probably better to create our own error type that will be more useful to all parties:

public class ServerError
{
  public string Error { get; set; }
}

_context.OperationResult = new OperationResult.InternalServerError
{
    ResponseResource = new ServerError { Error = description };
}

ResourceSpace.Has
  .ResourcesOfType<ServerError>()
  .WithoutUri
  .AsJsonDataContract();

Which will give this output instead:

{"Error":"An exception occurred while attempting
 to retrieve authorization information. The operation
 will not be allowed. The server log contains a full
 exception report. Please notify the system
 administrator."}

That’s better.

About the author

Daniel Irvine is a software craftsman at 8th Light, based in London. These days he prefers to code in Clojure and Ruby, despite having been a C++ and C# developer for the majority of his career.

For a longer bio please see danielirvine.com. To contact Daniel, send a tweet to @d_ir or use the comments section below.

Twitter GitHub Facebook Instagram dirv.me