1
votes

I have the following resolver for GraphQL:

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

module.exports = {
  getAllActivePosts: async (userId) => {
    try {
      const posts = await Post.find({
        userId: userId
      })
        .select(["name", "createdAt"])
        .populate("posts", ["name", "createdAt"]);

      return posts;
    } catch (err) {
      console.log(err);
      throw err;
    }
  },
};

which tries to get all active posts by the ID of the user from the Post model:

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

const PostSchema = new mongoose.Schema({
  userId: {
    type: Schema.Types.ObjectId,
    ref: "User",
    required: true,
  },
  content: {
    type: String,
    required: true,
  },
  createdAt: {
    type: Date,
    required: true,
  }
});

module.exports = Post = mongoose.model("Post", PostSchema);

Here's the GraphQL Schema:

const { buildSchema } = require('graphql');

module.exports = buildSchema(`
        type User {
            _id: MongoId!
            email: String!
            password: String
        }

        type Post {
            _id: MongoId!
            userId: MongoId!
            content: String!
            createdAt: String!
        }

        scalar MongoId

        input LoginInput {
            email: String!
            password: String!
        }

        type RootQuery {
            login(email: String!, password: String!): AuthData!
            getAllActivePosts(userId: MongoId!): [Post]
        }

        type RootMutation {
            createUser(loginInput: LoginInput): AuthData!
        }

        schema {
            query: RootQuery
            mutation: RootMutation
        }
    `);

... and the GraphQL query I'm running in GraphiQL:

{
  getAllActivePosts(userId: "5fbfc92312b90071179a160f") {
    name
    createdAt
  }
}

For this, the result of the query is:

{
  "errors": [
    {
      "message": "Cast to ObjectId failed for value \"{ userId: '5fbfc92312b90071179a160f' }\" at path \"userId\" for model \"Post\"",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "getAllActivePosts"
      ]
    }
  ],
  "data": {
    "getAllActivePosts": null
  }
}

Searched here for similar issues, tried wrapping userId in ObjectId, but nothing helped. What am I missing here?

2

2 Answers

1
votes

I was go through this problem once a year ago with no solution till i get main concept of graphql. Here you are passing string

{
  getAllActivePosts(userId: "5fbfc92312b90071179a160f") {
    name
    createdAt
  }
}

and graphql expecting to have mongoose.Types.ObjectId

getAllActivePosts(userId: MongoId!): [Post]

You need to do sync like

 getAllActivePosts(userId: mongoose.Types.ObjectId("5fbfc92312b90071179a160f")) {

But using above way you are not eligible for run query in graphiQL becuse there is no mongoose defined.

type RootQuery {
    login(email: String!, password: String!): AuthData!
    getAllActivePosts(userId: String!): [Post]
}

Better solution is use userId input as string and then validate on your resolver function like

getAllActivePosts: async ({ userId }) => {
    try {
      if(mongoose.Types.ObjectId.isValid(userId)) {
        const posts = await Post.find({
          userId: userId
        }) 
        .select(["name", "createdAt"])
        .populate("posts", ["name", "createdAt"]);
       // you can;t return null you need to return array
       return posts ? posts : []
      } else {
       // if mongoose id is wrong
       return []
      }
   } catch(error) {
    // it is better to throw error return blank array to complete flow
    throw error
   }
}
0
votes

Turned out, I was using userId directly, whereas I should've used args.userId. The proper resolver below:

module.exports = {
  getAllActivePosts: async (args) => {
    try {
      const posts = await Post.find({
        userId: args.userId
      })
        .select(["name", "createdAt"])
        .populate("posts", ["name", "createdAt"]);

      return posts;
    } catch (err) {
      console.log(err);
      throw err;
    }
  },
};

and for the schema:

getAllActivePosts(userId: String!): [Post]