Quick Look – Angular Service Swap
Dependency inversion is a common software engineering concept. It is the D in SOLID. With DI we are intentionally not programming against a particular implementation. Often this manifests itself by passing the implementation into a service through its constructor. This is called constructor injection.
Angular uses constructor injection within its architecture. Services are injected into components and other services using constructor injection.
Angular is a little unique in that you don’t program to abstracts, or the L in SOLID. Instead, you program against the actual services. Why? Angular is built on top of TypeScript, which provides real static types on top of the JavaScript programming language. TypeScript provides interfaces, but those interfaces are only a compile-time artifact. There is no way to check is something an interface at runtime. This makes using interfaces a difficult proposition for a DI solution.
Angular’s lack of programming against an interface is a pretty minor issue. Most of the time you won’t even notice. But what if you want to have a mock version of a service completely in Angular? You are going to have to solve this problem.
In our ongoing example of a ContactService that communicates with a backend to retrieve contacts, we know that writing a version that communicates to a ASP.NET backend will take some time and effort. It also means we can’t run our frontend Angular project without having our ASP.NET backend up and running. When building a complex frontend it is nice to first build it against mock data, then build the real backend piece later.
To save some time, we could begin by building our service against mock data and then rewrite it later to call the real server.
But an even better approach would be to keep the mock version of the service around if we ever need to run against it sometime down the road.
To do this, we will first add both mock and non-mock services.
One version of the service will return mock data. The other version will call a real backend.
This will get us really close, but we now have a big problem. We need to create a new environment configuration. To do this, we will have to add a new configuration to the environments folder.
And will have to update the Angular.json file.
Now we can run the application while using the mocks. This is done using the -c option when running ng serve.
ng serve -c mock
You may ask why not just mock out the HttpClient? Actually, in a previous blog post we discussed this very concept. If there is another solution, why not use that solution. While I think that solution is great for unit testing, I like a complete service replacement while building out the application.