Lightning Web Components and Apollo Client

An example of using Apollo Client with Lighting Web Components.

Motivation

For many who have been developing using React, Apollo Client has become a go-to tool for consuming GraphQL APIs. In many cases, it also has become the go-to tool for managing global state.

While Apollo Client often is associated with React, it is actually a view agnostic library that can be integrated with a variety of view libraries. As such, we will explore how to integrate it with Lightning Web Components.

note: The apollo-elements library is listed as a Web Components view integration solution; seems like it would be a natural fit for Lighting Web Components. As I found documentation sparse, I decided to explore integrating Apollo Client without it (or any view integration library for that matter).

The completed example is available for download.

Prerequisites

This article assumes that the reader is already developing with Lightning Web Components; see the article Lightning Web Components (The Open Source Version).

The article also assumes that the reader has been using Apollo Client; presumably with React.

To follow along, the required development tools are:

  • Docker
  • Node.js (examples developed using 10.16.0 LTS)
  • A text editor; recommend Visual Studio Code

The GraphQL API

In order to develop with Apollo Client, we need a GraphQL API. We can follow the Quick Start GraphQL Server section of the article Apollo Client with Arbitrary GraphQL Schemas: Part 1 to create a todos GraphQL API.

The relevant queries and mutations are:

  • allTodos: Query reading all the todos
  • createTodo: Mutation creating a todo

The Example

The example consists of a form to create todos followed by a list of todos.

The implementation consists of one module (client) and two Lightning Web Components (todos and todosCreate).

client

A module that exports an instance of ApolloClient.

src/modules/my/client/client.js

todos

The component that displays todos.

src/modules/my/todos/todos.html

Observations:

  • The Todos component has three tracked properties: loading, error, and todos
  • The boolean loading property is only true when the allTodos query is executing
  • The boolean error property is only true when the last allTodos query had an error
  • The todos property is an array of todos

src/modules/my/todos/todos.js

Observations:

  • When the component connects, it starts by using ApolloClient’s watchQuery method to subscribe (the subscription) to the allTodos query in the cache
  • The component, when connected, finishes by executing the allTodos query
  • When the component disconnects, it unsubscribes the subscription

todosCreate

The component that provides a form to create todos.

src/modules/my/todosCreate/todosCreate.html

Observations:

  • The TodosCreate component has three tracked properties (loading, error, title, and valid), one computed property (invalidOrLoading), and two methods (handleInput and handleSubmit)
  • The boolean loading property is only true when the createTodo mutation is executing
  • The boolean error property is only true when the last createTodo mutation had an error
  • The string title property is the value of the controlled input
  • The boolean valid property is only true when the form is valid, i.e., when the title property is not blank. This property is not directly used in the component’s template; rather used in the invalidOrLoading computed property
  • The boolean invalidOrLoading computed property is used to disable the submit input when either the valid property is false or the loading property is true
  • The handleInput method updates the title property as the input changes
  • The handleSubmit method executes the createTodo mutation

src/modules/my/todosCreate/todosCreate.js

Observations:

  • The handleMutationUpdate function updates the allTodos query in the cache once the createTodos mutation successfully completes

Wrap Up

We have just implemented Apollo Client within a Lightning Web Component application without the use of any view integration libraries. Looking back at the example code, it is a bit questionable that we even need a view integration library; guessing we would only save about 30 lines of code in this example if we did.

That being said, if we wanted to create such a view integration library for Lightning Web Components, we would have to use a development pattern that supports cross-cutting concerns. Unfortunately this is an unresolved issue (as of the writing of this article) with Lightning Web Components.