apollo-link-queue icon indicating copy to clipboard operation
apollo-link-queue copied to clipboard

Queue Event Listeners for Queue Persistence + Operation Type Filtering

Open robnewton opened this issue 3 years ago • 4 comments

I've pulled from a couple of other projects to develop a queue persistence package that is working for us in React Native. Here's the changes I made to this package for it to work. Per feedback @helfer gave to others about persistence not belonging in this package I took the approach of using the listeners from another PR and extended it a bit. Then I developed the other package https://github.com/SocialAutoTransport/apollo-link-queue-persist to make use of these changes.

Optional filtering

import QueueLink from 'apollo-link-queue';

const queueLink = new QueueLink();

// Optionally only queue mutations
QueueLink.setFilter(['mutation']);

// To start queueing requests
queueLink.close();

// To let requests pass (and execute all queued requests)
queueLink.open();

Link Queue Event Listeners

Listeners allow for a system outside to be notified when an enqueue or dequeue event occurrs. You can register a listener for a specific operation name or pass the keyword "any" to listen to all operations using the static method QueueLink.addLinkQueueEventListener().

QueueLink.addLinkQueueEventListener() takes the following parameters: - Operation name to listen to. Valid values are any or an actual operation name string from the mutation or query you want to be alerted on. - The enqueue or dequeue string to specify which event to listen to, - A callback function that takes a single parameter which will be the operation from the queue that is being acted upon.

    QueueLink.addLinkQueueEventListener("insert_myObject", "enqueue", (item: any) => {
      console.log('QueueLink listener (insert_myObject, enqueued) fired with item: ', item);
    });

    QueueLink.addLinkQueueEventListener("insert_myObject", "dequeue", (item: any) => {
      console.log('QueueLink listener (insert_myObject, dequeue) fired with item: ', item);
    });
    QueueLink.addLinkQueueEventListener("any", "enqueue", (item: any) => {
      console.log('QueueLink listener (any, enqueued) fired with item: ', item);
    });

    QueueLink.addLinkQueueEventListener("any", "dequeue", (item: any) => {
      console.log('QueueLink listener (any, dequeue) fired with item: ', item);
    });

Usage

import AsyncStorage from '@react-native-async-storage/async-storage';
import { persistQueue, AsyncStorageWrapper } from 'apollo-link-queue-persist';
import QueueLink from 'apollo-link-queue';
import {ApolloClient, InMemoryCache, ApolloProvider, HttpLink, ApolloLink} from '@apollo/client';

const queueLink = new QueueLink();

const client = new ApolloClient({
  link: ApolloLink.from([queueLink, httpLink]);,
  cache: new InMemoryCache(),
});

await persistQueue({
  queueLink,
  storage: AsyncStorage,
  client,
});

robnewton avatar Apr 26 '21 17:04 robnewton

Hi @robnewton, thanks for posting here. If I read your intentions correctly, you're not actually expecting to get this merged, right? Maybe the best thing to do would be to update README.md and link to your package if you think it's ready to be used by others?

helfer avatar Apr 28 '21 09:04 helfer

I was hoping to have it merged so that I do not need to maintain a separate fork ongoing. Once it’s merged I can update the apollo-link-queue-persist package deps to reference this instead.

robnewton avatar Apr 28 '21 11:04 robnewton

The setFilter() doesn't appear to be working correctly as implemented in our fork so I am using the following in the meantime. When I get it fixed in our fork I will follow up, or might just remove it, haven't decided.

    // Determine if an operation is a mutation
    const isMutationOperation = operation => {
      return operation.query.definitions.filter(e => e.operation === 'mutation').length > 0;
    };

    // Only allow mutations to be queued
    const onlyQueueMutationsLink = new ApolloLink((operation, forward) =>
      isMutationOperation(operation) ? queueLink.request(operation, forward) : forward(operation),
    );

Also as info I've added a couple new features to the queue persist library we are using along side our fork to do queue persistence to Async Storage in React Native. Below is an example showing the new onCompleted and onError functions.

await persistQueue({
  queueLink,
  storage: AsyncStorage,
  client: apolloClient,
  onCompleted: (request, response) => {
    console.log('Called onCompleted()', request, response);
    //Optional request specific handling
    if (request.context.customProperty === 'some specific value') {
      console.log('Do something specific based on that query or mutation running successfully');
    }
  },
  onError: (request, error) => {
    console.error('Called onError()', request, error);
    //Optional request specific handling
    if (request.context.customProperty === 'some specific value') {
      console.error('Do something specific based on that query or mutation failing');
    }
  }
});

robnewton avatar Apr 30 '21 17:04 robnewton

@helfer did you ever give this anymore consideration to merge in?

robnewton avatar Apr 03 '23 22:04 robnewton