Giter Site home page Giter Site logo

Comments (7)

oluwie avatar oluwie commented on September 25, 2024

Hi @toddtarsi, I was hoping you could hep me out. I have trouble getting this library to work with Apollo 2.0. I was hoping you could help me in my implementation to see what I'm doing wrong.

This is how I'm implementing my Apollo client.
const link = ApolloLink.from([addHeaders, stateLink, restLink, httpLink]); const apolloClient = new ApolloClient({ cache, link });

const newApolloClient = addPersistedQueries(apolloClient, queryMap);
export default newApolloClient;`

I'm using the apollo graphql function from react-apollo for querying but the queries don't seem to be getting transformed.

Any help would be greatly appreciated.

Thank you!

from persistgraphql.

toddtarsi avatar toddtarsi commented on September 25, 2024

I'll do my best @oluwie -

Okay, so this is how I'm using persistgraphql with a small commander script to build my queries:

// @flow

/* eslint-disable no-console */
/* eslint-disable import/no-extraneous-dependencies */

import program from 'commander';
import { ExtractGQL } from 'persistgraphql/lib/src/ExtractGQL';
import queryTransformers from '../helpers/queryTransformers';

program
  .version('0.1.0')
  .usage('[options] <file...>')
  .option('-i, --input <p>', 'Input Directory', '')
  .option('-o, --output <p>', 'Output file', '')
  .parse(process.argv);

new ExtractGQL({
  inputFilePath: program.input,
  outputFilePath: program.output,
  queryTransformers,
}).extract();

My queryTransformers file is the following. It looks a bit crazy, but uses the addTypename transform, as well as another transform I wrote to strip all client fields. I intend to open source that this weekend (edit: i fixed the d.name.value check later):

// @flow

/* eslint-disable no-console */
/* eslint-disable import/no-extraneous-dependencies */

import {
  DefinitionNode,
  DocumentNode,
} from 'graphql';
import { QueryTransformer } from 'persistgraphql/lib/src/common';
import { addTypenameTransformer } from 'persistgraphql/lib/src/queryTransformers';

function removeClientFieldsFromSelectionSet(selectionSet) {
  if (selectionSet.selections) {
    // eslint-disable-next-line no-param-reassign
    selectionSet.selections = selectionSet.selections.map((selection) => {
      if (selection.directives && selection.directives.length) {
        const hasClient = selection.directives.find(d => d.name.value === 'client');
        if (hasClient) return false;
      }
      if (selection.kind === 'Field' || selection.kind === 'InlineFragment') {
        if (selection.selectionSet) {
          removeClientFieldsFromSelectionSet(selection.selectionSet);
        }
      }
      return selection;
    }).filter(s => !!s);
  }
  return selectionSet;
}

const removeClientFieldsTransformer: QueryTransformer = (doc: DocumentNode) => {
  const docClone = JSON.parse(JSON.stringify(doc));

  docClone.definitions.forEach((definition: DefinitionNode) => {
    const isRoot = definition.kind === 'OperationDefinition';
    removeClientFieldsFromSelectionSet(definition.selectionSet, isRoot);
  });

  return docClone;
};

export default [
  addTypenameTransformer,
  removeClientFieldsTransformer,
];

As a note, it's currently impossible to use custom transforms with https://github.com/leoasis/graphql-persisted-document-loader until leoasis/graphql-persisted-document-loader#2 is accepted, at which point you'll be able to pass in your own queryTransformers via the webpack loader. I have a fork doing this, which I'm using here: https://github.com/toddtarsi/graphql-persisted-document-loader. This is what that looks like inline with the webpack stuff:

import persistedQueries from './persistedQueries.json';
import queryTransformers from './queryTransformers';
...
        {
          exclude: /node_modules/,
          test: /\.(graphql|gql)$/,
          use: [
            {
              loader: 'graphql-persisted-document-loader',
              options: {
                generateId: query => persistedQueries[query],
                queryTransformers,
              },
            }, // <= Before graphql-tag/loader!
            { loader: 'graphql-tag/loader' },
          ],
        },
...

Note, if this isn't accepted, we're both over a barrel, hah!

Also, in case it's an issue in the link ordering, this is the overall order of my link components too:
[error, context, state, persisted-queries, http].

Hope this helps!

from persistgraphql.

toddtarsi avatar toddtarsi commented on September 25, 2024

Oh, @oluwie - This is how I'm building my persisted-queries link more granularly:

  const persistOpts = {
    generateHash: ({ documentId }) => documentId,
    useGETForHashedQueries: false,
  };
  const httpLink = from([
    createPersistedQueryLink(persistOpts),
    new HttpLink(network),
  ]);

from persistgraphql.

toddtarsi avatar toddtarsi commented on September 25, 2024

To provide a bit more explanation of why this is needed (last post honest):

In 2.0, our issue is this:

By the time the query has reached the http request, it has been transformed since the initial expectation (in our case, missing client fields). If we remove these fields from the fragments, we lose our data dependencies. If we keep these fields, the serverside queries will fail to match what the client sent up.

So, to get our shape back to matching, we have to transform our persisted queries to be the correct shape right before it goes out over http. By trimming our client fields here, the persisted query looked up on the server will match what the client actually sends after the whole apollo-link-state transformation.

from persistgraphql.

oluwie avatar oluwie commented on September 25, 2024

@toddtarsi I see. You're using the apollo-link-persisted-queries for the actual as the network interface. From the README, I was under the impression that you use the addPersistedQueries function exported by the ApolloNetworkInterface.ts file to modify the network interface to use the queryMap object provided to that function.

I'm looking for a way to use the network interface provided by this module w/o having to import the apollo-link-persisted-queries library.

from persistgraphql.

toddtarsi avatar toddtarsi commented on September 25, 2024

In that case, I don't have too much I can offer to help, but I see in your initial comment this:

const link = ApolloLink.from([addHeaders, stateLink, restLink, httpLink]);
const apolloClient = new ApolloClient({ cache, link });
const newApolloClient = addPersistedQueries(apolloClient, queryMap);
export default newApolloClient;

I think addPersistedQueries takes a networkInterface, not an apollo client instance. The whole networkInterface API around 2.x was converted to simple network options for httpLink. If you're on 1.x, then you'd instead pass it in to something like this:

const networkInterface = createNetworkInterface({
  uri: 'http://api.example.com/graphql'
});
const client = new ApolloClient({
  networkInterface: addPersistedQueries(networkInterface)
});

On a side note, if you're using stateLink and httpLink, I really think you should look at the persisted queries link again. It fits right in with that code paradigm quite nicely. Otherwise, you'll need an intermediate link before the httpLink and after the stateLink to vacuum your query down to the variables and id in your request. If you use this anywhere else, you either won't be able to resolve the client fields using apollo-link-state, or you won't have the client fields persisted in the query body. All in all, its a lot of stress and headaches, for a solution that's already mostly there.

from persistgraphql.

toddtarsi avatar toddtarsi commented on September 25, 2024

Hey all, I hope I am not raising too much trouble. I'll namespace the query transformer script above as:

persistgraphql-query-transform-trim-client-fields

Thanks again for the amazing tools, and you all are awesome!

from persistgraphql.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.