graphql

SKILL.md

GraphQL Development

Design efficient GraphQL APIs.

When to Use

  • Creating GraphQL schemas
  • Resolver implementation
  • N+1 query problems
  • Federation/stitching
  • Performance optimization

Schema Design

type Query {
  user(id: ID!): User
  users(filter: UserFilter, limit: Int = 10): UserConnection!
}

type Mutation {
  createUser(input: CreateUserInput!): CreateUserPayload!
  updateUser(id: ID!, input: UpdateUserInput!): UpdateUserPayload!
}

type User {
  id: ID!
  email: String!
  name: String!
  posts(first: Int, after: String): PostConnection!
  createdAt: DateTime!
}

input CreateUserInput {
  email: String!
  name: String!
}

type CreateUserPayload {
  user: User
  errors: [Error!]
}

type UserConnection {
  edges: [UserEdge!]!
  pageInfo: PageInfo!
  totalCount: Int!
}

type UserEdge {
  node: User!
  cursor: String!
}

type PageInfo {
  hasNextPage: Boolean!
  endCursor: String
}

Resolvers

const resolvers = {
  Query: {
    user: (_, { id }, { dataSources }) => dataSources.users.getById(id),

    users: async (_, { filter, limit }, { dataSources }) => {
      const users = await dataSources.users.find(filter, limit);
      return connectionFromArray(users);
    },
  },

  User: {
    // Field resolver with DataLoader for N+1
    posts: (user, args, { loaders }) => loaders.postsByUser.load(user.id),
  },

  Mutation: {
    createUser: async (_, { input }, { dataSources }) => {
      try {
        const user = await dataSources.users.create(input);
        return { user, errors: null };
      } catch (e) {
        return { user: null, errors: [{ message: e.message }] };
      }
    },
  },
};

DataLoader (N+1 Solution)

const DataLoader = require("dataloader");

const createLoaders = (dataSources) => ({
  userById: new DataLoader(async (ids) => {
    const users = await dataSources.users.getByIds(ids);
    const userMap = new Map(users.map((u) => [u.id, u]));
    return ids.map((id) => userMap.get(id) || null);
  }),

  postsByUser: new DataLoader(async (userIds) => {
    const posts = await dataSources.posts.findByUserIds(userIds);
    const grouped = groupBy(posts, "userId");
    return userIds.map((id) => grouped[id] || []);
  }),
});

Performance Tips

  • Use DataLoader for batching
  • Implement query complexity limits
  • Add depth limiting
  • Cache with Redis/CDN
  • Use persisted queries

Best Practices

  • Nullable by default, explicit ! for required
  • Use input types for mutations
  • Return payload types with errors
  • Implement cursor pagination
  • Version via schema evolution

Examples

Input: "Fix N+1 queries" Action: Implement DataLoader, batch database queries

Input: "Design user management API" Action: Create schema with types, queries, mutations, pagination

Weekly Installs
4
Installed on
claude-code3
windsurf2
antigravity2
gemini-cli2
trae1
opencode1