By Cliff Meyers
Let’s get started!
The Old Way: Use $http Directly
Angular provides the
$resource “services” for making HTTP calls to load data into your app. In tutorials and simple applications these are frequently injected directly into UI controllers:
Here the controller invokes
$http directly and asks it to fetch data from a known URL. The same approach works for
$resource as well. While this approach is simple, it offers limited flexiblity and begins to overcomplicate the controller when data access becomes non-trivial.
Assume we have a number of UI widgets on this page that control the type of donuts we wish to load. When we invoke the backend service, we need to pass parameters to filter the donut based on size, filling, glaze and presence of a hole:
The code to construct the URL is getting more complex and muddying up the controller a bit. Furthermore if we have other views that need to fetch these donuts this code would need to be duplicated. Clearly we can improve the design through some refactoring and application of patterns.
The New Way: Use a Repository
This technique involves adding an intermediate layer between the controller and
$http that encapsulates data access and simplifies the code in the controller. Here’s a simple example of this expressed as an Angular module:
Note: I’m calling this intermediate a “Repository” although other terminology is likely valid, based on your preference. See “Quick Note on Names” below.
The Repository provides a very similar API to
$http in that it ultimately returns a Promise that is later resolved with the data returned by the server. However, it exposes a set of methods which provide a cleaner API to the controller rather than forcing it to perform string concatenation to build up URLs that are passed to
Using a Repository to Swap Out Mocks and Real Services
Now let’s explore how we can easily swap out real and mock services with another simple Angular module example:
Now we have a new “mock” implementation that loads a JSON file from the local web server. We use Angular’s
factory method to control exactly what object is bound as
donutRepository for injection into the controller. Alternatively the mock implementation could simply create its own data programmatically and return a promise using the
configModel referenced by the factory above is a simple object that holds configuration information about the application. The implementation below allows us to control the config options by passing parameters via the URL to the AngularJS app on startup:
Accessing the application via ‘http://some.url/index.html#?useMocks=true will enable mock mode, based on the code above.
Once we push all data access code into its own discrete layer we can derive other benefits as well. We can easily centralize cross-cutting concerns such as logging or caching into our repository layer. If we need to implement offline mode in an application, each repository can collaborate with a service that queues up requests and pushes them to
$http once the application comes back online. This is vastly preferrable to managing this complexity in a controller.
I’ve built a very basic “Reddit Browser” AngularJS application that provides a working sample of these techniques. The code is available on Github here.
Clone the repo and then start the Node web server script using:
The app will be available here:
“Mock mode” can be run easily via hitting ‘dev.html’ instead.
Feedback is encouraged. Drop me a comment below or hit me up on Twitter.
A Quick Note on Names
I pushed this section to the end because it’s just dealing with semantics. I chose “Repository” as the term for the the new data access layer but there are a variety of terms that are sensible. At the end of the day, the name has significance but the application of the pattern is what really matters. Here are a few other options:
- Proxy: because the intermediate sits between the client controller code and (ultimately) the backend server hosting the service. However, “Proxy” is an extremely generic pattern and doesn’t really tell us what it’s acting as a proxy to.
- Service: due to the popularity of the Service Oriented Architecture (SOA) buzzword, components residing on a server that return data in a HTTP response are frequently called “Services.” Therefore we could call the intermediate a Service. However, in the context of an AngularJS application this would be confusing since “service” is used generically to describe virtually any object available for dependency injection in the AngularJS context.
- Repository: made popular in Eric Evans’ book entitled Domain-Driven Design: Tackling Complexity in the Heart of Software, a Repository can be used in server side code to encapsulate querying and persistence, ultimately returning one or more Domain Objects. This aligns pretty closely with what’s going on in the AngularJS app so I decided to go with it.
- Data Access Object (DAO): this one is popular in Java circles. It’s probably at least as valid as Repository, perhaps moreso since it doesn’t carry along the Domain Model connotations.
It’s up to you. Pick what you like.