iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Exercises

Three short GraphQL exercises - schema, query, and resolver.

Three short challenges

EXAMPLE
# 1. Design a schema for a small blog
# Requirements: posts, comments, authors, tags. Pagination by cursor.

scalar DateTime

type Author {
  id: ID!
  email: String!
  posts(first: Int = 10, after: String): PostConnection!
}

type Tag {
  id: ID!
  name: String!
}

type Post {
  id: ID!
  title: String!
  body: String!
  author: Author!
  tags: [Tag!]!
  comments(first: Int = 10, after: String): CommentConnection!
  publishedAt: DateTime
}

type Comment {
  id: ID!
  body: String!
  author: Author!
  createdAt: DateTime!
}

type PostConnection {
  edges: [PostEdge!]!
  pageInfo: PageInfo!
}
type PostEdge { node: Post!; cursor: String! }

type CommentConnection {
  edges: [CommentEdge!]!
  pageInfo: PageInfo!
}
type CommentEdge { node: Comment!; cursor: String! }

type PageInfo {
  hasNextPage: Boolean!
  hasPreviousPage: Boolean!
  startCursor: String
  endCursor: String
}

type Query {
  post(id: ID!): Post
  posts(first: Int = 10, after: String, tag: String): PostConnection!
}


# 2. Query: first page of posts tagged 'graphql', plus 5 comments each

query Feed($tag: String!, $count: Int = 5) {
  posts(first: 10, tag: $tag) {
    edges {
      node {
        id
        title
        author { email }
        comments(first: $count) {
          edges { node { id body author { email } } }
        }
      }
    }
    pageInfo { hasNextPage endCursor }
  }
}


# 3. Resolver: implement post.comments efficiently with DataLoader to avoid N+1

// resolvers.ts
import DataLoader from 'dataloader';

function makeCommentsByPostLoader(db) {
  return new DataLoader<string, Comment[]>(async (postIds) => {
    const rows = await db.comments.findMany({
      where: { postId: { in: [...postIds] } },
      orderBy: { createdAt: 'asc' },
    });
    const grouped = new Map<string, Comment[]>(postIds.map((id) => [id, []]));
    for (const r of rows) grouped.get(r.postId)!.push(r);
    return postIds.map((id) => grouped.get(id)!);
  });
}

export const resolvers = {
  Post: {
    comments: async (post, args, ctx) => {
      const all = await ctx.loaders.commentsByPost.load(post.id);
      return paginate(all, args);
    },
  },
};

// Per-request loader
function createContext(req) {
  return { loaders: { commentsByPost: makeCommentsByPostLoader(db) } };
}

# Stretch
# - Add a mutation createPost with a payload type
# - Add a Subscription postCreated
# - Add a UserError type so 'duplicate title' is not a top-level error

Why it matters

Schema design, querying with variables, and DataLoader resolvers are the three legs of GraphQL muscle memory. Drill them on a small domain like a blog before you scale up.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
# Fill in: type Query { users: ____! }
Try it Yourself »

Discussion

Loading…