Faster Modern Apps with Angular and GraphQL

Jeff Cross

Nowadays, with more people relying on their mobile devices more frequently, users require more from mobile applications. They need mobile apps to work well, be stable and fast, and have a full set of features and capabilities.

In order to satisfy these demands, applications and frameworks have been moving away from a page-driven model, in which a single page controls everything about the application, and toward a component model. Components are self-contained building blocks containing functions and data that are used to construct an application, which is composed of multiple components in a top-to-bottom hierarchy. The application itself is a component, each of the application's routes is a component, and each route has child components that communicate and cooperate to perform a given task.

Components are favored for several reasons: They can be developed in isolation from one another, they can be used and reused in many different contexts if need be, and they have well-established contracts that define what they expect from the parent component while encapsulating their own state and behavior.

The Challenges of Angular

When building component-based applications in AngularJS, developers often face the question of how data will be passed to child components. Answering this question requires addressing three major points of consideration: the performance of the application, the maintainability of the various components, and the consistency between parent and child components.

One possibility is to use "self-fetching": fetching the data inside the component by injecting Angular's $http service. For example, during the ngOnInit() lifecycle hook, after the components initialize, the data can be fetched as an Observable and unwrapped using Angular's AsyncPipe. However, this option has a major drawback. The application will be making repeated XMLHttpRequests one at a time, which will block the other requests in the queue until it is completed. It could also be making redundant requests for data that might have already been loaded elsewhere in the application. This also means that if the data changes on the server between requests, it will be inconsistent when the application retrieves it at two different times.

Another possibility is to put a service in the component. Angular uses services for managing things such as state between components and data that should be shared. However, this choice will result in a lot of additional complexity and consideration. Developers will need to think about whether they want to batch requests or cache them and how to invalidate the cache if they choose the latter option. In addition, the component and the service will now be coupled, which makes the component a little less reusable. Anywhere that the component will be, the application will have to use this service and make sure that the service is provided.

A third option is to use "model passing": passing the full data from the parent component to the children components. However, this is not an ideal choice either. For one, the application becomes "leaky" because the parent component needs to know what the child component requires. If the child ever changes its view, the parent has to make sure that it's providing the child with all the required properties. This can be problematic for children components with many properties. As a result, this option creates an API maintenance burden for the developer to make sure the parent and child components know what to expect from each other. Finally, it's not safe to assume that the parent will always have the data needed by the child.

Use GraphQL with Angular

Angular and GraphQL

GraphQL can be used with Angular to improve on the three imperfect solutions mentioned above. Developers who work with both Angular and GraphQL have cited three main concepts behind the two technologies that have generated benefits for their development process:

  1. A component-based API. With GraphQL, the client is able to request and receive exactly what it needs from the server using composable queries. Data dependencies can be placed inside the component itself, making components truly reusable and self-contained. Any changes to a component do not need to be reflected in the parent component, the service, or anything else. This addresses the concern about the application's maintainability.
  2. A singular request per singular render. Users usually want their apps to be as fast as possible. Angular has been able to provide excellent performance during rendering, but this means that the bottleneck in performance is now the network itself. In order to provide strong performance, developers need to ensure the application will make only one request to the server per render. This addresses the concern about the application's performance.
  3. A GraphQL-First approach. Because GraphQL is a static, analyzable schema with types, application development can begin by formulating the GraphQL schema. The front-end and back-end developers can then go their separate ways and develop their parts independently of one another, while being assured that the application will work when the various parts are connected. This addresses the concern about the application's consistency.

More broadly, although these three concepts are applicable to Angular, they are also applicable to any view layer, whether that be Angular, React, Vue.js or something else. Much of the code can be moved out of the view layer and into the GraphQL client (such as Apollo or Relay) itself, which simplifies the process of switching between view layers. It also makes it easier to share code with other external developers who may be using a different view layer.

Watch the video