Never worry again about your GraphQL API breaking changes
Published: 2024-03-14 09:38:17

## Problem

We deploy our API and our frontend at the same time. It means our new frontend contains the necessary changes to match the new API ⇒ great ✅.
🚨 But a user can keep their browser opened with the previous frontend code version, as a consequence the previous frontend version calls the new API, and if there are breaking changes in the modifications ⇒ it breaks 💥.


![Breaking change illustration](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q859j9fj3pf7erhwx2i0.png)

## Our previous solution 

_🚨 Spoiler: not the one we recommend now, scroll down to '**Our new solution**' if you want to go straight to the point_

For a long time, here is how we have handled our breaking changes:

- **deprecate** the concerned field in the API instead of deleting/modifying it
- add the new one
- merge the pull request 
- wait for 7 days: totally arbitrary timing, we considered that after 1 week, all our users would have refreshed their frontend
- remove the deprecated field

### Pros and cons:
- 🟢 no impact at all for most users
- 🔴 not efficient for developers (2 pull requests, with a week delay between it)
- 🔴 not perfect: the 7 days delay is arbitrary, some users can still face a bug
- 🔴 we often forgot to clean the deprecated field: legacy code remaining in the codebase

We wanted to improve that situation.
Here are the solutions we considered:
- ❌ [API versioning](https://blog.hubspot.com/website/api-versioning): too costly to put in place versus the gain + GraphQL does not recommend it (see [best practices](https://graphql.org/learn/best-practices/#versioning))
- ❌ [Fields versioning](https://blog.logrocket.com/versioning-fields-graphql/): forces you to maintain legacy code in the backend
- ✅ **Automatically refresh the user frontend when they face an API breaking change**: this is the solution we chose and I will explain below how we implemented it.

## Our new solution
👉 Automatically refresh the user frontend when they face an API breaking change

![Automatic window reload](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aouqncvqih9yk2xfxyxm.png)

### How to 
- In your **ApolloClient**, if you do not have one already, you will need to add an **errorLink**
![error link](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f2vh92w5mnwy0ar5h1kg.png)

- Build this errorLink thanks to the given onError link furnished by @apollo in _@apollo/client/link/error_:

```typescript
import { onError } from '@apollo/client/link/error';

const errorLink = onError(({ graphQLErrors, operation }) => {
  if (graphQLErrors) {
    /* We are targeting here GraphQL API breaking changes 
    * due to schema changes which correspond to code 
    * 'GRAPHQL_VALIDATION_FAILED'
    */ 
    const validationErrors = graphQLErrors.filter(
      ({ extensions: { code } }) => 
          code === 'GRAPHQL_VALIDATION_FAILED',
    );

    if (validationErrors.length > 0) {
      const isMutation = operation.query.definitions
        .filter(
          (def: DefinitionNode): def is OperationDefinitionNode =>
            def.kind === 'OperationDefinition',
        )
        .some(
          ({ operation }) => operation === 'mutation',
        );

      if (isMutation) {
        /* In case of a mutation being affected 
        * by the breaking change,
        * as the data they entered will not be saved
        * we decided to display a pop up to the user 
        * so they can collect their data before losing it 
        * to avoid frustration, if it was a long text for example.
        */ 
        if (
          !window.confirm(
            "Sorry, the page needs to refresh to work properly.\n\n** You'll need to enter your latest data again **\nNote that you can:\n1. Click on 'Cancel'\n2. Copy your data\n3. Refresh the page\n4. Paste your data back\n\nSorry again for the inconvenience.\nThis will lead to improvements for you down the road.",
          )
        ) {
            return;
          }
        }

        window.location.reload();
      }
    }
  });
```
      
### Pros and cons:
- 🟢 no mental load for the developers (API fields can be modified/deleted with peace of mind)
- 🟢 the legacy code is removed right  away
- 🟠 small impact on user experience: users can face an auto reload or a pop up in the case of a mutation

### One last thing
Do not forget to stop your error alerting on 'Validation errors' if you had some, because you won't need it anymore.

---

_If you have any feedback, please feel free to comment! Thanks 🙏_