ApolloReactOffline icon indicating copy to clipboard operation
ApolloReactOffline copied to clipboard

Unable to stringify context to JSON

Open chidimo opened this issue 3 years ago • 5 comments

First of all, thanks for the detailed tutorial on codeburst

But I'm experiencing a major issue with stringifying context when working with offline mutations. This happens on line 16 in the file src/utils/trackerLink.ts. This line throws an error about not being about circular dependency. When I console logged the context I found that it had lots of properties and methods, of which I can't know exactly what is causing the problem.

const context = operation.getContext();
const contextJSON = JSON.stringify(context); // this fails with Unhandled Rejection (Error): Converting circular structure to JSON

I'm working with apollo-client 3.1.4.

chidimo avatar May 12 '21 00:05 chidimo

hey @chidimo

did you happen to find a solution for this?

:)

sajadghawami avatar Nov 29 '21 09:11 sajadghawami

Hello @sajadghawami I think the problem is related to the fact that the apollo cache has changed very much from when this was written. I ended up taking the cache apart and using what I need. I am using redux toolkit with redux persist to persist the mutations. Works on react-native too.

. So here's what I did to save the mutation info.

import { ApolloLink } from '@apollo/client';
import { v4 as uuidv4 } from 'uuid';
import {
  saveTrackedQuery,
  removeTrackedQuery,
} from '../store/trackedMutations';

export const mutationTrackerLink = (dispatch: any): any =>
  new ApolloLink((operation, forward) => {
    if (forward === undefined) {
      return null;
    }
    const id = uuidv4();
    const name = operation.operationName;
    const queryJSON = JSON.stringify(operation.query);
    const variablesJSON = JSON.stringify(operation.variables);
    operation.setContext({ start: new Date() });

    const context = { ...operation.getContext() };
    delete context.cache;
    delete context.getCacheKey;
    delete context.clientAwareness;

    const contextJSON = JSON.stringify(context);

    if (context.tracked !== undefined) {
      const payload = {
        id,
        name,
        queryJSON,
        contextJSON,
        variablesJSON,
      };
      dispatch(saveTrackedQuery(payload));
    }

    return forward(operation).map((data: any) => {
      if (context.tracked !== undefined) {
        dispatch(removeTrackedQuery(id));
      }
      const time = new Date().getTime() - operation.getContext().start;
      data.requestCompletionTime = time;
      return data;
    });
  });

Here's where I'm doing the actual mutation using the save information.

import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';

import { useApolloClient } from '@apollo/client';

import { getOnlineState } from '../store/online';
import {
  getTrackedQueries,
  removeTrackedQuery,
} from '../store/trackedMutations';
import { updateHandlerByName } from '../updateHandlers/createHandlers';

export const useTrackedQueries = () => {
  const dispatch = useDispatch();
  const apolloClient = useApolloClient();
  const isOnline = useSelector(getOnlineState);
  const trackedMutations = useSelector(getTrackedQueries);

  useEffect(() => {
    const execute = async () => {
      const promises: any = [];
      trackedMutations.forEach((trackedQuery: any) => {
        const query = JSON.parse(trackedQuery.queryJSON);
        const context = JSON.parse(trackedQuery.contextJSON);
        const variables = JSON.parse(trackedQuery.variablesJSON);

        promises.push(
          apolloClient.mutate({
            context,
            variables,
            mutation: query,
            optimisticResponse: context.optimisticResponse,
            update: updateHandlerByName[trackedQuery.name],
          })
        );
        dispatch(removeTrackedQuery(trackedQuery.id));
      });

      if (isOnline) {
        try {
          await Promise.all(promises);
        } catch (e) {
          // ALLOW TRACKED QUERIES TO FAIL
        }
      }
    };
    execute();
  }, [ isOnline ]);

  return {};
};

Sorry if this is too much info. Its just that I like giving as much context as possible.

chidimo avatar Nov 29 '21 10:11 chidimo

@chidimo

thank you very much for the quick reply!

I ended up using apollo-link-offline.

It seems to work so far :)

sajadghawami avatar Nov 29 '21 11:11 sajadghawami

Sure @sajadghawami I'll take a look at it. I like that "it assumes the worst". Lol

chidimo avatar Nov 29 '21 11:11 chidimo

@chidimo

just wanted to update you, apollo-link-offline seems to be buggy so i ended up using your version!

Thanks again :)

sajadghawami avatar Nov 30 '21 12:11 sajadghawami