EzDev.org

apollo-client

apollo-client - :rocket: A fully-featured, production ready caching GraphQL client for every server or UI framework Apollo GraphQL | Learn about the Apollo platform: Client, Engine, GraphQL servers, GraphQL support, and more. learn about the apollo platform: client, engine, graphql servers, graphql support, and more.


How to set fetchPolicy globally on apollo-client queries?

I have a few mutations that should trigger some refetchQueries, but I need those queries to have a fetchPolicy other than the default.

Is there a way to set fetchPolicy globally instead of per query? So to avoid setting fetchPolicy on each query.


Source: (StackOverflow)

Apollo Client (React): Handling unexpected errors

I have been reviewing the Apollo documentation but I do not see information of how to go about handling server errors in the Apollo client.

For example, suppose that the server either:

  • Times out
  • Becomes unreachable
  • Unexpectedly fails

How should this be handled in the client? Apollo currently fails with errors such as:

Unhandled (in react-apollo) Error: GraphQL error: Cannot ...

I'd like to avoid this happening and handling these errors. How can I do so using React Apollo?


For reference:

I am currently using React-Apollo and Redux.


Source: (StackOverflow)

Apollo client is giving me an error of 'store already contains an id' - what does that mean?

In a react native project I am creating an object and then redirecting the screen to the newly created object's details page and I'm getting this error:

Possible Unhandled Promise Rejection (id: 0): Network error: Store error: the application attempted to write an object with no provided id but the store already contains an id of XYZ for this object.

Looking in the database I see that the item is properly created in the previous step. Navigating to the same screen and item through a list (not after a create and redirect) seems to work fine. Do I have to wait or somehow set some sort of timing for the apollo store to stay correct?

I'm using the standard apollo client @graphql binding/wrapping

gql:

 query getEvent($eventId: ID!) {
    Event(id:$eventId) {
      id
      headline
      photo
      location
      startTime
      creator {
        username
        photo
      }
    }
  }
`;

And here's a code snippet

@graphql(getEventGql,{
  options: ({route}) => {
    console.log('route params', route.params);
    return {
      variables: {
        eventId: route.params.eventId,
      }
    }
  },
})

@connect((state) => ({ user: state.user }))
export default class EventDetailScreen extends Component {
...

Source: (StackOverflow)

How to update the Redux store after Apollo GraphQL query returns

I'm fetching a list of data with the graphql HOC provided by react apollo. E.g.:

const fetchList = graphql(
  dataListQuery, {
    options: ({ listId }) => ({
      variables: {
        listId,
      },
    }),
    props: ({ data: { loading, dataList } }) => {
      return {
        loading,
        list: dataList,
      };
    }
  }
);

I'm displaying the list in a controlled radio button group and I need to select one of the items by default. The id of the selected item is kept in the Redux store.

So, the question is how to update the Redux store (i.e. set the selectedItem) after the query successfully returns?

Some options that came to my mind:

Option 1

Should I listen for APOLLO_QUERY_RESULT actions in my Redux reducer? But that is kind of awkward because then I would need to listen to both APOLLO_QUERY_RESULT and APOLLO_QUERY_RESULT_CLIENT if the query already ran before. And also the operationName prop is only present in the APOLLO_QUERY_RESULT action and not in APOLLO_QUERY_RESULT_CLIENT action. So i would need to dissect every APOLLO_QUERY_RESULT_CLIENT action to know where that came from. Isn't there an easy and straight forward way to identify query result actions?

Option 2

Should I dispatch a separate action like SELECT_LIST_ITEM in componentWillReceiveProps e.g (using recompose):

const enhance = compose(
  connect(
    function mapStateToProps(state) {
      return {
        selectedItem: getSelectedItem(state),
      };
    }, {
      selectItem, // action creator
    }
  ),
  graphql(
    dataListQuery, {
      options: ({ listId }) => ({
        variables: {
          listId,
        },
      }),
      props: ({ data: { loading, dataList } }) => ({
        loading,
        items: dataList,
      }),
    }
  ),
  lifecycle({
    componentWillReceiveProps(nextProps) {
      const {
        loading,
        items,
        selectedItem,
        selectItem,
      } = nextProps;
      if (!selectedItem && !loading && items && items.length) {
        selectItem(items[items.length - 1].id);
      }
    }
  })
);

Option 3

Should I make use of the Apollo client directly by injecting it with withApollo and then dispatch my action with client.query(...).then(result => { /* some logic */ selectItem(...)}). But then I would loose all the benefits of the react-apollo integration, so not really an option.

Option 4

Should I not update the Redux store at all after the query returns? Because I could also just implement a selector that returns the selectedItem if it is set and if not it tries to derive it by browsing through the apollo part of the store.

None of my options satisfy me. So, how would I do that right?


Source: (StackOverflow)

How to handle Errors with the Apollo stack

I'm using the Apollo Stack with graphql-server-express and apollo-client.

Because my backend is not perfect errors can appear and therefore I have to respond to a request with an error for that path.

Till now my main problem was authentication and therefore I responded with an error.

return new Error(`${data.status}: ${data.statusText} @ ${data.url}`)

In the frontend I use apollo-client to query data.

return apollo
        .query({query: gql`
            query {
                ${query}
            }`,
            forceFetch: forceFetch
        })
        .then(result => { debugger; return result.data })
        .catch(error => { debugger; console.error(error); });

But if one property of the query responds with an error, only the catch function will be invoked. Even the data of the remaining properties is transferred, I see this in the network tab of the Chrome Dev Tools. In is not error object in the catch function.

My attempt works fine with GraphiQL where I get the errors and data in the same object.

So how can I throw errors for a property without loosing the whole request?


Source: (StackOverflow)

Why does Apollo/GraphQL return a non extensible object?

I'm building an app with VueJS and I'm using Apollo client to fetch data from a database through a GrapgQL server. I have code that looks like this:

    apollo.query({
        query,
        variables
    })
    // context.commit('populateComments', payload) triggers the mutation
    .then(payload => context.commit('populateComments', payload))

Then, in my mutations I have the following

    populateComments: (state, payload) => { 
        state.comments = payload.data.comments
    }

When I try to push another object into the comments array in another mutation I get an error that reads "Cannot add property 300, object is not extensible". I have found that the following works

state.comments = Array.from(payload.data.comments)

But.. I'm not sure how effective it is to repeatedly copy large arrays like this? Is this the preferred way to do it?


Source: (StackOverflow)

Apollo Client: Upsert mutation only modifies cache on update but not on create

I have an upsert query that gets triggered on either create or update. On update, Apollo integrates the result into the cache but on create it does not.

Here is the query:

export const UPSERT_NOTE_MUTATION = gql`
  mutation upsertNote($id: ID, $body: String) {
    upsertNote(id: $id, body: $body) {
      id
      body
    }
  }`

My client:

const graphqlClient = new ApolloClient({
  networkInterface,
  reduxRootSelector: 'apiStore',
  dataIdFromObject: ({ id }) => id
});

The response from the server is identical: Both id and body are returned but Apollo isn't adding new ids into the data cache object automatically.

Is it possible to have Apollo automatically add new Objects to data without triggering a subsequent fetch?

Here is what my data store looks like:

enter image description here

UPDATE

According to the documentation, the function updateQueries is supposed to allow me to push a new element to my list of assets without having to trigger my origin fetch query again.

The function gets executed but whatever is returned by the function is completely ignored and the cache is not modified.

Even if I do something like this:

    updateQueries: {
      getUserAssets: (previousQueryResult, { mutationResult }) => {
        return {};
      }
    }

Nothing changes.

UPDATE #2

Still can't get my assets list to update.

Inside updateQueries, here is what my previousQueryResult looks like:

    updateQueries: {
      getUserAssets: (previousQueryResult, { mutationResult }) => {
        return {
          assets: []
            .concat(mutationResult.data.upsertAsset)
            .concat(previousQueryResult.assets)
        }
      }
    }

But regardless of what I return, the data store does not refresh:

enter image description here

For reference, here is what each asset looks like:

enter image description here


Source: (StackOverflow)

How to make Redux Thunk and Apollo GraphQL work together

In my projects, Redux Thunk are used to keep all the async functions in action creators.

Now I am trying to add Apollo GraphQL into my project, everything works well except that when adding mutations into my functional Component and call them there, it breaks the redux thunk architecture.

How to solve it? I suppose I can create new action creator methods and pass the mutations into them, but it would soon become boilerplate and that just doesn't seem to be a good solution to me.


Source: (StackOverflow)

Error: Network error: Error writing result to store for query (Apollo Client)

I am using Apollo Client to make an application to query my server using Graphql. I have a python server on which I execute my graphql queries which fetches data from the database and then returns it back to the client.

I have created a custom NetworkInterface for the client that helps me to make make customized server request (by default ApolloClient makes a POST call to the URL we specify). The network interface only has to have a query() method wherein we return the promise for the result of form Promise<ExecutionResult>.

I am able to make the server call and fetch the requested data but still getting the following error.

Error: Network error: Error writing result to store for query 
{
   query something{
      row{
         data
      }
   }
}
Cannot read property 'row' of undefined
    at new ApolloError (ApolloError.js:32)
    at ObservableQuery.currentResult (ObservableQuery.js:76)
    at GraphQL.dataForChild (react-apollo.browser.umd.js:410)
    at GraphQL.render (react-apollo.browser.umd.js:448)
    at ReactCompositeComponent.js:796
    at measureLifeCyclePerf (ReactCompositeComponent.js:75)
    at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (ReactCompositeComponent.js:795)
    at ReactCompositeComponentWrapper._renderValidatedComponent (ReactCompositeComponent.js:822)
    at ReactCompositeComponentWrapper._updateRenderedComponent (ReactCompositeComponent.js:746)
    at ReactCompositeComponentWrapper._performComponentUpdate (ReactCompositeComponent.js:724)
    at ReactCompositeComponentWrapper.updateComponent (ReactCompositeComponent.js:645)
    at ReactCompositeComponentWrapper.performUpdateIfNecessary (ReactCompositeComponent.js:561)
    at Object.performUpdateIfNecessary (ReactReconciler.js:157)
    at runBatchedUpdates (ReactUpdates.js:150)
    at ReactReconcileTransaction.perform (Transaction.js:140)
    at ReactUpdatesFlushTransaction.perform (Transaction.js:140)
    at ReactUpdatesFlushTransaction.perform (ReactUpdates.js:89)
    at Object.flushBatchedUpdates (ReactUpdates.js:172)
    at ReactDefaultBatchingStrategyTransaction.closeAll (Transaction.js:206)
    at ReactDefaultBatchingStrategyTransaction.perform (Transaction.js:153)
    at Object.batchedUpdates (ReactDefaultBatchingStrategy.js:62)
    at Object.enqueueUpdate (ReactUpdates.js:200)

I want to know the possible cause of the error and solution if possible.


Source: (StackOverflow)

Is it possible to inject a service into apollo-client's middleware?

Is it possible to inject a service into apollo-client's middleware? There is Apollo module. https://www.npmjs.com/package/apollo-angular At the documentation there is an advice how to implement authentication. The communication is done using localStorage. http://dev.apollodata.com/angular2/auth.html It is not Angular2 way. I need confirmation. I've been for solution for some time.


Source: (StackOverflow)

Uncaught TypeError: Can't add property 12, object is not extensible

I can't seem to understand the error I am getting on my client application. I am subscribing to a graphql subscription and I am able to retrieve the updates but I am not being able to push the changes to the typescript array called "models:ModelClass[]" which is bound to the view.

Is there something I am missing or doing wrong?

models.component.ts

this.apollo.subscribe({
  query: gql`
    subscription {
      newModelCreated{
        _id
        name
        type
        train_status
        deploy_status
        data_path
        description
        created_at
        updated_at
      }
    }
  `
}).subscribe((data) => {
  console.log("CREATED: " + JSON.stringify(data.newModelCreated));
  console.log(data.newModelCreated);
  var temp:ModelClass = data.newModelCreated;
  this.models.push(temp);
});

model-class.ts

export interface ModelClass {
    _id: string;
    name: string;
    type: string;
    parameters: {
        alpha: number;
    };
    train_status: string;
    deploy_status: string;
    test_accuracy: string;
    created_at: number;
    updated_at: number;
}

Source: (StackOverflow)

How to use a mocked data with react-apollo for tests

I'm using react-apollo to build a client that consumes a GraphQL API, however, I'm very stuck on testing. What I want is to mock the server so I can easily test the application without needing to make network calls.

I've found some pointers on how to mock the server:

But there isn't really an example on how to use this mocked server in my app tests to avoid hitting the server.

My goal is to setup integration tests to assert that the app is actually working:

describe('Profile feature', () => {
  beforeAll(() => {
    store = setupStore();
    app = mount(
      <ApolloProvider store={store} client={apolloClient}>
        <ConnectedRouter history={history}>
          <App />
        </ConnectedRouter>
      </ApolloProvider>
    );
  });
});

The store is using Redux and the client is being created like this:

const networkInterface = createNetworkInterface({
  uri: process.env.REACT_APP_API_URL
});

export const apolloClient = new ApolloClient({
  networkInterface
});

How can I use a mocked server with graphql-tools here instead of the actual API?


Source: (StackOverflow)

How do I handle deletes in Vue Apollo with deeply nested queries?

I have a query that returns multiple nested objects to render a screen full of information. I want to delete one of the deeply-nested objects and update the screen optimistically (i.e. without running the complete query).

To explain the query and UI, I'll use a Trello board -like query as an example:

query everything {
  getBoard(id: "foo") {
    name
    cardLists {        
      edges {
        node {
          id
          name
          cards {
            edges {
              node {
                id
                name
              }
            }
          }
        }
      }
    }
  }
}

The result of this query is used to build a UI like this: https://d3uepj124s5rcx.cloudfront.net/items/170a0V1j0u0S2p1l290I/Board.png

I'm building the app using:

  • VueJS
  • Vue Apollo
  • Scaphold.io as my GraphQL store

When I want to delete one of the cards, I call:

deleteCard: function () {
  this.$apollo.mutate({
    mutation: gql`
      mutation deleteCard($card: DeleteCardInput!) {
        deleteCard(input: $card) {
          changedCard {
            id
          }
        }
      }
    `,
    variables: {
      'card': {
        id: this.id
      }
    },
  })
  .then(data => {
    // Success
  })
}

The mutation is successfully deleting the card, but I want to update the UI immediately based on the mutation. The simple option for doing this is to call refetchQueries: ['everything'] — but this is an expensive query and too slow for quick UI updates.

What I want to do is update the UI optimistically, but the example mutations for Vue Apollo don't address either deletes or the deeply-nested scenario.

What is the right solution / best-practices for deleting an item from a deeply-nested query, and optimistically updating the UI?


Source: (StackOverflow)

Apollo-client (react) - Update on create mutation - "Can't find field Fund({}) on object (ROOT_QUERY)"

Using: "react-apollo": "^1.4.3"

In the parent component I query using GraphQL a parent node 'Fund' with children 'fundQuarterlyMetric'. This returns data in the following format:

{      
  id
  name
  ...
  fundQuarterlyMetrics (orderBy: asAtDate_ASC) {
    id
    year
    quarter
    ...
  }
}

When I try to create a new fundQuarterlyMetrics I have to update the local store on react-apollo using the update feature (Apollo Client docs). It gives me an error:

   Can't find field Fund({}) on object (ROOT_QUERY) {
     "Fund({\"id\":\"cj57hpfips0x7014414u5tk8m\"})": {
     "type": "id",
     "id": "Fund:cj57hpfips0x7014414u5tk8m",
     "generated": false
    }

The thing is, is that when I console.log the proxy, I can see the Fund and it's children under data.... not sure what to do..

UPDATE following comment:

Here is the parent component data request:

export const fundPageQuery = gql`
 query Fund($fundId: ID!) {
Fund(id: $fundId) {
  id
  name
  ....other variables
  fundQuarterlyMetrics (orderBy: asAtDate_ASC) {
    id
    year
    quarter
    ....other variables
  }
}

} `;

Here are the options I used:

var optionsForCreateFundMetric = {
 update: (proxy, {data: {createFundMetrics}}) => {
 try {
  console.log('proxy', proxy);
  const data = proxy.readQuery({query: FundQL.fundPageQuery});
  console.log('data', data);
  data.Fund.fundQuarterlyMetrics.push(createFundMetrics);
  proxy.writeQuery({query: FundQL.fundPageQuery, data})
} catch (e) {
  console.log('error adding to store', e);
}

} };

export default compose(
 graphql(FundQL.createFundMetrics, {name: 'createFundMetrics', options: 
 optionsForCreateFundMetric}),
 graphql(FundQL.updateFundMetrics, {name: 'updateFundMetrics'})
 )(FundMetricsForm);

Here is my create mutation:

export const createFundMetrics = gql`
 mutation createFundQuarterlyMetric(
$fundId: ID
$year: Int!
$quarter: FUND_QUARTERLY_METRIC_QUARTER!
$netIRR: Float!
$tvpi: Float!
$rvpi: Float!
$dpi: Float!
$asAtDate: DateTime
$calledThisQuarter: Float!
$distributedThisQuarter: Float!
$cumulativeCalled: Float!
$cumulativeDistributed: Float!
$limitedPartnersNAV: Float!
$quarterlyValuationChangeLCY: Float
$quarterlyTotalReturn: Float
 ) {
createFundQuarterlyMetric(
  fundId: $fundId
  year: $year
  quarter: $quarter
  netIRR: $netIRR
  tvpi: $tvpi
  rvpi: $rvpi
  dpi: $dpi
  asAtDate: $asAtDate
  calledThisQuarter: $calledThisQuarter
  distributedThisQuarter: $distributedThisQuarter
  cumulativeCalled: $cumulativeCalled
  cumulativeDistributed: $cumulativeDistributed
  limitedPartnersNAV: $limitedPartnersNAV
  quarterlyValuationChangeLCY: $quarterlyValuationChangeLCY
  quarterlyTotalReturn: $quarterlyTotalReturn
) {
  id
  year
  quarter
  netIRR
  tvpi
  rvpi
  dpi
  asAtDate
  calledThisQuarter
  distributedThisQuarter
  cumulativeCalled
  cumulativeDistributed
  limitedPartnersNAV
  quarterlyValuationChangeLCY
  quarterlyTotalReturn
}

} `;

SOLUTION Thanks Daniel - I had to return the fund ID to make it work so thank you!

export default compose(
 graphql(FundQL.createFundMetrics, {name: 'createFundMetrics', options: 
optionsForCreateFundMetric, variables: {fundId: 
createFundQuarterlyMetric.fund.id}}),
 graphql(FundQL.updateFundMetrics, {name: 'updateFundMetrics'})
 )(FundMetricsForm);

Source: (StackOverflow)

How to pass graphQL query variable into a decorated react component

Does anyone know how what the proper way to add a query variable to apollo is from react? I can get the following code to work if I manually add the book name string instead of passing in the $name query variable, but as soon as I add it and try and pass the name variable in through an options in the propTypes, the Invariant Violation: The operation 'data' wrapping 'BookPage' is expecting a variable: 'name' but it was not found in the props passed to 'Apollo(BookPage)'

I pulled the syntax for the decorator directly from the reactQL package so I know it has a little more syntactic sugar than other examples but it should still be valid for a query right?

const query = gql`
  query ($name: String!){
    bookByName(name: $name) {
      id
    }
}
`;

@graphql(query)
class BookPage extends React.PureComponent {
  static propTypes = {
    options: (props) => { return { variables: { name: "Quantum Mechanics"}}},
    data: mergeData({
      book:
        PropTypes.shape({
          id: PropTypes.string.isRequired,
        }),
    }),
  }

  render() {
    const { data } = this.props;
    if (data.loading) {
      return <p>Loading</p>
    }
    const { bookByName } = data;
    const book = bookByName;

    return (
      <p>book.id</p>
    );
  }
}

export default BookPage;

Source: (StackOverflow)