M

Master Graphql

Battle-tested skill for graphql, gives, clients, exactly. Includes structured workflows, validation checks, and reusable patterns for development.

SkillClipticsdevelopmentv1.0.0MIT
0 views0 copies

GraphQL API Development Skill

A Claude Code skill for building production-grade GraphQL APIs — covering schema design, resolver patterns, N+1 query prevention with DataLoader, authentication, pagination, and performance optimization.

When to Use This Skill

Choose this skill when:

  • Designing a GraphQL schema for a new API
  • Implementing resolvers with proper error handling and authentication
  • Solving N+1 query performance problems with DataLoader
  • Adding pagination, filtering, and sorting to GraphQL queries
  • Migrating from REST to GraphQL or adding a GraphQL layer
  • Setting up GraphQL subscriptions for real-time data

Consider alternatives when:

  • You need a simple CRUD API (REST may be simpler)
  • You need file uploads as the primary use case (use REST or tus)
  • You need high-throughput streaming (use gRPC)

Quick Start

# Install dependencies npm install @apollo/server graphql dataloader # Set up Apollo Server claude "create a GraphQL API with users and posts"
import { ApolloServer } from '@apollo/server'; import { startStandaloneServer } from '@apollo/server/standalone'; const typeDefs = `#graphql type User { id: ID! name: String! email: String! posts: [Post!]! } type Post { id: ID! title: String! content: String! author: User! } type Query { user(id: ID!): User users(limit: Int, offset: Int): [User!]! post(id: ID!): Post } type Mutation { createPost(title: String!, content: String!): Post! } `; const resolvers = { Query: { user: (_, { id }) => userService.findById(id), users: (_, { limit, offset }) => userService.findAll({ limit, offset }), }, User: { posts: (parent, _, { loaders }) => loaders.postsByUser.load(parent.id), }, };

Core Concepts

Schema Design Patterns

PatternUse CaseExample
Connection PaginationLarge lists with cursor-based paginationusersConnection(first: 10, after: "cursor")
Input TypesComplex mutation argumentscreateUser(input: CreateUserInput!)
Union TypesPolymorphic resultsSearchResult = User | Post | Comment
InterfacesShared fields across typesinterface Node { id: ID! }
EnumsConstrained value setsenum Role { ADMIN, USER, GUEST }

DataLoader for N+1 Prevention

import DataLoader from 'dataloader'; // Without DataLoader: N+1 queries // Query 10 users → 10 separate queries for each user's posts // With DataLoader: 2 queries total function createLoaders() { return { postsByUser: new DataLoader(async (userIds: string[]) => { const posts = await db.posts.findMany({ where: { authorId: { in: userIds } } }); // Map results back to input order return userIds.map(id => posts.filter(p => p.authorId === id)); }), }; }

Cursor-Based Pagination

const typeDefs = `#graphql type UserConnection { edges: [UserEdge!]! pageInfo: PageInfo! totalCount: Int! } type UserEdge { cursor: String! node: User! } type PageInfo { hasNextPage: Boolean! hasPreviousPage: Boolean! startCursor: String endCursor: String } type Query { users(first: Int, after: String, last: Int, before: String): UserConnection! } `;

Configuration

ParameterTypeDefaultDescription
serverstring"apollo"GraphQL server: apollo, mercurius, yoga
schema_approachstring"schema-first"Schema: schema-first, code-first
paginationstring"cursor"Pagination: cursor (Relay), offset, none
depth_limitnumber10Maximum query nesting depth
complexity_limitnumber1000Maximum query complexity score
introspectionbooleantrueEnable schema introspection (disable in prod)
playgroundbooleantrueEnable GraphQL playground UI
tracingbooleanfalseEnable Apollo tracing for performance

Best Practices

  1. Use DataLoader for every relationship resolver — any resolver that loads related data should use DataLoader to batch and cache database queries within a single request; this eliminates N+1 queries.

  2. Implement query depth and complexity limits — without limits, a malicious client can craft deeply nested queries that overload your server; set depth_limit: 10 and complexity_limit: 1000.

  3. Use cursor-based pagination for production APIs — offset pagination breaks when data changes between pages; cursor pagination is stable and performs better on large datasets.

  4. Disable introspection in production — schema introspection exposes your entire API surface; disable it in production and use a schema registry or documentation site instead.

  5. Return structured errors with error codes — use GraphQL's error extensions to include machine-readable error codes alongside human-readable messages so clients can handle errors programmatically.

Common Issues

N+1 query problem causes slow responses — Each relationship resolver fires a separate database query. Implement DataLoader for batching and caching. Profile with Apollo tracing to identify which resolvers are the bottleneck.

Clients request too much data in one query — Without limits, clients can request the entire graph in one call. Implement query complexity analysis that assigns cost to each field and rejects queries exceeding the budget.

Schema evolution breaks existing clients — Removing or renaming fields breaks clients. Use @deprecated(reason: "Use newField") to mark fields for removal, add new fields alongside old ones, and remove deprecated fields only after all clients have migrated.

Community

Reviews

Write a review

No reviews yet. Be the first to review this template!

Similar Templates