Connecting a relationship using a hook in Keystone.js 6

I’m writing this for the weary internet traveler because I spent 3 hours debugging this and finally had some coffee ☕️ and figured it out after running into a ton of errors.

This is my desired outcome: every time a user signs up for my app, I want to associate the “Reader” role with that user. I had the option of doing this from the frontend but I would’ve had to run two mutations which isn’t ideal and I’m sure I was going to encounter a race condition in some cases.

The role list in my app can either be an “Admin”, “Reader”, or “Robot”. Pretty self-explanatory but I wanted to make sure all new users signing up are of the Reader role so they can’t mess with other users etc. Keystone does not come with a lot of built in control for this and I’m following Wes Bos’ example of Roles for Users.

Here’s the code:

// this is the Role schema
Role: list({
    fields: {
      name: text({ validation: { isRequired: true } }),
      assignedTo: relationship({
        ref: "User.role", // this is how the user is related to this list
        many: true,
      }),
    },
  }),
// this is the User schema, truncated to only show the Role relation

role: relationship({
        ref: "Role.assignedTo",
        hooks: {
          resolveInput: async ({ resolvedData, operation, context }) => {
            if (operation === "create") {
              const reader = await context.query.Role.findMany({
                where: { name: { equals: "Reader" } },
              });
              resolvedData.role = { connect: { id: reader[0].id } };
            }
            return resolvedData["role"];
          },
        },
      }),

The part I was struggling with was a vague Prisma error like the following, the UI only said “Prisma error”

Unknown arg `role` in data.role for type UserUncheckedCreateInput. Did you mean `roleId`? Available args:
type UserUncheckedCreateInput {
  id?: String
  name?: String
  username?: String
  email?: String
  password: String
  roleId?: String | Null
  readings?: ReadingUncheckedCreateNestedManyWithoutUserInput
}

I guess this error is not very helpful to someone running into this for the first time so my best understanding of it is that it’s due to the resolvedData being returned incorrect. I was returning resolvedData but instead needed to return resolvedData["role"] where role is the field name.

Some terminology

TermDescription
listKeystone’s way of indicating tables, more documentation: https://keystonejs.com/docs/apis/config#lists
field, or field nameA property on a list, aka a column in a table.

Posted

in