UPCOMING: Magento 2 Bootcamp of four days in The Netherlands (April 29th - May 2nd)
background

April 7, 2020

Working with Apollo introspection and Magento GraphQL fragments

Yireo Blog Post

It begins so simple. You build yourself a React app, running simple GraphQL queries towards a Magento shop and you hope for the best. However, the more progress you make, the more complex some issues might come: One such a topic is GraphQL introspection. Let's have a peak, so we can make things simple again.

About GraphQL fragments

Provided you are familiar with GraphQL, you have probably already heard or maybe even played with fragments: Thanks to fragments, you can prevent duplication of query snippets, simply by moving generic pieces of your queries (or mutations) into fragments. It cleans up the code, improves readability and reusability.

An example fragment might be used like this:

fragment NameParts on Person {
  firstName
  lastName
}

query GetPeople {
  people(id: "7") {
    ...NameParts
    avatar(size: LARGE)
  }
}

Because the return value of people is a listing of Person objects, with each Person including a firstName and lastName, we can simply reuse that Person snippet as a fragment in a query. In real-life (with React for example), it would be making sense to store the fragment and query in separate files and then importing their value again using React imports.

There's only one little issue: The fragment relies on the fact that GraphQL knows about the type-definition Person.

Client-side resolving of server-side

Usually, type-definitions live on the server. With Magento, that's definitely the case: Types (and interfaces) can defined in the etc/schema.graphqls within a Magento module. And using an interactive tool like GraphiQL (or ChromeiQL or whatever), you can fetch that schema (like Person) on the fly from the server, so that a fragment (like NameParts) is working together with a certain query (GetPeople).

Within a React app however, you don't want to do this on-the-fly. This would lead to unwanted network traffic, while we're actually trying to reduce overhead. The solution is to load the server-side schemas into the client-side PWA, while building that PWA. Apollo Client supports this by adding an IntrospectionFragmentMatcher to the Apollo Client configuration. But that still requires you to download the relevant GraphQL schemas.

In Duka

For some time now, I'm working on my own playground with React, Redux, Apollo Client and GraphQL to show trainees how to build a React app connecting to Magento 2. This playground is dubbed Duka and it is open sourced on GitHub: github.com/yireo-training/react-duka-playground

As soon as I started to play with fragments, I needed to extend upon my own Apollo Client to allow for it to introspect the GraphQL schema of my Magento instance:

import { IntrospectionFragmentMatcher } from "apollo-cache-inmemory";
import schemaData from "./graphql.schema.json";

const fragmentMatcher = new IntrospectionFragmentMatcher({schemaData});
const apolloClient = new ApolloClient({
  ...
  cache: new InMemoryCache({ fragmentMatcher }),
});

In the example, you can see that a file graphql.schema.json is used to read data from Magento. (See the sources on GitHub if you want to see the full example.) To generate this JSON, I used a tool called graphql-codegen with a command graphql-codegen --config codegen.yml and a YAML of the following:

overwrite: true
schema: "https://duka.yireo-demo.com/graphql"
documents: "src/state/graphql/queries/*.graphql"
generates:
  src/codegen/graphql.schema.json:
    plugins:
      - "introspection"

The command not only downloads the schema into a JSON file, it also validates whether queries in the documents folder (in my case src/state/graphql/queries/*.graphql) are still validating correctly against the schema. In short, it checks whether the React queries are compatible with the Magento GraphQL API.

In Magento PWA Studio

Magento PWA Studio faces a similar problem and uses a slightly same but different approach. Via the command .node_modules/.bin/graphql get-schema --project pwatest, the schemas are downloaded. Next, via the command .node_modules/.bin/graphql validate-magento-pwa-queries --project pwatest, the current queries are matched with the current schemas. Underneath, the tool graphql-cli is used, in combination with a configuration file .graphqlconfig within your own app.

Next, they have created a wrapper to be run with yarn run validate-queries, to make it easier to run the commands. Running this command is part of the procedure of building a new app and pushing it to a new live site.

While Duka and PWA Studio take different approaches, as of yet, I personally don't see any real difference. Both approaches work just fine.

When to update your schemas?

So that's a sneak preview on how introspection works. And as mentioned, as soon as you use fragments, the topic of introspection becomes important, because without introspection (most) fragments do not work. Plus, it gives you an add-on feature of validating whether GraphQL queries are still working with the GrapQL API you are communicating with.

This is highly important. It points towards a deployment strategy, where with every Magento upgrade, you will need to upgrade the client-side schemas as well: With every Magento upgrade, new GraphQL schemas (endpoints, types, interfaces) might be added, but more importantly, existing ones could be modified. And if the Magento GraphQL API changes, it might very well be that queries, mutations and fragments might break on the client-side.

So whenever, the Magento application is updated (minor updates, major upgrades, extension installs or updates, patches), the PWA might need updating as well. This sounds like an aweful situation.

When only to update your schemas?

This sounds like an aweful situation. But actually is not. Looking at the headless frontend built in PWA, there is (hopefully) only one dependency with Magento: GraphQL. So it is kind of obvious that when the GraphQL API changes, the client app also needs to change. But that's it. If the Magento application changes fundamentally in its inner architecture, it does not mean anything in regard to the app, until the GraphQL API (or actually its client-side implementation) changes as well.

This simplifies deployment: Theoretically, the query validation takes place with some kind of continuous integration process. Once the schema does not match with client-side usage anymore, a flag needs to go up, so that the app is re-deployed as well. But as long as the schemas validate, the app requires zero work.

The only pitful is that as of yet, the Magento GraphQL API is still under heavy development: The API coverage is maybe already allowing for building full-featured apps (I'm not saying anything else on this topic for now), but with every Magento minor release, it might be that some things need to be changed in the PWA as well. Is that hard? No, with the last Magento releases, it took me under a minute to make the needed changes. And Magento 2.4 will probably bring stability in this.

One more thing to say on this: GraphQL is so cool.

Posted on April 7, 2020

About the author

Author Jisse Reitsma

Jisse Reitsma is the founder of Yireo, extension developer, developer trainer and 3x Magento Master. His passion is for technology and open source. And he loves talking as well.

Sponsor Yireo

Looking for a training in-house?

Let's get to it!

We don't write too commercial stuff, we focus on the technology (which we love) and we regularly come up with innovative solutions. Via our newsletter, you can keep yourself up to date on all of this coolness. Subscribing only takes seconds.

Do not miss out on what we say

This will be the most interesting spam you have ever read

We don't write too commercial stuff, we focus on the technology (which we love) and we regularly come up with innovative solutions. Via our newsletter, you can keep yourself up to date on all of this coolness. Subscribing only takes seconds.