Requesting and Saving External JSON data? http.get vs $resource?


#1

I have an external (well, currently local) API which returns JSON formatted data.

I’m looking for the simplest way to request and store the data locally (all lookups will be performed on the saved file). There will be no additional communication with the API after initial retrieval.

However I’m getting about 3-4 different ways to do it with very poor explanations.

I think http.get is what I want and I’ve been playing with it; however I have a problem when trying to use the data in my service that returns a list.

The following code, when executed, will return the empty var (set in the first line), rather than the result defined within .then

My console logs “return” and “[]” before “data success” and a proper object. (My controller is simply $scope.things = getstuff.all();)

.factory('getstuff', function($http) {
  var things = [];

  $http.get('http://mylocalhost.api/with/token')
    .success(function(data, status, headers,config){
      console.log('data success');
      console.log(data); // object seems fine
    })
    .error(function(data, status, headers,config){
      console.log('data error');
    })
    .then(function(result){
      things = result.data;
    });

  return {
    all: function() {
      console.log('return');
      console.log(things);
      return things;
    }
  }
})
  1. How do i fix what I’m doing incorrectly with passing the result back

secondary:
2) How do I cache the result (for a browser based app)
3) How would I save that result to local file storage (for a native phone app)


#2

You might want to look at Angular-cache.
http://jmdobry.github.io/angular-cache/guide.html

Can be configured to do all of that.


#3

Looks pretty decent for steps 2 and 3, especially syncing with the local storage. Nice.

However I’m still stuck with issue 1, where the code is seemingly being executed backwards in my getstuff .factory. (Unless the http.get is happening asynchronously, meaning that the full code block gets executed before there’s an actual success response of data). In which case should I put my return inside the .then block?


#4

If I understand this correctly, you are declaring a variable called “things”, then firing off a promise in the form of $http.get(), and finally returning an object. The promise isn’t going to be resolved immediately. This results in your object being executed and returned before $http.get() is resolved.

You might want to take a look at the $q service and how promises behave. Or simply return the $http.get() and append the .then() to the injected service in your controller. The other alternative is have:

return $resource('http://mylocalhost.api/with/token');

and in your controller:

$scope.things = getstuff.get();

or

var things = getstuff.get(function() {
  $scope.things = things;
});

Restangular might also be one to look at. It is quite powerful, it also deals with ETags which can radically improve performance.


#5

Pushing the values to the array seems to solve the issue of the data not being available in my view. (without using push in .then(), my things array is empty to the view and will never display content).

So as it stands now, my view pops up with no content, and once it’s successful, the array is pushed and volia, my view populates.

var things = [];

  $http.get('http://local/api/')
    .success(function(data, status, headers, config){
      console.log("**** SUCCESS ****");
      console.log(status);
    })
    .error(function(data, status, headers, config){
      console.log("**** ERROR ****");
      console.log(status);
    })
    .then(function(response){
      console.log("**** THEN ****");
      
      var jsonData = response.data.mythings;
      var jsonKeys = Object.keys(jsonData);

      for (var i = 0; i < jsonKeys.length; i++) {
        var jsonSingle = jsonData[jsonKeys[i]];
        things.push(jsonSingle);
      }
    })

  return {
    all: function() {
      return things;
    }
  }

However, if I don’t have an array to push, i can never get the data from .then() into my view. So I’m currently stuck doing an ng-repeat for single items which sucks. (using the above code with a for loop when I expect only 1 result)

So how do I “push” a single object/variable from within .then()?


#6

Why use then at all in your $http.get? .success and .error handle all your needs.


#7

It presents the same problem if I put it in .success(), so there really isn’t much difference.


#8

An alternative solution is to paste the API URL into json-csv.com - then you can download the CSV file to local storage on your device.