跳到正文
cccskills
免费在 GitHub 公开

graphql-patterns

Schema design, resolver patterns, DataLoader, N+1 prevention, and subscription patterns for GraphQL APIs.

中文简介正在准备中。当前显示原文说明。

查看安装方法

包含的文件(1)

  • SKILL.md5.4 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

GraphQL Patterns

Production-grade GraphQL API design with performance and type safety.

Schema Design Principles

# Use interfaces for shared fields
interface Node {
  id: ID!
  createdAt: DateTime!
  updatedAt: DateTime!
}

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

# Relay-style pagination (cursor-based)
type PostConnection {
  edges: [PostEdge!]!
  pageInfo: PageInfo!
  totalCount: Int!
}

type PostEdge {
  node: Post!
  cursor: String!
}

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

# Input types for mutations
input CreatePostInput {
  title: String!
  body: String!
  tags: [String!]
}

# Union for mutation results (error handling without exceptions)
type CreatePostSuccess {
  post: Post!
}

type ValidationError {
  field: String!
  message: String!
}

union CreatePostResult = CreatePostSuccess | ValidationError

DataLoader - N+1 Prevention

import DataLoader from 'dataloader'

// Batch function: receives array of keys, returns array of results in same order
function createUserLoader(db: Database) {
  return new DataLoader<string, User | null>(async (userIds) => {
    const users = await db.user.findMany({
      where: { id: { in: [...userIds] } }
    })
    const userMap = new Map(users.map(u => [u.id, u]))
    // MUST return in same order as input keys
    return userIds.map(id => userMap.get(id) ?? null)
  })
}

// Create per-request context (loaders are NOT shared across requests)
function createContext(req: Request) {
  const db = getDatabase()
  return {
    db,
    loaders: {
      user: createUserLoader(db),
      post: createPostLoader(db),
      comment: createCommentLoader(db),
    }
  }
}

// Resolver uses loader instead of direct DB query
const resolvers = {
  Post: {
    author: (post: Post, _args: unknown, ctx: Context) => {
      return ctx.loaders.user.load(post.authorId)  // batched automatically
    }
  }
}

Resolver Pattern with Validation

import { z } from 'zod'

const CreatePostSchema = z.object({
  title: z.string().min(1).max(200),
  body: z.string().min(10).max(50000),
  tags: z.array(z.string()).max(10).optional()
})

const resolvers = {
  Mutation: {
    createPost: async (_parent: unknown, args: { input: unknown }, ctx: Context) => {
      // Auth guard
      if (!ctx.currentUser) {
        throw new AuthenticationError('Login required')
      }

      // Input validation
      const parsed = CreatePostSchema.safeParse(args.input)
      if (!parsed.success) {
        return {
          __typename: 'ValidationError',
          field: parsed.error.issues[0].path.join('.'),
          message: parsed.error.issues[0].message
        }
      }

      const post = await ctx.db.post.create({
        data: { ...parsed.data, authorId: ctx.currentUser.id }
      })

      return { __typename: 'CreatePostSuccess', post }
    }
  }
}

Subscription Patterns

import { PubSub, withFilter } from 'graphql-subscriptions'

const pubsub = new PubSub()  // Use RedisPubSub in production

const EVENTS = {
  POST_CREATED: 'POST_CREATED',
  COMMENT_ADDED: 'COMMENT_ADDED',
} as const

const resolvers = {
  Subscription: {
    commentAdded: {
      // Filter: only deliver to subscribers watching this post
      subscribe: withFilter(
        () => pubsub.asyncIterableIterator(EVENTS.COMMENT_ADDED),
        (payload, variables) => payload.commentAdded.postId === variables.postId
      )
    }
  },
  Mutation: {
    addComment: async (_p: unknown, args: { postId: string; body: string }, ctx: Context) => {
      const comment = await ctx.db.comment.create({
        data: { postId: args.postId, body: args.body, authorId: ctx.currentUser!.id }
      })
      await pubsub.publish(EVENTS.COMMENT_ADDED, { commentAdded: comment })
      return comment
    }
  }
}

Query Depth & Complexity Limiting

import depthLimit from 'graphql-depth-limit'
import { createComplexityLimitRule } from 'graphql-validation-complexity'

const server = new ApolloServer({
  schema,
  validationRules: [
    depthLimit(7),                          // Max 7 levels deep
    createComplexityLimitRule(1000, {        // Max 1000 complexity points
      scalarCost: 1,
      objectCost: 2,
      listFactor: 10,
    })
  ]
})

Checklist

  • Cursor-based pagination (not offset-based) for all list fields
  • DataLoader for every relationship resolver (one loader per entity per request)
  • Input validation with zod/joi before DB operations
  • Query depth limit (7-10) and complexity limit
  • Auth checks in resolvers, not middleware (field-level control)
  • Union types for mutation results instead of throwing errors
  • Persisted queries in production (disable arbitrary queries)
  • Schema versioned via interfaces, not breaking changes

Anti-Patterns

  • Exposing database IDs directly (use opaque/global IDs)
  • Resolver doing N+1 queries without DataLoader
  • Sharing DataLoader instances across requests (stale data, auth leak)
  • Offset pagination on large datasets (performance cliff)
  • God queries: single resolver fetching entire object graph
  • Putting business logic in resolvers (keep resolvers thin, use service layer)

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

WCAG 2.2 AA compliance, ARIA patterns, keyboard navigation, screen reader optimization

中文简介正在准备中。当前显示原文说明。

vibeeval/vibecosystem5382026年8月9日 更新

axe-core integration, WCAG 2.2 AA checklist, keyboard navigation testing, screen reader testing, and ARIA pattern validation.

中文简介正在准备中。当前显示原文说明。

vibeeval/vibecosystem5382026年8月9日 更新

Steam-style achievement system with XP, levels, streaks, and skill trees. Gamifies the development workflow. 25 achievements across 5 categories.

中文简介正在准备中。当前显示原文说明。

vibeeval/vibecosystem5382026年8月9日 更新

Framework for measuring and tracking agent response quality over time. Detects regressions before they reach production. Use when evaluating agent changes, auditing quality, or establishing performance baselines.

中文简介正在准备中。当前显示原文说明。

vibeeval/vibecosystem5382026年8月9日 更新

Agent Context Isolation

中文简介正在准备中。当前显示原文说明。

vibeeval/vibecosystem5382026年8月9日 更新

Agent ve skill dosyalarinin yapisal dogrulamasi. Frontmatter kontrol, naming convention, zorunlu bolum kontrolu, tutarlilik denetimi. Yeni agent/skill eklendiginde veya mevcut dosyalar duzenlediginde otomatik calistirilir.

中文简介正在准备中。当前显示原文说明。

vibeeval/vibecosystem5382026年8月9日 更新

查看 vibeeval 的全部技能

报告此技能的问题