Error Handling

If a middleware or route handler throws an error the server needs to know how to handle this. If the server does not know how to handle the error then the only thing it can return to the client is a status code of 500 (Internal Server Error). This is not overly informative.

HBHTTPError

Hummingbird uses the Error object HBHTTPError throughout its codebase. The server recognises this and can generate a more informative response for the client from it. The error includes the status code that should be returned and a response message if needed. For example

app.get("user") { request -> User in
    guard let userId = request.uri.queryParameters.get("id", as: Int.self) else {
        throw HBHTTPError(.badRequest, message: "Invalid user id")
    }
    ...
}

The HBHTTPError generated here will be recognised by the server and it will generate a status code 400 (Bad Request) with the body “Invalid user id”.

In the situation where you have a route that returns an EventLoopFuture you are not allowed to throw an error so you have to return a failed EventLoopFuture. Hummingbird provides a shortcut here for you request.failure. It can be used as follows

app.get("user") { request -> EventLoopFuture<User> in
    guard let userId = request.uri.queryParameters.get("id", as: Int.self) else {
        return request.failure(.badRequest, message: "Invalid user id")
    }
    ...
}

HBHTTPResponseError

The server knows how to respond to a HBHTTPError because it conforms to protocol HBHTTPResponseError. You can create your own Error object and conform it to HBHTTPResponseError and the server will know how to generate a sensible error from it. The example below is a error class that outputs an error code in the response headers.

struct MyError: HBHTTPResponseError {
    init(_ status: HTTPResponseStatus, errorCode: String) {
        self.status = status
        self.errorCode = errorCode
    }

    let errorCode: String

    // required by HBHTTPResponseError protocol
    let status: HTTPResponseStatus
    var headers: HTTPHeaders { ["error-code": self.errorCode] }
    func body(allocator: ByteBufferAllocator) -> ByteBuffer? {
        return nil
    }
}