Report your status

Detailed status information with failing Dispatch requests

Let me start with a disclaimer. There are many different versions of Dispatch around, and the API changed, so what I am about to explain to you is totally incompatible with the latest version of Dispatch. What I am about to show below is only for Dispatch Classic – which I think many people are still using, so I think it's still relevant to at least some of us.

The issue

I want to use a service. I send a request somewhere. I get back a 500 Internal Server Error. The people from on the receiving end ask me if I included the right headers, used the right URL and the right parameters. Unfortunately, with Dispatch, that information is not captured in the StatusCode that is returned from the HttpExecutor, so it's effectively lost. If I would have logged every request, some of that would have been included, but not all of it.

Now what?

The code that is producing the StatusCode subclass of Throwable is burried deep inside HttpExecutor, which is the base class of a whole bunch of other classes in Dispatch. Not something you easily rip and replace.

But have no fear, there is a way out. Just like I showed you in the Retry post, you can create a trait that you mix in your favorite HttpExecutor subclass to give you all the information you need.

trait DetailedStatusCodeReporting extends Http {
  override def execute[T](host: HttpHost, 
                          credsopt: Option[Credentials], 
                          req: HttpRequestBase,
                          block: (HttpResponse) => T, 
                          listener: dispatch.ExceptionListener) = 
  {
    def withBetterExceptionHandling(resp: HttpResponse) = try {
      block(resp)
    } catch {
      case status: StatusCode =>
        throw new UnexpectedStatusCode(status.code, status.contents, req )
    }
    super.execute(host, credsopt, req, withBetterExceptionHandling, listener)
  }
}

Once you have this trait, you can mix it in with every Http subclass, like I do here:

val http = new Http with Safety with DetailedStatusCodeReporting

Instead of the original StatusCode getting thrown from that execute method, I will now get an object that includes the entire request, including the headers, the URL including the request parameters. All I have to do is catch it and do something useful with it.

try {
    http(url as_str)
} catch {
    case UnexpectedStatusCode(code, contents, req) =>
         …  // logging it comes to mind
}