Build the mental model
This project combines schema design, resolvers and context, and DataLoader batching from earlier lessons into one complete Blog API — `Post`/`Comment` types, a `posts` query, `createPost`/`addComment` mutations, and a DataLoader-backed `Post.comments` field. Layer the application as schema (contract), resolvers (glue), and repository/db (data access) for testability.
Connect it to a real scenario
Build the Tutorial Platform's blog section with this project — `Post` (id, title, body) and `Comment` (id, body, author) types, a `posts` query, `createPost`/`addComment` mutations, and a `commentsByPost` DataLoader batching comment reads. End-to-end test it by creating a post, adding two comments, then querying posts to confirm nested comments come back correctly.
Try the working example
const typeDefs = `#graphql
type Post {
id: ID!
title: String!
body: String!
comments: [Comment!]!
}
type Comment {
id: ID!
body: String!
author: String!
}
type Query {
posts: [Post!]!
}
type Mutation {
createPost(title: String!, body: String!): Post!
addComment(postId: ID!, body: String!, author: String!): Comment!
}
`;
const resolvers = {
Query: {
posts: (_p: unknown, _a: unknown, ctx: Context) => ctx.db.post.findMany(),
},
Mutation: {
createPost: (_p: unknown, args: PostInput, ctx: Context) =>
ctx.db.post.create({ data: args }),
addComment: (_p: unknown, args: CommentInput, ctx: Context) =>
ctx.db.comment.create({ data: args }),
},
Post: {
comments: (post: Post, _a: unknown, ctx: Context) =>
ctx.loaders.commentsByPost.load(post.id),
},
};You can run a working Blog API end to end with schema, resolvers, mutations, and DataLoader in place.5-minute try-it
Add a `deletePost(id: ID!): Boolean!` mutation and write its resolver to also delete associated comments.
One important caution
Storing comments in one unrelated array and manually filtering by `postId` inside the `Post.comments` resolver grows into an O(N) cost as the project scales — use a database query or DataLoader instead.
Apollo Server — Getting Started — GraphQL