I'm brand new to Apollo and graphql, and I'm trying to setup an e-commerce site with shopify's storefront API. The website is build with react and Next.js for SSR.
I've managed to get some boilerplate code working for basic cart interactions with shopify. I have a Page component that wraps the whole app, and sits below ApolloProvider with access to apollo client. At the moment I'm using compose() to feed my Page component with some graphql (taken from this example):
const pageWithData = compose(
graphql(query), // Query that retrieves base shopify information, such as shop name, description and products
graphql(createCheckout, {name: "createCheckout"}), // Mutation that creates a new checkout object with shopify. Basically a cart object
graphql(checkoutLineItemsAdd, {name: "checkoutLineItemsAdd"}), // Mutation that adds a new lineitem to the checkout object
graphql(checkoutLineItemsUpdate, {name: "checkoutLineItemsUpdate"}), // Mutation that updates a line item
graphql(checkoutLineItemsRemove, {name: "checkoutLineItemsRemove"}), // Mutation that removes a lineitem
)(Page);
This all works as expected, Except when i refresh the browser, the cart is emptied, and a new checkout object is created. So what I want to do is store the checkout ID in localStorage and check if there is an ID in localstorage, before creating a new checkout object. If there is one, i'll load that checkout instead. right now the checkout is created like so in the Page component:
componentWillMount() {
this.props.createCheckout({
variables: {
input: {}
}}).then((res) => {
this.setState({
checkout: res.data.checkoutCreate.checkout
});
});
}
Now, I've found a working graphql query to load an existing checkout based on an ID:
const checkoutFetchQuery = gql`
query checkoutFetch ($checkoutId: ID!) {
node(id: $checkoutId) {
... on Checkout {
webUrl
subtotalPrice
totalTax
totalPrice
lineItems (first:250) {
pageInfo {
hasNextPage
hasPreviousPage
}
edges {
node {
title
variant {
title
image {
src
}
price
}
quantity
}
}
}
}
}
}
`;
And so I thought I could simply add this to the compose method like this:
const pageWithData = compose(
graphql(query), // Query that retrieves base shopify information, such as shop name, description and products
graphql(checkoutFetchQuery, { name: "fetchCheckout"}), // Query that fetches checkout based on a checkoutID
graphql(createCheckout, {name: "createCheckout"}), // Mutation that creates a new checkout object with shopify. Basically a cart object
graphql(checkoutLineItemsAdd, {name: "checkoutLineItemsAdd"}), // Mutation that adds a new lineitem to the checkout object
graphql(checkoutLineItemsUpdate, {name: "checkoutLineItemsUpdate"}), // Mutation that updates a line item
graphql(checkoutLineItemsRemove, {name: "checkoutLineItemsRemove"}), // Mutation that removes a lineitem
)(Page);
But this results in the following error from the Apollo dev tools:
GraphQL Errors: Variable checkoutId of type ID! was provided invalid value
I'm certain that this is me not understanding some key concept of how compose() work in react-apollo. I understand that I need to feed the query with some variables, but for some reason this query seem to run immediately on load, where as I expected this would simply make the query available on the component. Some of the other graphql() statements expects variables as well, such as "checkoutLineItemsAdd", but this doesn't result in errors. Another thing I've noticed is that the mutations are added as functions to the component props, where as my query is added as an object.
I'm struggling to find any good documentation on this.
- Are queries run immediately?
- Are mutations waiting to be called from the component, allowing us to dynamically add variables?
- Should I write my gql syntax differently for it to become a function on the component instead of an object?
- How do we pass variables dynamically to queries, when attached to the compose HOC?
- Howcome I get errors from this query, and not the mutations, that also expect variables before running?