Graphql Custom Resolver Mutation v4

System Information
  • Strapi Version: 4.1.0
  • Operating System: Mac OSX
  • Database: Postgres
  • Node Version: 16.13.2
  • NPM Version: 8.4.0
  • Yarn Version:

So I’ve read almost every forum post and discord post, and still can’t get the answer. I need a custom resolver, which I believe I’ve done. However, I can’t get the proper graphql response.

register: ({ strapi }) => {
    const extensionService = strapi.plugin("graphql").service("extension");
    const extension = ({ nexus }) => ({
      types: [
        nexus.extendType({
          type: "Mutation",
          definition: (t) => {
            t.field("createCustomerProfile", {
              type: "CustomerProfileEntityResponse",
              args: { data: "CustomerProfileInput" },
              async resolve(parent, args) {
                const date = new Date();
                const month = ("0" + (date.getMonth() + 1)).slice(-2);
                const year = date.getFullYear();
                const twoDigitYear = year.toString().substring(2)
                args.data.uid = uniqid.time(`${month}-${twoDigitYear}-`)
                const data = await strapi.entityService.create('api::customer-profile.customer-profile',args)
                console.log(data)
                return data
              },
            });
          }
        }),
      ]
    });
    extensionService.use(extension);
  },

However, that response, is just a simple JSON, and not a GraphQL response. Please help!!

1 Like

Hey,

When returning an EntityResponse type or an EntityResponseCollection type, you need to format your data so that it matches the expected structure.

You can get and use the following util to do so:
const { toEntityResponse } = strapi.plugin('graphql').service('format').returnTypes;

And then transform your data using
return toEntityResponse(data, { args, resourceUID: 'api::customer-profile.customer-profile' });

Let me know if it helped you fix your issue.
Best,

1 Like

@Convly Can you go into more detail on this line? I need some help.

Transforming data:
return toEntityResponse(data, { args, resourceUID: 'api::customer-profile.customer-profile' });

In my situation I have a collection type “Subscription” and I’m overwriting the createSubscription resolver. The mutation works and I get “data” back after I make the request, but I want to include a “session url” as well (I’m integrating Stripe).

This is what I have:

// above this I have pretty much what djourney has
const data = await strapi.entityService.create('api::subscription.subscription', args);
args.session_url = session.url; // I also tried swapping these 2 lines ^

return toEntityResponse(data, { args, resourceUID: 'api::subscription.subscription' });

In short, my data isn’t being transformed and I’m not sure how the “args” play in or if it’s the right approach to update the args directly like that. My goal is just to get back that session url so I can kick off the Stripe checkout process.

Hi @Convly,

I am writing GraphQL schema extensions for Strapi v4 at the moment and a bit puzzled with the behaviour I am seeing.
According to your answers we need to transform the results using toEntityResponse() method.

But when I do so, I get an error in graphql playground: "message": "Cannot return null for non-nullable field UsersPermissionsUser.username.",
And when I return an object as-is, it works just fine.

  extension: ({ nexus }) => ({
    typeDefs: `
      extend type Query {
        self: UsersPermissionsUser
      }`,
    resolvers: {
      Query: {
        self: {
          description: "Fetch details of the authenticated user",
          async resolve(parent, args, ctx) {
            const { toEntityResponse } = strapi.plugin("graphql").service("format").returnTypes;
            await strapi.controller("plugin::users-permissions.user").me(ctx);
            // Controller does not return, it mutates the ctx object
            const me = toEntityResponse(ctx.body, { args, resourceUID: "plugin::users-permissions.user" });
            console.log(me);
            return me;
          },
        },
      },
    },
    resolversConfig: {
      "Query.self": {
        auth: {
          scope: ["plugin::users-permissions.user.me"],
        },
      },
    },
  }),

And the “transformed” response object looks like this:

{
  value: {
    id: 2,
    username: 'test-user1',
    email: 'testuser@void.net',
    provider: 'local',
    confirmed: true,
    blocked: false,
    createdAt: '2022-03-20T14:28:33.768Z',
    updatedAt: '2022-04-12T08:00:57.918Z',
  },
  info: { args: {}, resourceUID: 'plugin::users-permissions.user' }
}

Note that this is the same structure as shown in the example in the official docs (GraphQL - Strapi Developer Docs) but the official example also did not work for me. I had to flatten the object by moving all the fields of the “value” object to the root level, then GraphQL playground works fine with it.

I am sorry Mr. @DMehaffy, but I mention you here because you are by far the most active strapi frontman and the most responsive too.

Is this a new behaviour and the documentation just has not been updated or is this something else?
Also, is there a documentation that explains how to write the resolvers properly?
Where is it documented that the “graphql” plugin has the “format” service and one must use the “toEntityResponse” method to prepare data before returning it from the resolver?

Gathering scattered pieces of information by searching through the forum is not a viable documentation strategy if success of the Strapi as a product is important.

2 Likes

Thanks for your sample code. I followed docs but it not working

I really agree with that remark,

90% of my workflow with Strapi is excellent.
And the last 10% are about essential use cases, without documentation. And then starts a very painful and time-consuming research on the web with poor results.

3 Likes

Just found this topic after having absolutely no idea how to add a custom mutation to the graphQL schema. I would have never learned about toEntityResponse otherwise. It would be really helpful to add some documentation about mutations to the docs. My knowledge about the GraphQL plugin is way too limited to do it myself sadly.