Improve error handling.

This pull requests improves the error handling, and fixes potential fall-through problems in some cases.

I'll try to annotate the code more specifically, but generally you should get into the habit of early `return`ing your callbacks. As an example, 

```js
someAsyncMethod(function(err, result) {
  if (err) {
    console.error(err);
    callback(err); // should `return callback(err)` here
  }
  // Execution continues after the if-block and this line will crash your process
  // because `result` will likely be `null`. Even if we didn't try to use a method
  // on the result and just passed it back, the callback would trigger twice, which
  // will have unexpected results.
  callback(null, result.doSomething());
})
```

Early `returns` on callbacks also mean you don't have to have a giant `else {..}` block. In this PR I removed the `else` blocks where applicable, but I *didn't* fix the whitespace so as not to unnecessarily obfuscate the diff. I can make a followup PR fixing the whitespace if you accept this one.

Another general fix that I did was on the API routes, I made them always JSON and use a proper status code. Previously they would only return JSON on success, and plain strings on failure, but they were also still returning HTTP 200 on failure. This would cause any tool that consumes those API endpoints possibly fail if they always assumed JSON on a 200 response.
Since we are returning early, we have to make sure to clean up the connection as soon as we know there's an error.