graphql-nexus / nexus

Code-First, Type-Safe, GraphQL Schema Construction
https://nexusjs.org
MIT License
3.4k stars 274 forks source link

unionType issue/question #1137

Open radromanov opened 1 year ago

radromanov commented 1 year ago

Hello guys,

I've been learning Nexus and I've been trying to implement a unionType that returns either a LoginSuccess, with its respective fields, or a LoginError -- the implementation could be applied to any other context, I suppose. However, I keep running into an error, and I can't wrap my head around it:

Error: Expected LoginSuccess to be a objectType, saw GraphQLScalarType

LoginSuccess is an objectType as seen below, so how come Nexus doesn't recognize it as such?

The code in question:

// src/graphql/types/auth/loginUser.ts

export const LoginUser = extendType({
  type: "Mutation",
  definition: (t) => {
    t.nonNull.field("loginUser", {
      type: LoginResult,
      args: {
        credentials: nonNull(LoginCredentials),
      },
      resolve: loginUser,
    });
  },
});

const LoginSuccess = objectType({
  name: "LoginSuccess",
  definition: (t) => {
    t.string("sid");
    t.id("id");
    t.boolean("loggedIn");
  },
});

const LoginError = objectType({
  name: "LoginError",
  definition: (t) => {
    t.boolean("error");
    t.string("message");
  },
});

// Type
const LoginResult = unionType({
  name: "LoginResult",
  definition: (t) => {
    t.members(LoginSuccess, LoginError);
  },
  resolveType: (data) => {
    const __typename =
      "username" in data
        ? "LoginSuccess"
        : "error" in data
        ? "LoginError"
        : null;

    if (!__typename) {
      throw new Error(
        `Could not resolve the type of data passed to union type "LoginResult"`
      );
    }

    return __typename;
  },
});

// Args
const LoginCredentials = inputObjectType({
  name: "LoginCredentials",
  definition: (t) => {
    t.nonNull.string("username");
    t.nonNull.string("password");
  },
});

I am also exporting the type, and importing it into my schema:

// src/graphql/types/index.ts

export * from "./auth/loginUser";
// src/graphql/schema.ts

import { join } from "path";
import { asNexusMethod, makeSchema } from "nexus";
import { DateTimeResolver } from "graphql-scalars";

import * as types from "../graphql/types";

const DateTime = asNexusMethod(DateTimeResolver, "DateTime");

export const schema = makeSchema({
  types: [types, DateTime],
  outputs: {
    typegen: join(
      process.cwd(),
      "node_modules",
      "@types",
      "nexus-typegen",
      "index.d.ts"
    ),
    schema: join(process.cwd(), "src/graphql/schema.graphql"),
  },
  contextType: {
    module: require.resolve("./context.ts"),
    export: "Context",
  },
});

My package.json dependencies:

...,
"dependencies": {
    "@prisma/client": "^4.4.0",
    "apollo-server-express": "^3.10.3",
    "bcrypt": "^5.1.0",
    "connect-redis": "^6.1.3",
    "cors": "^2.8.5",
    "express": "^4.18.2",
    "express-session": "^1.17.3",
    "graphql": "^16.6.0",
    "graphql-scalars": "^1.19.0",
    "ioredis": "^5.2.3",
    "nanoid": "^3.0.0",
    "next": "^12.3.1",
    "nexus": "^1.3.0",
    "node-fetch": "^3.2.10",
    "nodemailer": "^6.8.0",
    "zod": "^3.19.1"
  },
  "devDependencies": {
    "@types/bcrypt": "^5.0.0",
    "@types/connect-redis": "^0.0.18",
    "@types/cookies": "^0.7.7",
    "@types/cors": "^2.8.12",
    "@types/express": "^4.17.14",
    "@types/express-session": "^1.17.5",
    "@types/ioredis": "^4.28.10",
    "@types/node": "^18.8.4",
    "@types/nodemailer": "^6.4.6",
    "prisma": "^4.4.0",
    "ts-node": "^10.9.1",
    "ts-node-dev": "^2.0.0",
    "typescript": "^4.8.4"
  }

I could be overlooking something really simple here, but any help with this would be very much appreciated!

Thank you.

larrifax commented 1 year ago

Just bumped into this issue myself. Resolved it by doing as specified in https://github.com/graphql-nexus/nexus/issues/816#issuecomment-772824518, putting it into makeSchema's types.

In your case it will probably be enough to export both LoginSuccess and LoginError (maybe also LoginResult)