0
votes

This has been reported 100s of times, perhaps, but still posting, since this is the simplest case, and I can't figure out what's wrong here.

schema.js:

const { gql } = require("apollo-server");

const typeDefs = gql`
  scalar MongoID

  type User {
    _id: MongoID!
    address: String!
  }

  input LoginInput {
    address: String!
  }

  type Query {
    getUserById(userId: MongoID!): User!
  }

  type Mutation {
    createUser(loginInput: LoginInput): User!
  }
`;

module.exports = typeDefs;

resolver:

const User = require("../../models/User");

const createUser = async (args) => {
  try {
    const existingUser = await User.findOne({
      address: args.loginInput.address,
    });

    if (existingUser) {
      throw new Error("User already exists!");
    }

    const user = new User({
      address: args.loginInput.address,
    });

    const result = await user.save();

    return result;
  } catch (err) {
    console.error(err.message);
    res.status(500).send("Server error");
  }
};

module.exports = { createUser };

User model:

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

const UserSchema = new Schema({
  address: {
    type: String,
    unique: true,
    required: true,
  },
  date: {
    type: Date,
    default: Date.now,
  },
});

module.exports = User = mongoose.model("User", UserSchema);

Mutation:

mutation createUser($loginInput: LoginInput!) {
  createUser(loginInput: $loginInput) {
    _id
    address
  }
}

Query variables:

{
  "loginInput": {
    "address": "some address"
  }
}

All the queries and mutations of this schema return the mentioned error, as I explicitly specified User!. Note: same thing happens with ID! as well, instead of MongoId

What is wrong here?

UPD: Added server.js as no query is being processed (always returns data:null), and I think something could be wrong with the setup, though doubt it.

const express = require("express");
const session = require("express-session");
const { ApolloServer } = require("apollo-server-express");
const typeDefs = require("./graphql/schema/schema");
const rootResolver = require("./graphql/resolvers/index");
const config = require("config");
const sessionSecret = config.get("express_session_secret");
const connectDB = require("./config/db");

const app = express();

app.use(
  session({
    resave: true,
    saveUninitialized: true,
    secret: sessionSecret,
    cookie: {
      maxAge: 1000 * 60 * 60 * 24 * 355,
    },
  })
);

// Init Middleware
app.use(express.json({ extended: false }));

// Connect Database
connectDB();

const apolloServer = new ApolloServer({
  typeDefs,
  rootResolver,
});

apolloServer.applyMiddleware({ app });

// Serve static assets in production
if (process.env.NODE_ENV === "production") {
  // Set static folder
  app.use(express.static("client/build"));

  app.get("*", (req, res) => {
    res.sendFile(path.resolve(__dirname, "client", "build", "index.html"));
  });
}

const PORT = process.env.PORT || 5000;

app.listen(PORT, () => {
  console.log(`Server started on port ${PORT}`);
  console.log(`GraphQL available at ${PORT}${apolloServer.graphqlPath}`);
});

When running, I successfully get the console messages.

1

1 Answers

0
votes

In my case, the issue was in structure. As I am using apollo-server-express, I needed to define a single resolvers file (I was combining several previously). I defined resolvers.jsthe following way, and everything worked:

const User = require("../../models/User");

const resolvers = {
  Query: {
    getUserById(parent, args) {
      const user = User.findById(args.userId);
      return user;
    },
  },

  Mutation: {
    createUser(parent, args) {
      const existingUser = User.findOne({
        address: args.loginInput.address,
      });

      if (existingUser) {
        throw new Error("User already exists!");
      }

      const user = new User({
        address: args.loginInput.address,
      });

      const result = user.save();

      return {
        userId: user.id,
        address: user.address,
      };
    },
  },
};

module.exports = resolvers;

Note: this is what needs to be imported in the constructor, don't rename the files:

const apolloServer = new ApolloServer({
  typeDefs,
  resolvers,
});