GraphQL mutation

Enonic version: 7.6.0
OS: Linux

Hello,

I would like to use the Enonic API not only to read data, but also to write data to the content studio (update or insert). I searched for a way to do that with Graphql and found a type of query called “mutation”. I tried this in the Enonic API but I was not able to update or insert any data. The queries that are for reading the Enonic data are enclosed in the “guillotine” tag, which is for accessing read-only data. So I tried to remove the “guillotine” tag but got the error:

“OperationNotSupported: Schema is not configured for mutations.”

Here is an example of a query for retrieving the data:

{
  guillotine {
    query(
      contentTypes: "com.gksoftware.es.esintranet:how-to-item"
      query: "pathMatch('_path', '/content/intranet/how-to-do/how-to-items', 4)"
      first: 100
    ) {
      ... on com_gksoftware_es_esintranet_HowToItem {
        data {
          title
          content
        }
      }
    }
  }
}

And here is an example of the mutation that’s trying to create new data of the same type:

> mutation {
>   createHowToDo(input: {
>     title: "Testing title"
>     content: "Testing content"
>   } ) {
>         ... on com_gksoftware_es_esintranet_HowToItem {
>           data {
>             title
>             content
>           }
>         }
>       }
> }

Is there a way to create new data or update existing data via the Enonic Graphql API?

Thank you in advance for your response.
Best regards,
Pavel

Hello, @pcermak!

Lib Guillotine API gives read-access to all your content. But, you can add a mutation by customizing your schema. Please refer to this topic https://developer.enonic.com/docs/guillotine/stable/advanced.

Best regards,
Anatol

Hello,

in our project we do not configure any schema, but we use a tool/layer called Apollo (https://www.apollographql.com/) and we send the query to the Enonic API via this layer. The Apollo layer has a query function which accepts queries to retrieve data and it has also a mutate function which is for inserting/updating data. We would like to send a mutation to the Enonic API directly via the Apollo layer. Is this possible or do we have to configure the Enonic XP to accept mutations in the first place?

Thank you in advance for your help.

Best regards,
Pavel

Hi Pavel.

The Guillotine API is as a read-only API, but you can extend it with your own custom mutations as you see fit. You’ll find more information about extending the API here: https://developer.enonic.com/docs/guillotine/stable/advanced#extending_the_schema

Hello,

could you please provide an example of extending the schema with a custom mutation?
I tried to extend the schema but I get the error OperationNotSupported: Schema is not configured for mutations in the Graphql Playground.

The content type has two fields of type string (title and content). With this mutation, I would like to modify the content.

Here is the schema:

var SCHEMA = guillotineLib.createSchema({
    creationCallbacks: {
        'com_gksoftware_es_esintranet_HowToItem': function modifyHowToDo(params) {
            params.fields.content = {
                type: graphQlLib.GraphQLString,
                resolve: function(env) {
                    return "Hello world.";
                }
            }
        }
    }
});

and here is the mutation called in the Graphql Playground:

mutation {
  modifyHowToDo(input: {
    title: "Testing item"
    content: "Testing content"
  } ) {
      ... on com_gksoftware_es_esintranet_HowToItem {
        data {
          title
          content
        }
      }
    }
}

I am not using any ID in the mutation to identify an actual node in the content studio yet. I will use one when the mutation will be callable.

Thank you in advance for your response.

Best regards,
Pavel

Hi, Pavel

Below you can find the example how to add a mutation to schema

var guillotineLib = require('/lib/guillotine');
var graphQlLib = require('/lib/graphql');


function generateCustomTypes(context) {
    context.types.howToDoInputType = graphQlLib.createInputObjectType({
        name: context.uniqueName('HowToDoInput'),
        description: 'HowToDoInput type',
        fields: {
            title: {
                type: graphQlLib.GraphQLString
            },
            content: {
                type: graphQlLib.GraphQLString
            }
        }
    });
}

function createHeadlessCmsMutationType(context) {
    return graphQlLib.createObjectType({
        name: context.uniqueName('HeadlessCmsMutation'),
        description: 'Headless CMS Mutation',
        fields: {
            modifyHowToDo: {
                type: graphQlLib.GraphQLString,
                args: {
                    input: context.types.howToDoInputType
                },
                resolve: (env) => {
                    return `title = ${env.args.input.title}`;
                }
            }
        }
    });
}

function createRootQueryType(context) {
    return graphQlLib.createObjectType({
        name: 'Query',
        fields: {
            guillotine: {
                type: guillotineLib.createHeadlessCmsType(context),
                resolve: function () {
                    return {};
                }
            }
        }
    });
}

function createRootMutationType(context) {
    return graphQlLib.createObjectType({
        name: 'Mutation',
        fields: {
            guillotine: {
                type: createHeadlessCmsMutationType(context),
                resolve: function () {
                    return {};
                }
            }
        }
    });
}

function createSchema() {
    var context = guillotineLib.createContext();

    generateCustomTypes(context);

    return graphQlLib.createSchema({
        query: createRootQueryType(context),
        mutation: createRootMutationType(context),
        dictionary: context.dictionary
    });
}

var SCHEMA = createSchema();

Best regards,
Anatol

1 Like