3

I am writing an backbone js web app on top of an JSON server that returns JSON responses in JSend specification format.

Here are a few examples of that format:

GET /posts

{
 "status": "success",
 "data": {
   "posts" [
     {"id": 1, "title": "A blog post"}, 
     {"id": 2, "title": "another blog post"}
   ]
 }
}

POST /posts

{
  "status": "fail",
  "data": {
    "title": "required"
  }
}

By default the "error" event in $.ajax gets triggered by http codes, but since the JSend specification format does not use HTTP codes at all, I have to rewrite the $.ajax error handler.

The way it works by default (http codes):

$.ajax({
  error: function() {
    // Do your job here.
  },
  success: function() {
    // Do your job here.
  }
});

How can I rewrite the $.ajax error handler that it gets triggered when parsed the body and if the "status" property is "fail" or "error"?

James A Mohler
  • 11,060
  • 15
  • 46
  • 72
onlineracoon
  • 2,932
  • 5
  • 47
  • 66
  • You could use the dataFilter callback to invalidate the json if it's an error, however you would then lose any error messages that get returned and add complexity to your code. You're better off detecting if it's an error within the success handler instead. – Kevin B Jan 21 '13 at 15:53
  • What JSON Server are you using, can't you just make it sending proper HTTP status codes?? I don't think that it would be forbidden to use JSend AND HTTP codes to ensure correct behavior. – ohcibi Jan 21 '13 at 15:55
  • @ohcibi I don't like HTTP codes, everywhere I look everyone has a different opinion about codes, so I don't want to use HTTP codes at all. – onlineracoon Jan 21 '13 at 15:56
  • @onlineracoon Hm, I don't share the same experience; but in this case the answer to your question if there is no other way to do it, is clear (you should get an idea what HTTP status codes are good for if you think further about the problem 8-)). – ohcibi Jan 21 '13 at 15:58
  • 1
    @onlineracoon is your goal to avoid having `if (json.status == 'fail')` visible in your code at all? – Explosion Pills Jan 21 '13 at 16:03

2 Answers2

4

As counter-intuitive as it seems, you will have to put it in the success function. Simply check the value yourself:

$.ajax({
  error: function() {
    // Handle http codes here
  },
  success: function(data) {

    if(data.status == "fail"){
      // Handle failure here
    } else {
      // success, do your thing
    }

  }
});
James Montagne
  • 77,516
  • 14
  • 110
  • 130
  • 1
    Together with deferred objects, the error case could be handled transparently. – Felix Kling Jan 21 '13 at 15:54
  • This would be my last resort, is there no other way to do this? – onlineracoon Jan 21 '13 at 15:56
  • 2
    No. you can make it less obvious that you are doing this by hiding it behind a custom method, however in the end this is what you would be doing. – Kevin B Jan 21 '13 at 16:01
  • @FelixKling Perhaps you could elaborate in an answer? I would be interested to see what you had in mind. I have to be honest and say that I don't often bother with deferred aside from waiting on multiple requests. – James Montagne Jan 21 '13 at 18:34
1

To keep the things DRY you can use something like this:

function JSendHandler(success, fail) {
    if (typeof success !== 'function' || typeof fail !== 'function') {
        throw 'Please, provide valid handlers!';
    }
    this.success = success;
    this.fail = fail;
}

JSendHandler.prototype.getHandler = function () {
    return function (result) {
        if (result.status === 'fail') {
            this.fail.call(this, arguments);
        } else {
            this.success.call(this, arguments);
        }
    }
};

function success() { console.log('Success'); }
function error() { console.log('Fail!'); }

var handler = new JSendHandler(success, error);

$.ajax({
  error: error,
  success: handler.getHandler()
});
Kevin B
  • 94,570
  • 16
  • 163
  • 180
Minko Gechev
  • 25,304
  • 9
  • 61
  • 68