How to display a JSON error message?

17,435

Your callback actually takes 2 other parameters you're not showing:

     $.getJSON('{URL}/api/read/json?type=' + postType + 
          '&callback=?', 
              function(data, textStatus, xhr) {   // main callback function
                if(xhr.status == 500 || xhr.status == 404 || xhr.status == 503) {
                  yourErrorHandler(data, textStatus, xhr); // success
                } else {
                  yourCallbackToRunIfSuccessful(data);   // failed
                }
              }
       );

       // your original code, but wrapped up in it's own function definition
       function yourCallbackToRunIfSuccessful(data) {
         var article = [];
         $.each(data.posts, function(i, item) {
         // i = index
         // item = data for a particular post
         switch(item.type) {
           case 'photo':
           ...
           ...
       }

       function yourErrorHandler(data,textStatus,xhr) {
           alert("Server returned status code " + xhr.status + ".  Try again later.");
       }

You can use the xhr object to check the status of the raw XMLHttpRequest object. If you get a 404, 503, 500, etc then you can display your error message or run your alternate function.

http://api.jquery.com/jQuery.ajax

Also, if you don't already have Firebug for Firefox, I'd highly recommend it for JavaScript debugging: http://getfirebug.com/

UPDATE:

The getJSON JQuery AJAX wrapper does not have an error callback handler. Instead, you'll need to use the regular JQuery AJAX handler to make your JSON request:

  jQuery.ajax({
     type: "GET",
     url: '{URL}/api/read/json?type=' + postType + 
          '&callback=?',
     dataType: "json",
     success: function(results){
         console.info("Success!");
         yourCallbackToRunIfSuccessful(results);
     },
     error: function(XMLHttpRequest, textStatus, errorThrown){
         alert("Error");
         yourErrorHandler(XMLHttpRequest, textStatus, errorThrown);
     }
  });

It's important to note that this is NOT JSONP. This means you cannot make cross-domain requests using this function.

If you're relying on JSONP using my original answer, then you'll need to implement a solution whereby you set a setInterval event to poll a value that will be changed in your callback. More details can be found here:

http://groups.google.com/group/jquery-dev/browse_thread/thread/73ca6be8071479fb

Share:
17,435
Tiny Giant Studios
Author by

Tiny Giant Studios

Updated on June 19, 2022

Comments

  • Tiny Giant Studios
    Tiny Giant Studios about 2 years

    I'm currently developing a tumblr theme and have built a jQuery JSON thingamabob that uses the Tumblr API to do the following:

    The user would click on the "post type" link (e.g. Video Posts), at which stage jQuery would use JSON to grab all the posts that's related to that type and then dynamically display them in a designated area.

    Now everything works absolutely peachy, except that with Tumblr being Tumblr and their servers taking a knock every now and then, the Tumblr API thingy is sometimes offline. Now I can't foresee when this function will be down, which is why I want to display some generic error message if JSON (for whatever reason) was unable to load the post.

    You'll see I've already written some code to show an error message when jQuery can't find any posts related to that post type BUT it doesn't cover any server errors. Note: I sometimes get this error:

    Failed to load resource: the server responded with a status of 503 (Service Temporarily Unavailable)

    It is for this 503 Error message that I need to write some code, but I'm slightly clueless :)

    Here's the jQuery JSON code:

    $('ul.right li').find('a').click(function() {
      var postType = this.className;
      var count = 0;
      byCategory(postType);
      return false;
    
      function byCategory(postType, callback) {
        $.getJSON('{URL}/api/read/json?type=' + postType + '&callback=?', function(data) {
        var article = [];
         $.each(data.posts, function(i, item) {
         // i = index
         // item = data for a particular post
         switch(item.type) {
         case 'photo':
         article[i] = '<div class="post_wrap"><div class="photo" style="padding-bottom:5px;">'
             + '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/XSTldh6ds/photo_icon.png" alt="type_icon"/></a>'
             + '<a href="' + item.url + '" title="{Title}"><img src="' 
           + item['photo-url-500'] 
           + '"alt="image" /></a></div></div>';
         count = 1;
         break;
         case 'video':
         article[i] = '<div class="post_wrap"><div class="video" style="padding-bottom:5px;">'
             + '<a href="' + item.url + '" title="{Title}" class="type_icon">'
           + '<img src="http://static.tumblr.com/ewjv7ap/nuSldhclv/video_icon.png" alt="type_icon"/></a>'
             + '<span style="margin: auto;">' 
           + item['video-player'] 
           + '</span>' 
           + '</div></div>';
         count = 1;
         break;
         case 'audio':
         if (use_IE == true) {
         article[i] = '<div class="post_wrap"><div class="regular">'
                 + '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/R50ldh5uj/audio_icon.png" alt="type_icon"/></a>'
             + '<h3><a href="'
             + item.url
           + '">'
           + item['id3-artist'] 
           +' - '
           + item['id3-title']
           + '</a></h3>'
           + '</div></div>';
    
        } else {
         article[i] = '<div class="post_wrap"><div class="regular">'
                 + '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/R50ldh5uj/audio_icon.png" alt="type_icon"/></a>'
           + '<h3><a href="'
             + item.url
           + '">'
           + item['id3-artist'] 
           +' - '
           + item['id3-title']
           + '</a></h3><div class="player">'
           + item['audio-player'] 
           + '</div>'
           + '</div></div>';
        };
         count = 1;
         break;
         case 'regular':
         article[i] = '<div class="post_wrap"><div class="regular">' 
           + '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/dwxldhck1/regular_icon.png" alt="type_icon"/></a><h3><a href="'
           + item.url 
           + '">' 
           + item['regular-title']
           + '</a></h3><div class="description_container">'
           + item['regular-body'] 
           + '</div></div></div>';
         count = 1;
         break;
         case 'quote':
         article[i] = '<div class="post_wrap"><div class="quote">'
             + '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/loEldhcpr/quote_icon.png" alt="type_icon"/></a><blockquote><h3><a href="' + item.url + '" title="{Title}">' 
           + item['quote-text']
           + '</a></h3></blockquote><cite>- '
           + item['quote-source'] 
           + '</cite></div></div>';
         count = 1;
         break;
         case 'conversation':
         article[i] = '<div class="post_wrap"><div class="chat">' 
           + '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/MVuldhcth/conversation_icon.png" alt="type_icon"/></a><h3><a href="' 
           + item.url 
           + '">'
           + item['conversation-title']
           + '</a></h3></div></div>';
         count = 1;
         break;
         case 'link':
         article[i] = '<div class="post_wrap"><div class="link">' 
           + '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/EQGldhc30/link_icon.png" alt="type_icon"/></a><h3><a href="'
           + item['link-url'] 
           + '" target="_blank">'
           + item['link-text']
           + '</a></h3></div></div>';
         count = 1;
         break;
         default:
         alert('No Entries Found.');
         };
         }) // end each
    
         if (!(count == 0)) {
         $('#content_right')
          .hide('fast')
          .html('<div class="first_div"><span class="left_corner"></span><span class="right_corner"></span><h2>Displaying ' 
          + postType 
          + ' Posts Only</h2></div>'
          + article.join(''))
        .slideDown('fast')
        } else {
         $('#content_right')
         .hide('fast')
         .html('<div class="first_div"><span class="left_corner"></span><span class="right_corner"></span><h2>Hmmm, currently there are no ' 
           + postType 
           + ' posts to display</h2></div>')
         .slideDown('fast')
        }
    
    
        // end getJSON
       }); // end byCategory
      }
     });
    

    If you'd like to see the demo in action, check out Elegantem but do note that everything might work absolutely fine for you (or not), depending on Tumblr's temperament.


    Update Okay, so after following jmorts answer underneath as close to the letter as 2am allows, I've churned out the following code without success - there's no alert popping up. Myabe I'm a muppet, maybe I'm just scheleeeepy but if you jedi folks can take another peek I'd really appreciate it :)
    $('ul.right li').find('a').click(function() {
            var postType = this.className;
            var count = 0;
            byCategory(postType);
            return false;
    
            function byCategory(postType, callback) {
              $.getJSON('{URL}/api/read/json?type=' + postType + '&callback=?', function(data, textStatus, xhr) { // main callback function
              if(xhr.status == 500 || xhr.status == 404 || xhr.status == 503) {
                      yourErrorHandler(data, textStatus, xhr); // success
                    } else {
                      yourCallbackToRunIfSuccessful(data);   // failed
                    }
                  }
            );
    
    
            function yourCallbackToRunIfSuccessful(data) {  
              var article = [];
                  $.each(data.posts, function(i, item) {
                  // i = index
                  // item = data for a particular post
                  switch(item.type) {
                  case 'photo':
                  article[i] = '<div class="post_wrap"><div class="photo" style="padding-bottom:5px;">'
                                + '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/XSTldh6ds/photo_icon.png" alt="type_icon"/></a>'
                                + '<a href="' + item.url + '" title="{Title}"><img src="' 
                                + item['photo-url-500'] 
                                + '"alt="image" /></a></div></div>';
                  count = 1;
                  break;
                  case 'video':
                  article[i] = '<div class="post_wrap"><div class="video" style="padding-bottom:5px;">'
                                + '<a href="' + item.url + '" title="{Title}" class="type_icon">'
                                + '<img src="http://static.tumblr.com/ewjv7ap/nuSldhclv/video_icon.png" alt="type_icon"/></a>'
                                + '<span style="margin: auto;">' 
                                + item['video-player'] 
                                + '</span>' 
                                + '</div></div>';
                  count = 1;
                  break;
                  case 'audio':
                  if (use_IE == true) {
                  article[i] = '<div class="post_wrap"><div class="regular">'
                                + '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/R50ldh5uj/audio_icon.png" alt="type_icon"/></a>'
                                + '<h3><a href="'
                                + item.url
                                + '">'
                                + item['id3-artist'] 
                                +' - '
                                + item['id3-title']
                                + '</a></h3>'
                                + '</div></div>';
    
                    } else {
                  article[i] = '<div class="post_wrap"><div class="regular">'
                                + '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/R50ldh5uj/audio_icon.png" alt="type_icon"/></a>'
                                + '<h3><a href="'
                                + item.url
                                + '">'
                                + item['id3-artist'] 
                                +' - '
                                + item['id3-title']
                                + '</a></h3><div class="player">'
                                + item['audio-player'] 
                                + '</div>'
                                + '</div></div>';
                    };
                  count = 1;
                  break;
                  case 'regular':
                  article[i] = '<div class="post_wrap"><div class="regular">' 
                                + '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/dwxldhck1/regular_icon.png" alt="type_icon"/></a><h3><a href="'
                                + item.url 
                                + '">' 
                                + item['regular-title']
                                + '</a></h3><div class="description_container">'
                                + item['regular-body'] 
                                + '</div></div></div>';
                  count = 1;
                  break;
                  case 'quote':
                  article[i] = '<div class="post_wrap"><div class="quote">'
                                + '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/loEldhcpr/quote_icon.png" alt="type_icon"/></a><blockquote><h3><a href="' + item.url + '" title="{Title}">' 
                                + item['quote-text']
                                + '</a></h3></blockquote><cite>- '
                                + item['quote-source'] 
                                + '</cite></div></div>';
                  count = 1;
                  break;
                  case 'conversation':
                  article[i] = '<div class="post_wrap"><div class="chat">' 
                                + '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/MVuldhcth/conversation_icon.png" alt="type_icon"/></a><h3><a href="' 
                                + item.url 
                                + '">'
                                + item['conversation-title']
                                + '</a></h3></div></div>';
                  count = 1;
                  break;
                  case 'link':
                  article[i] = '<div class="post_wrap"><div class="link">' 
                                + '<a href="' + item.url + '" title="{Title}" class="type_icon"><img src="http://static.tumblr.com/ewjv7ap/EQGldhc30/link_icon.png" alt="type_icon"/></a><h3><a href="'
                                + item['link-url'] 
                                + '" target="_blank">'
                                + item['link-text']
                                + '</a></h3></div></div>';
                  count = 1;
                  break;
                  default:
                  alert('No Entries Found.');
                  };
                  }) // end each
    
                  if (!(count == 0)) {
                  $('#content_right')
                    .hide('fast')
                    .html('<div class="first_div"><span class="left_corner"></span><span class="right_corner"></span><h2>Displaying ' 
                      + postType 
                      + ' Posts Only</h2></div>'
                      + article.join(''))
                    .slideDown('fast')
                    } else {
                        $('#content_right')
                        .hide('fast')
                        .html('<div class="first_div"><span class="left_corner"></span><span class="right_corner"></span><h2>Hmmm, currently there are no ' 
                          + postType 
                          + ' posts to display</h2></div>')
                        .slideDown('fast')
                    }
    
    
                    // end getJSON
                }; // end byCategory
    
                function yourErrorHandler(data,textStatus,xhr) {
                    alert("Server returned status code " + xhr.status + ".  Try again later.");
                }
            }
        });
    
  • Tiny Giant Studios
    Tiny Giant Studios over 13 years
    Hi jmort, thanks for the speedy reply - at the risk of sounding ridiculously inexperienced I have to say that my exposure to JSON and the like is extremely limited. Would you mind if I asked for some code as I've never worked with XMLHttpRequests before? Heck even a link or two just to point me in the right direction would be awesome :) -- On a sidenote, thank very much for taking the time to scope our the question, it's definitely appreciated...
  • jamesmortensen
    jamesmortensen over 13 years
    Actually, you're not far off. You should take all of the code in the anonymous function after this line &callback=?', and put it in a function called "yourCallbackToRunIfSuccessful". Then replace your original callback with mine, the one that checks xhr.status to see what the response code is. I'll make another clarifying edit.
  • Tiny Giant Studios
    Tiny Giant Studios over 13 years
    Hey jmort - just posted an update: maybe I'm a muppet, or just missed something small, but somehow there's no alert pop-up gracing my ears.
  • jamesmortensen
    jamesmortensen over 13 years
    What is the error code in Firebug, Chrome Debugger, or any other JavaScript debugger that would show you the response code returned by your AJAX call that represents the status on the server when you get the error? I assumed 500, 503, 404, but if it's something not in your list, you'll need to add it to the list of OR conditions.
  • jamesmortensen
    jamesmortensen over 13 years
    I would also suggest you close the function after your return false. Since you're defining your other functions after that, that may be causing problems.
  • Tiny Giant Studios
    Tiny Giant Studios over 13 years
    Yep, regarding the error code - it's still that damn 503. And as for closing the function after the "return false", it didn't make a difference :)
  • Tiny Giant Studios
    Tiny Giant Studios over 13 years
    Oh, I've updated the code with the latest amendments at elegantem.tumblr.com if you wanna have a look - as luck would have it, Tumblr's servers are freaking out with their API atm, so it's ideal to test :)
  • Tiny Giant Studios
    Tiny Giant Studios over 13 years
    The full error code as shown my Chrome's Debugger is: Failed to load resource: the server responded with a status of 503 (Service Temporarily Unavailable)
  • Tiny Giant Studios
    Tiny Giant Studios over 13 years
    So far the new jQuery AJAX error handler seems to be working - although I can't test it as of yet, as (rather annoyingly) Tumblr's server are working fine at the moment. That said, the console.log does log the "Success" perfectly... I'll continue to monitor it throughout the day to see if the error handler works. So far so good - jmort, thank you so much for helping me out on this one. It's folk like you that make SO one of the best tech communities around, top job!
  • Tiny Giant Studios
    Tiny Giant Studios over 13 years
    Just checked the new code - Tumblr's API was finally down again and I was able to check the error handling - worked like a charm! Thanks loads jmort, you've saved my hairline...