Ever do a lot of work in disconnected mode and then just hit a point where you just need to do execute a GraphQL query to power a component? I personally love GraphQL and wanted to use it regardless of mode.

In disconnected mode with Sitecore JSS, we have a manifest object that gets generated that represents the items we have defined in our data directory. The manifest has a complete representation of all routes, non-routes, content items and dictionary items that we have defined. Read more about the manifest here.

This project leverages the manifest object and generates a GraphQL schema directly off of it. No mocking of JSON responses is necessary, the data you query is the data you've already defined. This project also exposes GraphiQL on the path that you have defined on your graphQLEndpointPath config value in your package.json, meaning you will get a great user interface to test and run queries with even in disconnected mode.

Feels a lot like connected mode GraphQL to me. (Not) sorry for not including the dark theme.

The schema should look very familiar, I've tried to keep the names of fields and the types the exact same as you would expect in connected mode, so the path to integration should be hopefully be straight forward. Ideally, queries themselves should not have to change after they've been integrated.

Getting Started

I've put together a "Getting Started" section on the GitHub README. I'm not going to replicate it here for now because I expect the steps to install to evolve as more work is done for a fuller integration. This project should be classified as proof of concept. Please see the "What's the catch?" section for issues with fully integrating this into a Sitecore JSS application.

Please check out the code here for steps on enabling the server on your projects.

Installation is minimal and has been tested with the React sample app.

What's the catch?

There is a catch to have this server fully integrated into your Sitecore JSS project and it's available-in-connected-mode. If you've worked in disconnected mode then you've seen this, it's in itemId on the Sitecore context, it's in the dataSource value as well. It's not unique and doesn't match up with any item in particular. This value originates in the disconnected layout service, it populates these fields this way because the Sitecore ID's for items get generated when items get imported into Sitecore and aren't yet available.

This will need to get changed in some way to actually fully integrate this GraphQL project into your application. It's not possible to fetch items using this value since it is just a placeholder. Some ideas to solve this are:

  • Populate id fields with a unique value, such as a name value. We have names for routes and names for data source items, such as graphql-jss-main-ContentBlock-1. I'm using these names internally to mock out a tree. This value could be used where available-in-connected-mode is and it enable things work.
  • Move ID generation to manifest generation instead of import. I suspect this would be less likely but if this was done, it would allow for the same ID to be used to represent an item in both modes. Added benefit of this would be you could technically hardcode an ID anywhere and feel comfortable knowing that the ID won't change during integration.

I'm definitely open to other ideas and will be exploring a solution in the near future. Please reach out if I missed something here and there is an easier solution. I secretly hope someone will tell me I missed a more obvious solution after I post this.

Known Issues

There are a few things worth mentioning here...

Template Inheritance

Just not implemented currently. I suspect an interface needs to be generated for base templates and then inherited on template types that need them. Will likely require a another pass during type generation to build these.

Persistent Queries and Batching in Connected Mode

If you go through the steps and add this to your project and start making queries from your components, you'll likely get errors back from the service. It seems like express-graphql can't handle batching or persistent queries and will just give you back an error for each request. The answer for this, for now, is to make changes to GraphQLClientFactory.js. Your link in disconnected mode should just use:

const link = createHttpLink({ uri: endpoint, credentials: 'include' }); 

You should be able to conditionally set this so this only impacts disconnected mode. Might explore other alternatives in the future though.

Integrated Mode

This hasn't really been explored yet but you should be able to leverage customizeRendering to accomplish this. You should be able to execute the query from this function and set the field data here. This also won't work properly until available-in-connected-mode is solved.

Fields

Some fields are just simply aren't implemented and are just mocked out to return a fixed value. Some of these fields can be improved but some of them just won't be possible to refine further.

Contribute

Did I get a field wrong? Am I missing a field you use a lot? I'd love a pull request. I'll put some missing things in the Issues list that haven't been mocked or implemented yet.

Conclusion

I see this as a first step. I considered waiting to release this code until I could address all the integration issues but I wanted to open the conversation.

This is the server aspect of what could become a full integration. As you can see from the above, there are some things that need to be thought through a little more before before a full integration of connected and integrated queries is possible. I'll be continuing to work towards that goal with this project and will have some follow up posts with some solutions.

Until then, enjoy and happy querying.