Getting used to asynchronous requests

facebooktwittergoogle_pluslinkedin

Another week working with Angular JS has passed any I start taking looks into the insides of the frameworks – with it’s benefits and troubles. On one hand I’m in awe of the extremely simple way to mock your whole backend (I’ll certainly talk about that in a future post) and I’m having troubles with some concepts. One of these concepts is the way to handle asynchronous REST requests and I’d like to evolve a bit on that.

Sending requests with Angular

There are two obvious ways to communicate with a backend in Angular. One is the $http service from the core Angular module and is the service $resource from the module of the same name. In the end they both do the same: By specifying URL, parameter and request method, the communicate with remote HTTP servers.

But $resource is more abstract as it creates a resource object on which you can then set your requests. But that might just be personal taste. What is important to know, is that both immediately a promise of an answer and not a answer itself. This makes asynchronous requests possible. I never worked with promises before and immediately fell into some pitfalls.

Dealing with promises

Take a look at the following code:

$httpBackend.whenGET('/rest/employees').respond($resource('/test/mock/employees.json').query());
$httpBackend.whenGET(/^\/rest\/employee\/[0-9]*/).respond($resource('/test/mock/employees.json')
    .query().filter(function (employee) {
        return employee.id == 1;
    })[0]);

What I tried to here, is to tell my mocked backend to return specific json objects for specific requests. The first one fetches all employees and returns them as an array. Lazy as I am, I tried to be smart in the second one and reused the same json file to return a single employee (with the ID 1, regardless the id in the parameter).

The first requests works as intended. The second one always returns null.

When I started to look into the problem I first realized that it’s much more difficult to debug asynchronous requests and soon after that I realized that this second line never works with promises, as it will evoke filter(function) on an empty array and then return that.

The solution? Well, I just overcame my laziness and wrote a new proper json object.

The second problem I encountered was the following: When I want to display a project, I also want to display it’s start date and end date. But these properties do not exist on this entity, only on the releases belonging to a project. The project duration can then be deriven from the length of it’s releases (e.g. a Project has Release 1 starting in June 11 and Release n ending in January 12, the project duration would be June 11 – January 12).

Okay, to display that I wrote a function that fetches those dates from a project and I called this method from my view. I did not work again because we’re dealing with promises hear: Funny enough the methods on rendering the view are called twice before the request to the backend has it’s response (don’t know exactly why that often).

Luckily the request methods on the $resource object also offer callbacks for a success and the error. So  could overcome it as follows:

$scope.project = $resource('/rest/project/:projectId', {projectId:'@id'})
    .get({projectId:$routeParams.projectId}, function (project) {
        var r = project.releases.sort(function (a, b) {
            /* Sort releases descending */
            return b.nr - a.nr;
        });
        project.start = r[r.length - 1].start;
        project.end = r[0].end;
    });

Yes, I have to be careful with nesting…

Conclusion

Anyway, so the way the requests are handled in Angular is quite nice, but you have to get used to the fact, that you can never rely on an actual response. At least I have to get used to it. It’s a bit of a different mindset.

I hope I could provide you some insight on that.