2

I created a resolver and graphql file about user creation.
The data type seems to fit, and I have asynchronous processing, but the result always return null. I don't know why.

  • Resolver (createAccount.js)
import { prisma, generateToken, changePhoneNumber } from "../../../utils";
import bcrypt from "bcryptjs";

export default {
  Mutation: {
    createAccount: async (_, args) => {
      const {
        username,
        password,
        password2,
        email,
        phoneNum,
        bio,
        avatarUrl,
      } = args;

      if (password !== password2) {
        throw new Error("two password aren't same each other");
      }

      const encryptPw = await bcrypt.hash(password, 10);
      const newPhoneNumber = await changePhoneNumber(phoneNum, "+82");
      const user = await prisma.user.create({
        data: {
          username,
          email,
          password: encryptPw,
          phoneNum: newPhoneNumber,
          bio,
          avatarUrl,
        },
      });
      const token = generateToken(user.id);

      return { token, user };
    },
  },
};

  • GraphQL file (createAccount.graphql)
type Mutation {
  createAccount(
    username: String!
    email: String!
    password: String!
    password2: String!
    phoneNum: String!
    bio: String
    avatarUrl: String
  ): AuthPayload!
}


type AuthPayload {
  token: String
  user: User
}

  • utils.js
import { PrismaClient } from "@prisma/client";
import jwt from "jsonwebtoken";

export const prisma = new PrismaClient();

export const changePhoneNumber = (phoneNum, locationNum) => {
  var leftStr = locationNum;
  var rightStr = phoneNum.slice(1, phoneNum.length);
  var newStr = leftStr + rightStr;
  return newStr;
};

export const generateToken = (id) => jwt.sign({ id }, process.env.JWT_SECRET);
  • models.graphql
type User {
  id: ID!
  avatarUrl: String
  username: String!
  email: String!
  password: String!
  phoneNum: String!
  emailSecret: String
  phoneSecret: String
  bio: String
  rooms: [Room]
  createdAt: String
  messages: [Message]
  sender: [User]
  receiver: [User]
}

I read the answers to other similar questions, but most said that I should fit the data type or asynchronous processing.
(Why does a GraphQL query return null?)
But my code used code for asynchronous processing, and I guess I matched the data type. Why does this code always return null? enter image description here
Also, in addition to this Mutation, all other Query, Mutation and Subscriptions return nulls

sdy
  • 335
  • 1
  • 3
  • 10
  • Please create a stackblitz so that we can have a closer look – Yogesh Aggarwal May 26 '20 at 03:18
  • It might be some error occurring in before returning the object – Yogesh Aggarwal May 26 '20 at 03:18
  • Please edit the question to show how `createAccount.js` is being imported and how you're creating your resolver map using it. – Daniel Rearden May 26 '20 at 03:24
  • @YogeshDeveloper sorry I tried to stackblitz, but I can not bring github, so I leave my github repo address. [link](https://github.com/khusw/capstone/tree/master/back) – sdy May 26 '20 at 03:27
  • @sdy please see my edited answer. The issue boils down to what you're exporting in two of the modules (function instead of object), which is causing `mergeResolvers` to return a function instead of an object. – Daniel Rearden May 26 '20 at 03:52

1 Answers1

2

Based on the error, it looks like GraphQL doesn't think you've provided a resolver for the createAccount field at all. The issue is with how you're merging your resolvers. This is your code:

const allTypes = fileLoader(path.join(__dirname, "api/**/*.graphql"));
const allResolvers = fileLoader(path.join(__dirname, "api/**/*.js"));

const schema = makeExecutableSchema({
  typeDefs: mergeTypes(allTypes),
  resolvers: mergeResolvers(allResolvers),
});

This is the resulting value of allResolvers:

[ { Query: { TestQL: [Function: TestQL] } },
  { Mutation: { addCategory: [Function: addCategory] } },
  { Mutation: { deleteCategory: [Function: deleteCategory] } },
  { Mutation: { editCategory: [Function: editCategory] } },
  { Mutation: { newMessage: [Function: newMessage] } },
  { Subscription: { subMessage: [Object] } },
  [Function: _default],
  { Mutation: { createRoom: [Function: createRoom] } },
  [Function: _default],
  { Query: { getRooms: [Function: getRooms] } },
  { Mutation: { createAccount: [Function: createAccount] } },
  { Mutation: { deleteUser: [Function: deleteUser] } },
  { Mutation: { editProfile: [Function: editProfile] } },
  { Query: { findEmail: [Function: findEmail] } },
  { Mutation: { login: [Function: login] } },
  { Mutation: { requestEmailSecret: [Function: requestEmailSecret] } },
  { Mutation: { resetPassword: [Function: resetPassword] } },
  { Query: { searchUser: [Function: searchUser] } },
  { Query: { seeProfile: [Function: seeProfile] } } ]

Two of your modules export a function instead of an object:

export default () => {...}

As a result, what's returned by mergeResolvers ends up being a function, not an object. So you're not providing a resolver map at all to makeExecutableSchema. You need to fix the default exports for those two modules for the resolvers to be merged correctly.

Daniel Rearden
  • 80,636
  • 11
  • 185
  • 183