Update 12 September 2013: some folks have inquired why I didn't use RESTangular in this blog. I think RESTangular is a fine framework that is more flexible than Angular's
$resource abstraction. However, for simple sample code it makes more sense to use
$http since more folks are familiar with it. Also, the question misses the main point of this blog post which is applying a pattern so data access code is abstracted, thereby simplifying the controller code. If your application grows and requires new code to implement custom caching or request queueing logic, the Repository will be the perfect place to do it. You can apply this pattern with
$resource, RESTangular or any other data access framework. And that's the whole point: by abstracting the data access code, the controller doesn't care how data is fetched; it only expects a promise to be returned which will later be resolved or rejected.
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 nontrivial.
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 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 as
$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 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: "blog-examples" repository
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
Feedback is encouraged. Drop me a comment below, use my contact form 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. :)