2

I have an issue with graphQLSchemaExtension

I don’t have active session on my custom mutations..

An example below of the beginning of custom mutation And my graphQLSchemaExtension declaration And my Keystone.ts file

On my generic queries/mutations on playground I have a session. On my frontend too

Thanks <3

resolvers/mutations/confirmBooking.ts

resolvers/index.ts

Keystone.ts

I tried to change secure option on keystone.ts but nothing change Check on google, check on KeystoneJS github issues

5 Answers5

1

I assume that when you say "I don’t have active session on my custom mutations" you mean that, in your custom mutation resolver, the session property of the context argument is coming though as null?

Not sure what's causing this in your case. I've created a simple Keystone app with session and a custom mutation but failed to reproduce the issue you describe. In the current release of Keystone the custom GraphQL syntax is a bit different that the version you're on (docs, examples). It's also possible whatever problem you were seeing has been fixed. Hard to know without knowing the specific version you have in your package.json.

My example has just a User list that can be authenticated and a mutation called getRandom that returns a random float. The entire thing is ~50 lines; here's the keystone.ts:

import { list, config, graphql } from '@keystone-6/core';
import { statelessSessions } from '@keystone-6/core/session';
import { allowAll } from '@keystone-6/core/access';
import { text, password } from '@keystone-6/core/fields';
import { createAuth } from '@keystone-6/auth';
import { Context } from '.keystone/types';

let sessionSecret = Math.random().toString(36).substring(2, 10).repeat(4);
let sessionMaxAge = 60 * 60 * 24 * 30;

const { withAuth } = createAuth({
  listKey: 'User',
  identityField: 'email',
  secretField: 'password',
  sessionData: 'name',
});

const lists = {
  User: list({
    access: allowAll,
    fields: {
      name: text({ validation: { isRequired: true } }),
      email: text({ isIndexed: 'unique', validation: { isRequired: true } }),
      password: password(),
    },
  }),
};

const extendGraphqlSchema = graphql.extend(base => ({
  mutation: {
    getRandom: graphql.field({
      type: graphql.Float,
      args: {},
      resolve(source, {}, context: Context) {
        console.log('Dumping session object:', context.session);
        return Math.random();
      },
    }),
  },
}));

export default withAuth(
  config({
    db: {
      provider: 'postgresql',
      url: process.env.DATABASE_URL || 'postgres://molomby@localhost/ks6-auth',
    },
    lists,
    session: statelessSessions({
      maxAge: sessionMaxAge,
      secret: sessionSecret,
    }),
    extendGraphqlSchema,
  })
);

I'm running this out of the examples directory in a clone of the main Keystone repo so package versions are current, specifically: @keystone-6/auth@5.0.1 and @keystone-6/core@3.1.2.

The DB was manually seeded with a single user so I could authenticate: user record in the DB

Then I start the app and hit the custom mutation:

mutation {
   getRandom
}

If there's no current session, then context.session is null, as you'd expect:

Dumping session object: undefined

But if I sign into the Admin UI using the seeded user record, then hit the mutation from the GraphQL Playground (in the same browser, of course), I get my GraphQL resolver dumps the session object you'd expect:

Dumping session object: {
  listKey: 'User',
  itemId: 'claro2yq40008lh6y5wpkh2s1',
  data: [Object: null prototype] { name: 'Molomby' }
}
Molomby
  • 5,859
  • 2
  • 34
  • 27
0

Thanks for response

Yes context.session is null on custom mutation

I don't understand the new syntax for GraphQL Extension as :

const extendGraphqlSchema = graphql.extend(base => ({
  mutation: {
    getRandom: graphql.field({
      type: graphql.Float,
      args: {},
      resolve(source, {}, context: Context) {
        console.log('Dumping session object:', context.session);
        return Math.random();
      },
    }),
  },
}));

What's the type for ? ( graphql.float)

My extensions :

 "dependencies": {
    "@keystone-6/auth": "^4.0.0",
    "@keystone-6/core": "^2.1.0",
    "@keystone-6/fields-document": "^4.0.1",
    "@keystonejs/server-side-graphql-client": "^2.1.2",
    "@prisma/client": "^4.4.0",
    "@types/nodemailer": "^6.4.4",
    "dotenv": "^10.0.0",
    "graphql": "^15.8.0",
    "next": "12.2.4",
    "nodemailer": "^6.6.2",
    "stripe": "^8.161.0",
    "typescript": "^4.7.4"
  },

The better solution is to share this repo. It's an open-source project to learn

Project link : https://github.com/thibault60000/keystone-6-backend

Thanks for your time :)

  • The `type` in for the custom mutation is the GraphQL return type. I've added links to my answer for the docs and some examples. Hope that helps – Molomby Nov 22 '22 at 12:15
  • Thanks, I will try this new syntax. Thanks – user1189847343 Nov 22 '22 at 13:38
  • Hi I tried to use https://keystonejs.com/docs/guides/schema-extension#title with 'Using Third-Party Tools' | 'GraphQL-Tools Merge Schemas' syntax I have another anwser – user1189847343 Nov 24 '22 at 07:30
0

With 'Graphql Tool Merge Schemas' from documentation (https://keystonejs.com/docs/guides/schema-extension#title)

'context.session' continue to be undefined :/

export const extendGraphqlSchema = (schema: GraphQLSchema) =>
  mergeSchemas({
    schemas: [schema],
    typeDefs: `
      type Query {
        allGifts: [Gift]
      }
      type Mutation {
        confirmBooking(giftId: ID!): Boolean
      }
    `,
    resolvers: {
      Query: {
        // Testing
        allGifts: (root, { id, days }, context: Context) =>
          context.db.Gift.findMany(),
      },
      Mutation: {
        // To implement
        confirmBooking: (root, { giftId }, context: Context) => {
          console.log('CONTEXT', Object.keys(context));
          /*
            'db',           'query',
            'totalResults', 'prisma',
            'graphql',      'maxTotalResults',
            'sudo',         'exitSudo',
            'withSession',  'req',
            'session',      'startSession',
            'endSession',   'gqlNames',
            'images',       'files'
          */
          const session = context.session as Session;
          console.log('SESSION', session); // undefined
          return true;
        },
      },
    },
  });
  • 1
    Rather than posting answers, that just extend the question, please choose to edit the question or making a comment if it is as a reaction to someones answer – MalwareMoon Nov 27 '22 at 23:09
  • Are you sure the HTTP call that hits the `confirmBooking` mutation does in fact carry the cookies that identify an existing session? Obviously, if these are missing, the request will be processed without the session object being populated. – Molomby Nov 28 '22 at 00:30
  • Hello Sorry for the double answer. I am not a regular user of StackOverflow. That's my problem. I don't understand why the mutation doesn't contain a cookie in the context. Normally it should exist. I am well connected on the frontend, and the Keystone admin. Maybe a configuration problem... I don't know and the problem persists – user1189847343 Nov 29 '22 at 08:20
0

With 'Graphql Tool Merge Schemas' from documentation (https://keystonejs.com/docs/guides/schema-extension#title)

'context.session' continue to be undefined :/

export const extendGraphqlSchema = (schema: GraphQLSchema) =>
  mergeSchemas({
    schemas: [schema],
    typeDefs: `
      type Query {
        allGifts: [Gift]
      }
      type Mutation {
        confirmBooking(giftId: ID!): Boolean
      }
    `,
    resolvers: {
      Query: {
        // Testing
        allGifts: (root, { id, days }, context: Context) =>
          context.db.Gift.findMany(),
      },
      Mutation: {
        // To implement
        confirmBooking: (root, { giftId }, context: Context) => {
          console.log('CONTEXT', Object.keys(context));
          /*
            'db',           'query',
            'totalResults', 'prisma',
            'graphql',      'maxTotalResults',
            'sudo',         'exitSudo',
            'withSession',  'req',
            'session',      'startSession',
            'endSession',   'gqlNames',
            'images',       'files'
          */
          const session = context.session as Session;
          console.log('SESSION', session); // undefined
          return true;
        },
      },
    },
  });

I tried to use your graphql.extend(base) syntax And the log dumping session object is undefined too :)

export const extendGraphqlSchema = graphql.extend((base) => ({
  mutation: {
    confirmBooking: graphql.field({
      type: graphql.Float,
      args: {},
      // eslint-disable-next-line no-empty-pattern
      resolve(source, {}, context: Context) {
        console.log('Dumping session object:', context.session);
        return Math.random();
      },
    }),
  },
}));
0

I just encountered this problem - spent hours combing the web & keystone docs for any info on why it might be happened and found nothing, but then realised that auth headers were not being passed as I was calling the mutation from the graphql sandbox api explorer.

Long story short - if you have set it up like the keystone 6 docs, your logged in frontend should be able to call the mutations no problem.

desertnaut
  • 57,590
  • 26
  • 140
  • 166
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 19 '23 at 15:59