- Home
- Skills
- APIs & Backend
- GraphQL API Contract and Schema Design
GraphQL API Contract and Schema Design
Designs GraphQL schemas: type definitions, query depth/complexity bounds, DataLoader N+1 mitigation, and Relay pagination.
$5
Works with the AI tools you already use
GraphQL API Contract and Schema Design
Example session with this skill installed
Design the GraphQL schema and query protection contract for our Creator Marketplace Storefront API.
- Subject: marketplace-graphql-api v2.0 (run-id: marketplace-gql-001) federating Creator Profiles, Digital Assets, and Customer Reviews.
- Deciders: Lead API Standards Architect (Sarah Chen) and Platform Performance Lead (Marcus Vance).
- Traffic & Scale: Peak 1,600 GraphQL queries/sec; p95 latency budget <= 150 ms; PostgreSQL database backing 250,000 digital products.
- Tension: Frontend web team requested unrestricted nested queries (author -> products -> reviews -> author...) without depth or complexity bounds to simplify mobile component trees; Marcus Vance warns that recursive cyclic queries cause catastrophic database Denial of Service (incident INC-3904 where a 9-level nested query locked RDS CPU at 100% for 22 minutes), mandating a strict query depth ceiling (max depth 6), query complexity cost analysis (max cost 250 points per query), mandatory DataLoader batching to eliminate N+1 queries, and Relay-style cursor connections (first, after, pageInfo) for all paginated lists.
Write the GraphQL schema contract under docs/.
- Read your context and instructions
- Compiled the graphql api contract
- Generated the UI component
Wrote docs/architecture/tasks/marketplace-gql-001/graphql-api-design/graphql-schema-contract.md. Complete GraphQL schema contract specifying GraphQL SDL, query depth ceiling (max 6), complexity score bounding (max 250), DataLoader N+1 batching, and Relay connection pagination.
---
skill: graphql-api-design
---
# GraphQL Schema Contract: Creator Marketplace Storefront [GQL-MKT-001]
## Summary
This specification establishes the enterprise GraphQL schema, resolver execution architecture, and query safety contract for `marketplace-graphql-api v2.0` under run ID `marketplace-gql-001`. It federates Creator Profiles, Digital Assets, and Customer Reviews across 250,000 products, sustaining 1,600 peak queries/second within a 150 ms p95 latency SLA. It decisively resolves the catastrophic database exhaustion exposed in incident INC-3904 (where a 9-level circular query triggered 100% database CPU lockup for 22 minutes) by rejecting unbounded nested queries. The contract mandates a strict query depth ceiling of 6, an algorithmic complexity cost ceiling of 250 points per query, batch-loading via DataLoader to eliminate N+1 queries, and the Relay Cursor Connections specification for collection pagination.
## Detailed Description
GraphQL's flexible client-driven querying invites severe server-side Denial of Service vulnerabilities when query depth and cardinality remain unconstrained. Without server-side depth and complexity validation, malicious or poorly drafted client queries execute exponential database queries through cyclic object graphs (e.g. `Creator -> Products -> Reviews -> Creator -> Products...`).
Incoming Client Query: query { creator(id: "c_12") { products(first: 20) { reviews { author { ... } } } } }
│
▼
[ GraphQL Ingress Engine / Apollo Server ]
├── 1. Syntax & Type Validation (GraphQL SDL)
├── 2. Query Depth Analysis (Ceiling: Max 6 Levels) ────► Exceeded: HTTP 400 (ERR_QUERY_TOO_DEEP)
├── 3. Complexity Cost Calculator (Ceiling: 250 Points) ─► Exceeded: HTTP 400 (ERR_COMPLEXITY_EXCEEDED)
│
▼
[ Resolver Execution Seam with DataLoader ]
├── CreatorResolver: Batches Creator IDs via CreatorLoader
├── ProductResolver: Batches Product IDs via ProductLoader
└── ReviewResolver: Single SQL IN (...) Query (Zero N+1)
│
▼
[ Relayed Response Payload (Latency p95 <= 110 ms) ]
### Criteria and weights
| Criterion | Why it matters here | Weight | Source of the weight |
|---|---|---|---|
| Query DoS Defense & Depth Bounding | Unbounded recursive queries lock database CPUs and cause platform-wide outages (INC-3904). | 0.40 | Marcus Vance (Performance Lead) |
| N+1 Resolver Batching & Index Efficiency | Fetching related reviews and authors must never execute O(N) individual SELECT queries. | 0.30 | Database Reliability Standard |
| Client Pagination Predictability | Collection pagination must adhere to stable Relay cursor standards, avoiding deep-offset scans. | 0.15 | Sarah Chen (API Standards) |
| Standardized Partial Error Taxonomy | Graph execution failures must differentiate field-level validation from unauthenticated tokens. | 0.15 | Client Engineering Guild |
### Comparison
| Query Protection Candidate | Depth Control Model | Complexity Analysis | Database Load Profile | Evaluation |
|---|---|---|---|---|
| Option A: Unconstrained Native GraphQL | None (Client requests arbitrary depth) | None | Exponential O(N^K) database queries | Rejected: Recreates INC-3904 database CPU collapse. |
| Option B: Execution Timeout Only (5s) | Thread timeout kill switch | None | High initial CPU spike before socket kill | Rejected: Sits on DB connections for 5s before failing; burns capacity. |
| Option C: Static Depth + Complexity Cost (Chosen) | AST inspection (Max Depth: 6) | Field score sum (Max Cost: 250) | Constant O(1) batched queries via DataLoader | Selected: Rejects abusive queries before resolver execution in < 3 ms. |
### Result
Option C is selected. Pre-execution AST validation rejects deeply nested or computationally expensive queries before database execution.
---
### Required Mechanisms
#### 1. GraphQL SDL Schema Definition [MC-SDL-01]
```graphql
```bash
type Query {
creator(id: ID!): Creator
product(id: ID!): Product
marketplaceFeed(first: Int = 20, after: String): ProductConnection!
}
type Creator {
id: ID!
handle: String!
displayName: String!
products(first: Int = 10, after: String): ProductConnection!
}
type Product {
id: ID!
slug: String!
title: String!
priceCents: Int!
creator: Creator!
reviews(first: Int = 10, after: String): ReviewConnection!
}
type Review {
id: ID!
rating: Int!
comment: String
author: User!
createdAt: String!
}
type User {
id: ID!
username: String!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
type ProductConnection {
edges: [ProductEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type ProductEdge {
cursor: String!
node: Product!
}
type ReviewConnection {
edges: [ReviewEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
type ReviewEdge {
cursor: String!
node: Review!
}
#### 2. Query Complexity & Depth Limiting Defenses [MC-CD-01]
- **Depth Limiting Rule**: Query AST depth must not exceed 6 levels.
- Calculation: Root `Query` = Level 0; `creator` = Level 1; `products` = Level 2; `edges` = Level 3; `node` = Level 4; `reviews` = Level 5; `author` = Level 6.
- Queries requesting Level 7 are rejected before execution with error code `ERR_QUERY_DEPTH_EXCEEDED`.
- **Complexity Cost Rules**:
- Scalar fields (`id`, `title`, `priceCents`): **1 point**.
- Object fields (`creator`, `product`): **2 points**.
- Connections (`products(first: N)`): Multiplier formula:
$$\text{Cost} = 2 + (N \times \text{ChildFieldCosts})$$
- Max Permitted Query Cost: **250 points**. Queries exceeding 250 points terminate immediately with `ERR_COMPLEXITY_EXCEEDED`.
#### 3. DataLoader & N+1 Prevention Strategy [MC-DL-01]
Resolvers are forbidden from issuing direct database queries. All relational lookups use batch DataLoaders:
- `ProductByCreatorLoader`: Consolidates creator IDs across the event loop turn and issues single query:
`SELECT * FROM products WHERE creator_id IN ($1, $2, ...) ORDER BY created_at DESC;`
- `ReviewByProductLoader`: Batches product IDs and executes single query returning partitioned results.
#### 4. Error Formatting & Partial Failure Contracts [MC-EF-01]
Errors adhere to GraphQL specification with typed extensions:
```json
{
"errors": [
{
"message": "Query depth of 7 exceeds the maximum allowed depth of 6.",
"locations": [{ "line": 4, "column": 7 }],
"path": ["creator", "products", "edges", "node", "reviews", "edges", "node", "author"],
"extensions": {
"code": "ERR_QUERY_DEPTH_EXCEEDED",
"currentDepth": 7,
"maxDepth": 6
}
}
],
"data": null
}
Invariants and Contracts
Query Depth Ceiling Invariant [INV-GQL-01]
The GraphQL engine must enforce an immutable depth ceiling of 6 levels. Queries exceeding
6 levels must be aborted during AST parsing prior to resolver invocation.
Complexity Cost Ceiling Invariant [INV-GQL-02]
The calculated complexity cost of any query must not exceed 250 points. Requests specifying
unbounded `first` arguments or deep collections must be rejected with HTTP 400.
DataLoader Resolution Mandate [INV-GQL-03]
Resolvers for relational association fields (`products`, `reviews`, `creator`) must resolve
exclusively through registered DataLoaders. Inline SQL calls in resolver functions are prohibited.
Explicit Unknowns
- Memory footprint of DataLoader caches when individual client queries request 100 items across multiple connections (G-1).
- Apollo Federation subgraph schema composition latency during continuous CI/CD deployments (G-2).
Traceability
| Claim | Classification | Source | Freshness |
|---|---|---|---|
| 250,000 digital products catalog | provided | Catalog scale intake | Current |
| Peak 1,600 queries/sec | provided | Traffic profile | Current |
| Latency budget p95 <= 150 ms | provided | SLA constraint | Current |
| Incident INC-3904 9-level cyclic CPU lock | provided | Post-mortem evidence | Historical |
| Max depth 6, max complexity 250 points | decided | Marcus Vance & Sarah Chen | 2026-09-15 |
| Mandatory DataLoader batching | decided | Architectural invariant INV-GQL-03 | 2026-09-15 |
Verification
No validator was supplied, so no command was run.
Reviewer self-check against GraphQL schema contracts:
- Schema Soundness: PASS. Relay connection pagination and strict GraphQL SDL specified.
- DoS Protection: PASS. Hard depth ceiling (6) and complexity budget (250) prevent CPU lockups.
- N+1 Elimination: PASS. DataLoader batching mandates single SQL statements per entity tier.
- Error Transparency: PASS. Standard GraphQL error response includes typed extension codes.
Open Decisions
DEC-GQL-01: Sarah Chen to determine whether persisted queries (Automatic Persisted Queries / APQ) should be mandatory for all public production traffic (Owner: Sarah Chen).
Next steps
- Sarah Chen reviews GraphQL schema SDL with mobile engineering leads.
- Platform team configures
graphql-depth-limitandgraphql-validation-complexityplugins in Apollo Server. - Conduct staging stress test verifying DataLoader batching under 1,600 queries/sec load.
graphql-api-contract-and-schema-design.tsx
TSX · React component
Example file from a real run - the skill writes it into your workspace.
Connects securely to your tools. The creator never sees your data.
What you get
About this skill
What it does
This skill maps authoritative consumer capabilities and domain/API semantics into a GraphQL schema contract: graph identities, type/field/argument/input meanings, root operations, null/list/error behavior, authorization references, collection seams and evolution.
Use it when
Use when accepted consumer operations and domain identities/relationships need a precise GraphQL-facing graph contract.
For example: “One mobile query brought down the API. It asked for customers, their orders, each order's items, and each item's supplier, four levels deep, for 200 customers.”
What you get
- GraphQL Schema Definition
Written as Markdown to <your output folder>/architecture/tasks/<run-id>/graphql-api-design/.
What it will not do
Do not use for domain/data modeling, general API/federation design, resolver/client implementation, query optimization, pagination/filter/auth policy, subscription transport or generation.
How it works
- Check GraphQL earns its cost here.
- Design the graph from the domain, not from the tables.
- Bound query cost before exposure.
- Solve N+1 in the schema design, not only with a loader.
- Enforce authorisation per field and per node, not at the query root.
- Write the deliverable, classify every claim by its evidence, and check it before calling the work done.
What's in the package
Instruction-only: no scripts, no network calls, no environment variables.
- LICENSE.txt
- SKILL.md
- agents/openai.yaml
- assets/output-template-task.md
- references/domain-rules.md
- references/operating-rules.md
- references/output-contract.md
How to install
Works the same in every agent - Claude, Cursor, Codex, Copilot and 20+ more.
- 1
Download the ZIP
Free skills download straight away. Paid skills unlock right after purchase.
- 2
Unzip into your skills folder
Every agent reads skills from one folder on your machine. Drop the unzipped folder in there.
- 3
Ask your agent to use it
Restart the agent if it was already running. It picks the skill up automatically - no config needed.
Skills folder by agent
Click the path to copy it. Create the folder if it does not exist yet.
Reviews
No reviews yet
Be one of the first to try it. Every listed skill passes our trust checks below.
Security scanned
Passed our 8-point scan before listing
Fresh listing
Recently published to Agensi
30-day refund
Not a fit? Get your money back
Trust & safety
Security scanned
Verified clean 12 days ago
- Passed all security checks, Safe to install