agentsclimarketplace

Graphql

Skill iceflower/agent-skills/graphql

Agent Skills 오픈 표준 기반 AI 코딩 에이전트용 스킬 컬렉션 (Java, Kotlin, Spring, NestJS, K8s, Terraform, GraphQL, gRPC, OpenTelemetry, a11y, i18n 등 60개)

Install
npx -y skills add iceflower/agent-skills --skill graphql

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

GraphQL API design and implementation patterns including schema design principles, type system (Object, Input, Interface, Union, Enum), resolver patterns, N+1 problem prevention with DataLoader, pagination (Cursor-based, Relay Connection), error handling, query complexity and depth limiting, authentication/authorization at field level, and Federation (Apollo). Covers Spring for GraphQL, Netflix DGS Framework, and GraphQL security (OWASP GraphQL Cheat Sheet). Use when designing GraphQL schemas, implementing resolvers, optimizing query performance, setting up GraphQL Federation, or reviewing GraphQL API security.

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

13.0 KB, ~2.8k tokens by cl100k_base, as published. Nobody here has run it

GraphQL API Design and Implementation Rules

1. Schema Design Principles

SDL-first vs Code-first

  • SDL-first (recommended for most projects): Define the schema in .graphqls files, then implement resolvers to match
    • Encourages contract-first design — schema is the API contract
    • Better for team collaboration — frontend and backend agree on schema first
    • Tools: Spring for GraphQL, Apollo Server
  • Code-first: Generate the schema from code annotations or DSL
    • Useful when schema closely mirrors domain model
    • Risk of coupling schema to implementation details
    • Tools: Netflix DGS (annotation-based), GraphQL Kotlin, TypeGraphQL

Schema Organization

src/main/resources/graphql/
  schema.graphqls          # Root schema (Query, Mutation, Subscription)
  types/
    user.graphqls          # User-related types
    order.graphqls         # Order-related types
  inputs/
    user-input.graphqls    # User input types
  enums/
    status.graphqls        # Enum definitions
  interfaces/
    node.graphqls          # Shared interfaces

Naming Conventions

  • Types: PascalCase (User, OrderItem)
  • Fields: camelCase (firstName, createdAt)
  • Enums: PascalCase type, SCREAMING_SNAKE_CASE values (OrderStatus.IN_PROGRESS)
  • Mutations: verb + noun (createUser, updateOrder, deleteComment)
  • Queries: noun for single (user), plural for list (users)
  • Input types: suffix with Input (CreateUserInput, UpdateOrderInput)
  • Payload types: suffix with Payload (CreateUserPayload)

2. Type System

Object Types

type User {
  id: ID!
  email: String!
  name: String!
  avatar: String
  orders(first: Int, after: String): OrderConnection!
  createdAt: DateTime!
}
  • Use ID! for identifiers — never Int! or String!
  • Mark required fields with ! (non-null)
  • Use nullable fields (String) for optional data
  • Add arguments to fields for filtering/pagination

Input Types

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

input UpdateUserInput {
  email: String
  name: String
  avatar: String
}
  • Separate input types for create and update operations
  • Create inputs: required fields are non-null
  • Update inputs: all fields nullable (partial update)
  • Never reuse output types as input types

Interface Types

interface Node {
  id: ID!
}

interface Timestamped {
  createdAt: DateTime!
  updatedAt: DateTime!
}

type User implements Node & Timestamped {
  id: ID!
  email: String!
  createdAt: DateTime!
  updatedAt: DateTime!
}
  • Use interfaces for shared field contracts
  • Node interface is standard for Relay-compatible APIs

Union Types

union SearchResult = User | Order | Product

type Query {
  search(term: String!): [SearchResult!]!
}
  • Use unions when return types share no common fields
  • Prefer interfaces when types share fields
  • Always handle all union members in the client

Enum Types

enum OrderStatus {
  PENDING
  CONFIRMED
  SHIPPED
  DELIVERED
  CANCELLED
}
  • Use enums for fixed sets of values
  • Use SCREAMING_SNAKE_CASE for values
  • Add descriptions for non-obvious values

Custom Scalar Types

scalar DateTime
scalar URL
scalar JSON
scalar BigDecimal
  • Define custom scalars for domain-specific types
  • Always provide serialization/deserialization logic
  • Prefer specific scalars over String for validation

3. Resolver Patterns and DataLoader

Resolver Structure

Query.user(id) → UserResolver
  User.orders → OrderResolver (field resolver)
    Order.items → OrderItemResolver (field resolver)
  • Keep resolvers thin — delegate business logic to service layer
  • One resolver class per type or domain area
  • Field resolvers load data lazily — only when requested

See references/advanced-patterns.md for N+1 problem explanation, DataLoader implementation example, and mutation error patterns.

DataLoader Rules

  • Always use DataLoader for field resolvers that load related entities
  • DataLoader batches requests within a single request context
  • DataLoader also provides per-request caching
  • Monitor batch sizes — unexpectedly large batches may indicate issues

Resolver Best Practices

  • Never call repositories directly from resolvers — use a service layer
  • Handle null values explicitly in resolvers
  • Use @Secured or custom directives for field-level authorization
  • Log resolver errors with correlation IDs for debugging

4. Pagination

Cursor-based Pagination (Relay Connection Spec)

type Query {
  users(first: Int, after: String, last: Int, before: String): UserConnection!
}

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

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

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

Pagination Guidelines

  • Prefer cursor-based over offset-based pagination
    • Cursor-based: stable under concurrent inserts/deletes
    • Offset-based: simple but breaks with data changes
  • Cursors should be opaque strings (base64-encoded IDs)
  • Always include totalCount when feasible
  • Set reasonable defaults and maximums for first/last (e.g., default 20, max 100)
  • For simple use cases, offset-based pagination is acceptable:
type Query {
  users(page: Int = 1, size: Int = 20): UserPage!
}

type UserPage {
  content: [User!]!
  totalElements: Int!
  totalPages: Int!
  hasNext: Boolean!
}

5. Error Handling

GraphQL Error Response Structure

{
  "data": null,
  "errors": [
    {
      "message": "User not found",
      "locations": [{ "line": 2, "column": 3 }],
      "path": ["user"],
      "extensions": {
        "code": "NOT_FOUND",
        "classification": "DataFetchingException"
      }
    }
  ]
}

Error Handling Patterns

  • Use extensions.code for machine-readable error codes

  • Define a consistent set of error codes across the API:

    • NOT_FOUND, VALIDATION_ERROR, UNAUTHORIZED, FORBIDDEN, INTERNAL_ERROR, CONFLICT, RATE_LIMITED
  • Return partial data when possible — GraphQL supports partial responses

  • Never expose internal details (stack traces, SQL) in error messages

  • Use union return types for mutations to provide typed error responses (see references/advanced-patterns.md for union-based mutation error pattern examples)


6. Query Complexity and Depth Limiting

Depth Limiting

  • Set a maximum query depth (recommended: 7-10 for general APIs)
  • Reject queries exceeding the depth limit before execution
# This nested query could be malicious if unbounded:
{
  user {
    friends {
      friends {
        friends {
          friends { ... }  # Excessive depth
        }
      }
    }
  }
}

Complexity Analysis

  • Assign complexity scores to fields based on cost:
    • Scalar fields: 0-1
    • Object fields: 1
    • List fields: multiply by expected/requested count
    • Database-heavy fields: higher weight
  • Set a maximum total complexity per query (e.g., 1000)
  • Return the complexity cost in response extensions for transparency

For DGS framework configuration example, see references/advanced-patterns.md.


7. Authentication and Authorization

Authentication

  • Authenticate at the transport layer (HTTP headers, cookies)
  • Pass the authenticated user context to resolvers via GraphQL context
  • Do NOT put authentication logic inside individual resolvers

Field-Level Authorization

type User {
  id: ID!
  name: String!                  # Public
  email: String! @auth(role: SELF)     # Only the user themselves
  salary: BigDecimal @auth(role: ADMIN) # Admin only
}
  • Use custom directives or schema annotations for declarative authorization
  • Implement authorization in a middleware/interceptor layer, not in business logic
  • Return null for unauthorized nullable fields; throw for non-null fields
  • Log authorization failures for security monitoring

Authorization Patterns

  • Directive-based: @auth(role: ADMIN) on schema fields
  • Resolver-based: Check permissions in the resolver or service layer
  • DataLoader-based: Filter results in DataLoader based on context

8. Subscriptions (Real-time)

Subscription Design

type Subscription {
  orderStatusChanged(orderId: ID!): OrderStatusEvent!
  newMessage(channelId: ID!): Message!
}

type OrderStatusEvent {
  order: Order!
  previousStatus: OrderStatus!
  newStatus: OrderStatus!
  changedAt: DateTime!
}

Implementation Guidelines

  • Use WebSocket (graphql-ws protocol) for subscriptions
  • Keep subscription payloads small — include only changed data
  • Always require authentication for subscriptions
  • Set connection timeouts and maximum subscription limits per client
  • Use server-sent events (SSE) as an alternative for simpler use cases
  • Consider using a message broker (Redis Pub/Sub, Kafka) for scalability

9. Federation (Apollo Federation)

When to Use Federation

  • Multiple teams own different parts of the graph
  • Microservice architecture where each service owns its domain types
  • Need to compose a unified schema from independent subgraphs

For subgraph schema examples, see references/advanced-patterns.md.

Federation Guidelines

  • Each entity has exactly one owning subgraph
  • Use @key directive to define entity identity
  • Use @external, @requires, @provides for cross-subgraph fields
  • Keep the gateway/router stateless — all logic in subgraphs
  • Monitor subgraph latency — gateway adds overhead
  • Version subgraphs independently; use schema registry for compatibility

10. Security

For the full security reference, see the OWASP GraphQL Cheat Sheet.

Introspection

  • Disable introspection in production — it exposes the full schema
  • Enable only in development/staging environments

Query Restrictions

  • Set maximum query depth (see Section 6)
  • Set maximum query complexity (see Section 6)
  • Limit batch queries (array of operations in single request)
  • Set request size limits at the HTTP layer
  • Implement rate limiting per client/IP

Input Validation

  • Validate all input arguments at the schema level (non-null, enums)
  • Add custom validation in resolvers for business rules
  • Sanitize string inputs to prevent injection attacks
  • Use custom scalars with built-in validation (e.g., Email, URL)

Persisted Queries

  • Use automatic persisted queries (APQ) or pre-registered queries in production
  • APQ: client sends a hash; server looks up the query
  • Prevents arbitrary query execution in sensitive environments
  • Reduces bandwidth by not sending full query strings

Additional Security Measures

  • Enable CORS with strict origin policies
  • Use HTTPS for all GraphQL endpoints
  • Log and monitor query patterns for anomaly detection
  • Set timeouts for resolver execution to prevent resource exhaustion

11. GraphQL vs REST Selection Criteria

Prefer GraphQL When

  • Clients need flexible data fetching (mobile vs web different needs)
  • Multiple related entities are fetched in a single request
  • API serves diverse clients with varying data requirements
  • Real-time features (subscriptions) are needed
  • Rapid frontend iteration without backend changes

Prefer REST When

  • Simple CRUD operations on well-defined resources
  • File upload/download is a primary use case
  • Caching at the HTTP layer (CDN, browser) is critical
  • Team has limited GraphQL experience
  • API is primarily server-to-server communication
  • OpenAPI/Swagger tooling ecosystem is a requirement

Hybrid Approach

  • Use GraphQL for client-facing APIs with complex data requirements
  • Use REST for internal service-to-service communication
  • Use REST for file handling, health checks, and webhook endpoints
  • A single application can expose both GraphQL and REST endpoints

12. Framework Reference

For detailed framework-specific implementation patterns with Spring for GraphQL and Netflix DGS, see references/spring-graphql-dgs.md.

For advanced schema design patterns, naming conventions, and mutation design guidelines, see references/schema-design-patterns.md.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.