skip to Main Content

I’m creating an Apollo Client like this:

var { ApolloClient }    = require("apollo-boost");
var { InMemoryCache }   = require('apollo-cache-inmemory');
var { createHttpLink }  = require('apollo-link-http');
var { setContext }      = require('apollo-link-context');

exports.createClient = (shop, accessToken) => {

  const httpLink = createHttpLink({
    uri: `https://${shop}/admin/api/2019-07/graphql.json`,
  });
  const authLink = setContext((_, { headers }) => {
    return {
      headers: {
        "X-Shopify-Access-Token": accessToken,
        "User-Agent": `shopify-app-node 1.0.0 | Shopify App CLI`,
      }
    }
  });  

  return new ApolloClient({
    cache: new InMemoryCache(),
    link: authLink.concat(httpLink),
  });
};

to hit the Shopify GraphQL API and then running a query like that:

    return client.query({
        query: gql` {
            productVariants(first: 250) {
                edges {
                    node {
                        price
                        product {
                            id
                        }
                    }
                    cursor
                }
                pageInfo {
                    hasNextPage
                }
            }
        }
    `})

but the returned object only contain data and no extensions which is a problem to figure out the real cost of the query.

Any idea why?

Many thanks for your help

2

Answers


  1. I dont have any idea of ApolloClient but i tried to run your query in shopify graphql app. It return results with extensions. Please find screenshot below. Also You can put questions in ApolloClient github.

    enter image description here

    Login or Signup to reply.
  2. There’s a bit of a hacky way to do it that we wrote up before:

    You’ll need to create a custom apollo link (Apollo’s equivalent of middleware) to intercept the response data as it’s returned from the server, but before it’s inserted into the cache and the components re-rendered.

    Here’s an example were we pull metrics data from the extensions in our API:

    import { ApolloClient, InMemoryCache, HttpLink, ApolloLink } from 'apollo-boost'
    
    const link = new HttpLink({
      uri: 'https://serve.onegraph.com/dynamic?show_metrics=true&app_id=<app_id>',
    })
    
    const metricsWatchers = {}
    
    let id = 0
    
    export function addMetricsWatcher(f) {
      const watcherId = (id++).toString(36)
      metricsWatchers[watcherId] = f
      return () => {
        delete metricsWatchers[watcherId]
      }
    }
    
    function runWatchers(requestMetrics) {
      for (const watcherId of Object.keys(metricsWatchers)) {
        try {
          metricsWatchers[watcherId](requestMetrics)
        } catch (e) {
          console.error('error running metrics watcher', e)
        }
      }
    }
    
    // We intercept the response, extract our extensions, mutatively store them,
    // then forward the response to the next link
    const trackMetrics = new ApolloLink((operation, forward) => {
      return forward(operation).map(response => {
        runWatchers(
          response
            ? response.extensions
              ? response.extensions.metrics
              : null
            : null
        )
        return response
      })
    })
    
    function create(initialState) {
      return new ApolloClient({
        link: trackMetrics.concat(link),
        cache: new InMemoryCache().restore(initialState || {}),
      })
    }
    
    const apolloClient = create(initialState);
    

    Then to use the result in our React components:

    import { addMetricsWatcher } from '../integration/apolloClient'
    
    const Page = () => {
      const [requestMetrics, updateRequestMetrics] = useState(null)
    
      useEffect(() => {
        return addMetricsWatcher(requestMetrics =>
          updateRequestMetrics(requestMetrics)
        )
      })
    
    // Metrics from extensions are available now
    return null;
    }
    
    

    Then use a bit of mutable state to track each request and its result, and the use that state to render the metrics inside the app.

    Depending on how you’re looking to use the extensions data, this may or may not work for you. The implementation is non-deterministic, and can have some slight race conditions between the data that’s rendered and the data that you’ve extracted from the extensions.

    In our case, we store performance metrics data in the extensions – very useful, but ancillary – so we felt the tradeoff was acceptable.

    There’s also an open issue on the Apollo client repo tracking this feature request

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search