Ibrahim
Ibrahim

Reputation: 340

Trouble Returning Relational Data in GraphQL

I'm creating a Reddit clone and I'm setting up the backend first, but having trouble creating relational data.

When I use this query:

query {
  subreddit(id: 1) {
    name
    posts {
      title
    }
  }
}

I expect:

{
  "data": {
    "subreddit": {
      "name": "javascript"
      "posts": [
        {
          "title": "JS Post"
        }
      ]
    }
  }
}

What I get:

{
  "data": null,
  "errors": [
    {
      "message": "Cannot return null for non-nullable field Subreddit.posts.",
      "locations": [
        {
          "line": 4,
          "column": 5
        }
      ],
      "path": [
        "subreddit",
        "posts"
      ]
    }
  ]
}

Here's the schema:

type Query {
  subreddits: [Subreddit!]!
  subreddit(id: ID!): Subreddit!
  posts: [Post!]!
  post(id: ID!): Post!
}

type Mutation {
  createSubreddit(
    name: String!
    description: String!
    contentType: String!
    ageRestriction: Boolean!
  ): Subreddit!
}

type Subreddit {
  id: ID!
  name: String!
  description: String!
  contentType: String!
  ageRestriction: Boolean!
  posts: [Post!]!
}

type Post {
  id: ID!
  title: String!
  body: String!
  subredditId: ID!
  # userId: ID!
}

Here is server/index.js:

const { GraphQLServer } = require('graphql-yoga');

let dummySubreddits = [
  {
    name: 'javascript',
    description: 'all things javascript',
    contentType: 'any',
    ageRestriction: false,
    id: 1
  },
  {
    name: 'react',
    description: 'all things react',
    contentType: 'any',
    ageRestriction: false,
    id: 2
  },
  {
    name: 'primsa',
    description: 'all things prisma',
    contentType: 'any',
    ageRestriction: false,
    id: 3
  }
];
let idCountSubreddit = dummySubreddits.length;

let dummyPosts = [
  { title: 'JS Post', body: 'Body of post one', id: 1, subredditId: 1 },
  { title: 'React Post', body: 'Body of post two', id: 2, subredditId: 2 },
  {
    title: 'Prisma Post',
    body: 'Body of post three',
    id: 3,
    subredditId: 3
  }
];
let idCountPost = dummyPosts.length;

const resolvers = {
  Query: {
    subreddits: () => dummySubreddits,
    subreddit: (parent, args) => {
      return dummySubreddits.find(obj => obj.id == args.id);
    },
    posts: () => (parent, args) => {
      return dummyPosts.find(obj => obj.subredditId == parent.id);
    },
    post: (parent, args) => {
      return dummyPosts.find(obj => obj.id == args.id);
    }
  },
  Mutation: {
    createSubreddit: (parent, args) => {
      let subreddit = {
        id: idCountSubreddit++,
        name: args.name,
        description: args.description,
        contentType: args.contentType,
        ageRestriction: args.ageRestriction
      };
      return subreddit;
    }
  }
};

const server = new GraphQLServer({ typeDefs: './schema.graphql', resolvers });
server.start(() => console.log('Server is running on localhost:4000'));

I'm using the GraphQL desktop app for querying and I do not have grapql-yoga config file.

Where am I going wrong? I'd like to be pointed in the right direction so I can figure it out myself. This is my first time working with GraphQL alone, after doing some tutorials on YouTube, however they used graphql-express and I'm using graphql-yoga.

Upvotes: 0

Views: 216

Answers (2)

Ibrahim
Ibrahim

Reputation: 340

I had to add a resolver for subreddit to deal with posts.

const resolvers = {
  Query: {
    subreddits: () => dummySubreddits,
    subreddit: (parent, args) => {
      return dummySubreddits.find(obj => obj.id == args.id);
    },
    posts: (parent, args) => {
      return dummyPosts;
    },
    post: (parent, args) => {
      return dummyPosts.find(obj => obj.id == args.id);
    }
  },
  Mutation: {
    createSubreddit: (parent, args) => {
      let subreddit = {
        id: idCountSubreddit++,
        name: args.name,
        description: args.description,
        contentType: args.contentType,
        ageRestriction: args.ageRestriction
      };
      return subreddit;
    }
  },

  // This resolver was needed
  Subreddit: {
    posts: subreddit =>
      dummyPosts.filter(obj => obj.subredditId == subreddit.id)
  }
};

Upvotes: 0

Herku
Herku

Reputation: 7666

Move the resolver you have written for Query's posts into Subreddit to resolve the posts field there. If your resolver does not comply to the default resolver implementation:

(parent) => parent[fieldName]

Like in your case

(parent) => parent.posts

You have to specify it yourself. If your field posts on Query should display all the posts you might want to go for the following implementations:

const resolvers = {
  Query: {
    subreddits: () => dummySubreddits,
    subreddit: (parent, args) => {
      return dummySubreddits.find(obj => obj.id == args.id);
    },
    posts: () => dummyPosts,
    post: (parent, args) => {
      return dummyPosts.find(obj => obj.id == args.id);
    }
  },
  Subreddit: {
    posts: () => (parent, args) =>
      dummyPosts.filter(obj => obj.subredditId == parent.id),
  },
  Mutation: {
    createSubreddit: (parent, args) => {
      let subreddit = {
        id: idCountSubreddit++,
        name: args.name,
        description: args.description,
        contentType: args.contentType,
        ageRestriction: args.ageRestriction
      };
      return subreddit;
    }
  }
};

Upvotes: 1

Related Questions