Within this article, I want to provide a helpful solution in Angular for managing local state when
working with GraphQL. This involves 2 technologies: NgRx ComponentStore & Apollo Angular.
This article will cover topics that involve a basic understanding of GraphQL , Apollo
Angular , and NgRx . If you are unfamiliar with any of these technolgies,
please read up on them before going futher.
With the groundwork layed out, we can now begin the fun stuff! Lets start by building a GraphQL
Query to which we’ll use to fetch our collection of villagers. This is where Apollo Angular comes in
to play. Apollo Angular gives us the ability to construct a GraphQL Query in the form of an Angular
Service. This can be done like so:
Let’s break down what we just did here. We started by creating our expected response data:
IVillagersResponse. Next, we setup our actual Angular Service which is simply extending Apollo
Angular’s Query class. By passing IVillagersResponse in to the class as such, we now gain
Type-Saftey around the Query from wherever we use it.
As for the logic within the Service itself, It’s just GraphQL. This is one of the core principles
Apollo Angular sticks to. As you can see, the query is syntactically identical to what a tradional
Query would look like. Pretty cool, huh?
Now that we have a way of retrieving our data and a component to display it, lets begin our local
state management. For this we’ll use NgRx ComponentStore. Let’s start by creating our store.
With our basic Store now in place, let’s add the logic to interact with our Query we just wrote.
Within our effect, we make use of Apollo Angular’s fetch() method via this.query.fetch(). This
will return a single Observable emmisson and hook in to the effect’s pipeline with ease. On a
successful response, we’ll use the this.addMany(villagers) updater to immutably update our
villagers state. Finally, we have a selector: villagers$ which we’ll use to async bind to our UI.
Now let’s jump back to our component and hook this all up.
Within our Component’s initialization, we are now calling this.store.fetchAll() which is our
Store’s effect which in turn calls our VillagersGQL Query. With that effect, our local state
should then be updated and will now contain a collection of villagers. We can then async bind our
Store’s villagers$ to the DOM.
Ok, so we’ve come along way since we’ve first started; however, there’s still one scenario I’d like
to cover which is GraphQL Mutations. We are able to perform a simple read operation on our data but
what about writes? To do so, let build another Angular Service but instead of implementing the Query
class, we’ll implement the Mutation class. For this example, we will create a Mutation for updating
a villager’s name:
Apollo Angular provides other ways of performing a Mutation.
Just like our Query class, a Mutation can enforce Type-Safety as well. IVillagerEditNameResponse
for the response and IVillagerEditNameVariables for the variables. Also like the Query class
logic, It’s just GraphQL.
Just like we did for VillagersGQL, we utilize a ComponentStore effect to invoke
this.editNameGQL.mutate(update) which returns an Observable and can be hooked in to the pipeline.
On successful response, we then call our this.updateOne(res?.data?.updateVillager) which updates
our single villager record.
Finally, lets update our component to call our effect and update the local state:
Apollo Angular maintains the integrity of GraphQL syntax which allows us to quickly pinpoint what a
particular Service’s Query or Mutation is doing (ex: VillagersGQL). NgRx ComponentStore offers an
intuitive api with minimal setup required for local state management. It also caters to the reactive
approach which blends nicely with our Queries and Mutations.