9

I am hitting a number of API's from JQuery, and caching the result of each so that the data can be re-used multiple times in the page to render some dashboard widgets in different formats.

The problem is that if an API returns a 500 status code with error, I don't want to try and draw the widget, but capture the error in a friendly way.

However, I cannot figure out how .catch works with the JQuery.ajax() function. After reading here, here, here, here and a dozen others, I've got so far but always get the same console error:

TypeError: LoadDataFromApi(...).then(...).catch is not a function

I've tried to comment the code to explain what I'm trying to do at each stage. Please somebody explain why the whole .catch thing isn't working for me.

// Cache object to save API data for re-use
var requestCache = {};

// Get API data and save to cache 
function LoadDataFromApi(apiUrl) {
    if (!requestCache[apiUrl]) {
        var result = $.ajax({
            type: 'GET',
            url: apiUrl,
            dataType: "json",
            statusCode: {
                500: function (xhr) {
                    var err = JSON.parse(xhr.responseText);
                    console.log('Message:' + err.Message);
                    // throw err.Message; // removed because this was always an "uncaught exception", even if used within try/catch
                },
                200: function (xhr) {
                    // Do nothing here - put result into cache regardless of status code
                }
            }
        });
        requestCache[apiUrl] = result; // save the JSON data into cache
    }
    return requestCache[apiUrl];
}

// Called by page on load
function LoadJsonData() {
    LoadDataFromApi('/api/GetFoo?Row=10')
        .then(function (data) {
            RenderChart(data, 'Removed for legibility');
        })
        .catch(function (error) {
            console.log('Promise catch: ' + error);
        });
    LoadDataFromApi('/api/GetFoo?Row=10') // this returns cached data because API has already been hit
        .then(function (data) {
            RenderChart(data, 'Removed for legibility');
        })
        .catch(function (error) {
            console.log('Promise catch: ' + error);
        });
    LoadDataFromApi('/api/GetBar')
        .then(function (data) {
            RenderChart(data, 'Removed for legibility');
        })
        .catch(function (error) {
            console.log('Promise catch: ' + error);
        });
}
EvilDr
  • 8,943
  • 14
  • 73
  • 133
  • 1
    Also jquery has it's own implementation of promises (basically because they were doing this before promises became a thing). It requires a `fail` not `catch` call. – Liam Oct 12 '18 at 10:34
  • I know this is a big ask, but my head is spinning from a day on this. Could you please help apply that re-structure so I can see this in action? It's really important that the cache is respected, so API's aren't called twice unnecessarily, and it's this complexity that's making this so much more difficult to grasp. – EvilDr Oct 12 '18 at 10:36
  • 1
    @Liam I think you're wrong - look at the implementation of `LoadDataFromApi` - it evidently returns `jQuery.ajax()` result, not the cache object itself :) – SzybkiSasza Oct 12 '18 at 10:38
  • Yes, I've just seen that @SzybkiSasza , sorry – Liam Oct 12 '18 at 10:38
  • Obviously not enough coffee this am. – Liam Oct 12 '18 at 10:40

2 Answers2

10

Use .fail() as described in your first link here

Depending on your jQ version

"Deprecation Notice: The jqXHR.success(), jqXHR.error(), and jqXHR.complete() callbacks are removed as of jQuery 3.0. You can use jqXHR.done(), jqXHR.fail(), and jqXHR.always() instead."

EDIT: You error callback should accept 3 arguments, so make it so

function(jqXHR,textStatus,errorThrown ){}
MKougiouris
  • 2,821
  • 1
  • 16
  • 19
  • As per the comment on the other answer, I've swapped that out, but how do I interrogate the object that remains to get the data within there please? – EvilDr Oct 12 '18 at 10:47
  • Ah fantastic, that was the issue. I see that the JSON data is within jqXHR which is great. That's all working perfectly now. Thank you. – EvilDr Oct 12 '18 at 12:01
5

JQuery does not return typical promise, it's$.Deferred in that case:

More on that here, with answers: Deferred versus promise

SzybkiSasza
  • 1,591
  • 12
  • 27
  • Okay... If I swap out `.catch` with `.fail (function(error) {...}` the console is showing the output `Promise catch: [object Object]`. How can I interrogate this please to get the error details, or whatever exists in this? – EvilDr Oct 12 '18 at 10:45