Redwood: Graphql validation error from generate scaffold [includes short-term work-around]

Created on 10 Mar 2020  ·  9Comments  ·  Source: redwoodjs/redwood

ENVIRONMENT

0.1.0

PREPARATION

Created custom models, and ran yarn rw db save and yarn rw db up -- success. Schema:

model User {
id          String @id @default(cuid())
name        String
email       String
wkspaces    Workspace[] @relation(name: "UserAsWorkspaceMember")
wkspaces_o  Workspace[] @relation(name: "UserAsWorkspaceOwner")
projects    Project[] @relation(name: "UserAsProjectMember")
projects_o  Project[] @relation(name: "UserAsProjectOwner")
createdAt   DateTime @default(now())
}

model Workspace {
id          String @id @default(cuid())
name        String
owner       User? @relation(name: "UserAsWorkspaceOwner")
users       User[] @relation(name: "UserAsWorkspaceMember")
createdAt   DateTime @default(now())
}

model Project {
id          String @id @default(cuid())
wkspace     Workspace @relation(name: "WorkspaceAsProjectContainer")
name        String
owner       User @relation(name: "UserAsProjectOwner")
users       User[] @relation(name: "UserAsProjectMember")
createdAt   DateTime @default(now())
}

Ran yarn rw g scaffold user and yarn rw g scaffold workspace and yarn rw g scaffold project -- all ran (after I manually patched around the "scaffold.css already exists" problem).

OBSERVED PROBLEM

When I started the server via yarn rw dev, got this error trace repeatedly:

17:56:13 api |
17:56:13 api | /Users/chris/proj/aw-hammer/node_modules/graphql/type/validate.js:71
17:56:13 api |     throw new Error(errors.map(function (error) {
17:56:13 api |           ^
17:56:13 api | Error: The type of ProjectInput.wkspace must be Input Type but got: Workspace.
17:56:13 api |
17:56:13 api | The type of ProjectInput.owner must be Input Type but got: User.
17:56:13 api |
17:56:13 api | The type of ProjectInput.users must be Input Type but got: User.
17:56:13 api |
17:56:13 api | The type of UserInput.wkspaces must be Input Type but got: Workspace.
17:56:13 api |
17:56:13 api | The type of UserInput.wkspaces_o must be Input Type but got: Workspace.
17:56:13 api |
17:56:13 api | The type of UserInput.projects must be Input Type but got: Project.
17:56:13 api |
17:56:13 api | The type of UserInput.projects_o must be Input Type but got: Project.
17:56:13 api |
17:56:13 api | The type of WorkspaceInput.owner must be Input Type but got: User.
17:56:13 api |
17:56:13 api | The type of WorkspaceInput.users must be Input Type but got: User.
17:56:13 api |
17:56:13 api | The type of WorkspaceInput.projects must be Input Type but got: Project.
17:56:13 api |     at assertValidSchema (/Users/chris/proj/aw-hammer/node_modules/graphql/type/validate.js:71:11)
17:56:13 api |     at assertValidExecutionArguments (/Users/chris/proj/aw-hammer/node_modules/graphql/execution/execute.js:136:35)
17:56:13 api |     at executeImpl (/Users/chris/proj/aw-hammer/node_modules/graphql/execution/execute.js:86:3)
17:56:13 api |     at Object.execute (/Users/chris/proj/aw-hammer/node_modules/graphql/execution/execute.js:64:63)
17:56:13 api |     at Object.generateSchemaHash (/Users/chris/proj/aw-hammer/node_modules/apollo-server-core/src/utils/schemaHash.ts:11:18)
17:56:13 api |     at ApolloServer.generateSchemaDerivedData (/Users/chris/proj/aw-hammer/node_modules/apollo-server-core/src/ApolloServer.ts:496:24)
17:56:13 api |     at new ApolloServerBase (/Users/chris/proj/aw-hammer/node_modules/apollo-server-core/src/ApolloServer.ts:369:32)
17:56:13 api |     at new ApolloServer (/Users/chris/proj/aw-hammer/node_modules/apollo-server-lambda/src/ApolloServer.ts:38:5)
17:56:13 api |     at createGraphQLHandler (/Users/chris/proj/aw-hammer/node_modules/@redwoodjs/api/src/graphQLServer.ts:48:19)
17:56:13 api |     at Object.<anonymous> (/Users/chris/proj/aw-hammer/api/src/functions/graphql.js:37:47)
error Command failed with exit code 1.
generators

Most helpful comment

All 9 comments

In my schema, the Workspace and Project models are like this:

model Workspace {
    id          String @id @default(cuid())
    name        String
    owner       User? @relation(name: "UserAsWorkspaceOwner")
    users       User[] @relation(name: "UserAsWorkspaceMember")
    createdAt   DateTime @default(now())
}

model Project {
    id          String @id @default(cuid())
    wkspace     Workspace @relation(name: "WorkspaceAsProjectContainer")
    name        String
    owner       User @relation(name: "UserAsProjectOwner")
    users       User[] @relation(name: "UserAsProjectMember")
    createdAt   DateTime @default(now())
}

That means the Projects:Workspace relation is N:1 ... each project has one workspace; each workspace can have many projects. In other words, Project.wkspace points to a Workspace.

Looking at the generated workspaces.sdl.js:

type Workspace {
    id: String!
    name: String!
    owner: User
    users: User
    createdAt: DateTime!
    projects: Project
}

input WorkspaceInput {
    name: String
    owner: User
    users: User
    projects: Project
}

Should projects: Project be projects: [Project] due to the 1:N relation?

I'll be honest, when we built the generators it was to make sure the tutorial worked as written, we hadn't looked into the more complex relation syntax that prisma provides. It's on our list, though!

See https://graphql.org/graphql-js/mutations-and-input-types: "Input types can't have fields that are other objects, only basic scalar types, list types, and other input types".

Here's an in-depth explanation of why this is: https://stackoverflow.com/a/55881719/763269.

Bottom line: when one model references another (think foreign keys), dumb example like this:

model Invoice {
    id Int @id @default(autoincrement())
    name String!
    lines InvoiceLine[]
}

model InvoiceLine {
    id Int @id @default(autoincrement())
    quantity Int!
    unitprice Float!
    invoice Invoice!
}

... the input type for InvoiceLine should be like this:

input InvoiceLineInput {
  quantity: Int
  unitprice: Float
  invoice: Int                <-- NOTE THIS
}

For the input type, the type of the field that references the parent Invoice type needs to match the scalar data type (in this case, Int) of the @id field in the Invoice type.

In other words, any place the SDL generation is applying a custom type to an input type field, that's what needs to change. Input fields can be only scalars or enums (or wrappers of those).

Thanks for this! And on the off chance you have days and days of free-time available we'd be more than happy to merge a PR. 😅

I'm taking a look at a PR now, thanks for suggesting.

For those experiencing this before a fix -- an easy manual edit to SDL files bridges over this.

After running yarn rw g scaffold whatever, open whatever.sdl.js and change the type of any fields in the input WhateverInput block that reference custom types to use the (scalar) type used by the @id field in the referenced type, in place of the type name.

Like in my previous comment -- invoice: Invoice! would become invoice: String.

For me that's String since I'm using cuids; by default it would be Int.

Updating this issue Title to indicate there’s a shor-term fix included. Thanks again @chris-hailstorm

Resolved by #229

Was this page helpful?
0 / 5 - 0 ratings