スキル一覧に戻る
jovermier

graphql-resolvers

by jovermier

Claude Code agents for Go, GraphQL, Next.js, and Playwright. 4 agents, 12 skills for code review and test generation.

0🍴 0📅 2026年1月3日
GitHubで見るManusで実行

SKILL.md


name: graphql-resolvers description: GraphQL resolver patterns including dataloader for N+1 prevention, context propagation, authorization, error handling, and validation. Use when implementing GraphQL resolvers.

GraphQL Resolvers

Expert guidance for implementing efficient, secure GraphQL resolvers.

Quick Reference

ConcernSolutionPattern
N+1 queriesDataloaderBatch load relations
AuthenticationContext middlewareCheck before resolving
AuthorizationField-level checksUser can access this data
ValidationSchema layerInput validation before resolvers
Error handlingWrapped errorsDon't expose internal details
Context propagationPass through all levelscontext.Context to nested resolvers

What Do You Need?

  1. Dataloader - Batching relations to prevent N+1 queries
  2. Authorization - Checking access at field level
  3. Error handling - Proper GraphQL errors, no internal exposure
  4. Context - Propagating user, request-scoped data
  5. Validation - Schema-level validation approach

Specify a number or describe your resolver scenario.

Routing

ResponseReference to Read
1, "dataloader", "n+1", "batch", "relation"dataloader.md
2, "auth", "authorization", "access", "permission"authorization.md
3, "error", "wrapped", "internal"errors.md
4, "context", "user", "request"context.md
5, "validation", "input", "schema"validation.md

Critical Rules

  • Always use dataloader for relations: Prevents N+1 queries
  • Authorize at resolver level: Check user can access the data
  • Never expose internal errors: Wrap before returning
  • Propagate context through resolver chain: All nested resolvers need it
  • Validate at schema layer: Use input validation, not in resolvers
  • No circular dependencies: Be aware of resolver chains

Dataloader Pattern

// Bad: N+1 query pattern
func (r *queryResolver) Users(ctx context.Context) ([]*User, error) {
    users, _ := r.db.Users()  // 1 query
    for _, user := range users {
        posts, _ := r.db.PostsByUser(user.ID)  // N queries!
        user.Posts = posts
    }
    return users, nil
}

// Good: Using dataloader
func (r *queryResolver) Users(ctx context.Context) ([]*User, error) {
    users, err := r.db.Users()
    if err != nil {
        return nil, err
    }

    // Batch load posts using dataloader
    loaders := dataloader.For(ctx)
    for _, user := range users {
        user.Posts, err = loaders.PostsByUser.Load(user.ID)
        if err != nil {
            return nil, err
        }
    }

    return users, nil
}

Authorization Pattern

// Good: Authorization check in resolver
func (r *queryResolver) User(ctx context.Context, id string) (*User, error) {
    // Check authentication
    viewer := auth.FromContext(ctx)
    if viewer == nil {
        return nil, fmt.Errorf("authentication required")
    }

    // Fetch user
    user, err := r.db.FindUser(id)
    if err != nil {
        return nil, err
    }

    // Check authorization (users can view own profile, admins can view any)
    if user.ID != viewer.ID && !viewer.IsAdmin {
        return nil, fmt.Errorf("access denied")
    }

    return user, nil
}

Error Handling Pattern

// Bad: Exposing internal errors
func (r *mutationResolver) CreateUser(ctx context.Context, input CreateUserInput) (*CreateUserPayload, error) {
    if err := r.db.CreateUser(input); err != nil {
        return nil, fmt.Errorf("database error: %v", err)  // Leaks DB details!
    }
    // ...
}

// Good: Wrapped errors
func (r *mutationResolver) CreateUser(ctx context.Context, input CreateUserInput) (*CreateUserPayload, error) {
    if err := r.db.CreateUser(input); err != nil {
        if errors.Is(err, db.ErrDuplicate) {
            return &CreateUserPayload{
                Errors: []UserError{{
                    Field:   []string{"email"},
                    Message: "Email already exists",
                }},
            }, nil
        }
        return nil, fmt.Errorf("failed to create user")
    }
    // ...
}

Common Resolver Issues

IssueSeverityImpactFix
N+1 queriesCriticalDatabase overload, slowUse dataloader
Missing authorizationCriticalData exposureAdd auth checks
Exposing internal errorsHighInformation disclosureWrap errors
Not propagating contextHighBreaks auth, timeoutPass ctx through
No validationMediumBad data in DBValidate at schema
Circular resolver dependenciesHighInfinite loopsRestructure schema

Reference Index

FileTopics
dataloader.mdBatching, caching, implementation
authorization.mdAuth checks, role-based access
errors.mdError wrapping, field errors
context.mdPropagation, request-scoped data
validation.mdSchema validation, input types

Success Criteria

Resolvers are correct when:

  • Dataloader used for all relations (no N+1 queries)
  • Authorization checked before data access
  • Internal errors wrapped, not exposed
  • Context propagated through resolver chain
  • Validation happens at schema layer
  • No circular dependencies in resolver chains
  • Field-level authorization for sensitive data

スコア

総合スコア

65/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

+10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

0/5
タグ

1つ以上のタグが設定されている

0/5

レビュー

💬

レビュー機能は近日公開予定です